Appearance
Meeting the Primitive Values
到目前为止,我们一直在从地球表面观察我们的 JavaScript 宇宙。我们已经熟悉了远距离填充我们宇宙的价值观,但在这个模块中,我们正在改变它。我们将跳上宇宙飞船去探索,向我们介绍 JavaScript 世界中的每一个价值。
花时间详细查看每个值可能感觉没有必要,但是当您清楚地看到它们是两个不同的苹果时,您只能说存在“两个苹果” 。区分值是理解JavaScript 中相等性的关键——这将是我们的下一个主题。
我们的宇宙飞船将引导我们穿越 JavaScript 的“天体”来满足不同的价值观。我们将首先遇到原始值:布尔值、数字、字符串等。稍后,我们将遇到对象和函数。将其视为观光旅游。
Undefind
我们将从未定义类型开始。这是一个非常简单的起点,因为这个类型只有一个值——undefined。
console.log(typeof(undefined)); // "undefined"
它被称为未定义,因此您可能会认为它不存在——但它是一个值,并且是一个非常真实的值!像黑洞一样,undefined
脾气暴躁,经常会带来麻烦。例如,从中读取一个属性会破坏你的程序:
let person = undefined;
console.log(person.mood); // TypeError!
哦,好吧。幸运的是,在整个JavaScript世界中只有一个undefined。你可能会想:它到底为什么会存在?在JavaScript中,它表示无意中丢失的值的概念。 你可以在你自己的代码中使用它,比如写undefined 2或“hello”。然而,undefined也通常“自然发生”。它会在JavaScript不知道你想要的值的情况下出现。例如,如果你忘记给一个变量赋值,它将指向undefined:
let bandersnatch;
console.log(bandersnatch); // undefined
然后你可以将它指向另一个值,或者如果你想的话,再次指向undefined。 别太在意它的名字。人们很容易把undefined看作是某种变量状态,例如“这个变量还没有定义”。但这完全是一种误导!实际上,如果读取的变量实际上没有定义(或在let声明之前),则会得到一个错误
console.log(jabberwocky); // ReferenceError!
let jabberwocky;
实际上,undefined是一个常规的原始值,就像2或"hello"。
Null
我们的下一站是null
。你可以把null看作undefined的姐妹值;这种类型只有一个值 - null。它的行为与undefined很相似。例如,当您试图访问它的属性时,它也会引起混乱
let mimsy = null;
console.log(mimsy.mood); // TypeError!
Fun Fact
null是它自己的类型的唯一值。然而,null也是一个骗子。由于JavaScript中的一个bug,它假装是一个对象:
console.log(typeof(null)); // "object" (a lie!)
您可能认为这意味着null是一个对象。不要落入这个陷阱!它是一个原始值,它的行为方式与对象完全不同。 不幸的是,typeof(null)是一个历史上的意外,我们将不得不永远忍受它。
在实践中,null用于故意丢失值。为什么null和undefined都有?这可以帮助您区分编码错误(可能导致未定义)和有效的缺失数据(可能表示为null)。然而,这只是一种约定,JavaScript并没有强制这种用法。有些人会尽量避免这两种情况!
Booleans
接下来,我们将学习布尔值!像白天和黑夜或开和关一样,只有两个布尔值:true和false。
console.log(typeof(true)); // "boolean"
console.log(typeof(false)); // "boolean"
我们可以用它们进行逻辑运算
let isSad = true;
let isHappy = !isSad; // The opposite
let isFeeling = isSad || isHappy; // Is at least one of them true?
let isConfusing = isSad && isHappy; // Are both true?
Numbers
到目前为止,我们已经介绍了四个值:null、undefined、true和false。 坚持住,当我们在我们的心智模型中增加18,000,000,437,000,000,736,874亿,4544,812,624个值的时候!
console.log(typeof(28)); // "number"
console.log(typeof(3.14)); // "number"
console.log(typeof(-140)); // "number"
一开始,数字可能看起来没什么了不起,但让我们更好地了解它们!
Math for Computers
JavaScript数字与普通数学数字的行为方式不完全相同。下面是一个演示代码片段
console.log(0.1 + 0.2 === 0.3); // false
console.log(0.1 + 0.2 === 0.30000000000000004); // true
- 这可能看起来非常令人惊讶!与普遍的看法相反,这并不意味着JavaScript的数据被打破了。
- 这种行为在不同的编程语言中很常见。它甚至还有个名字:浮点数学。
- 你看,JavaScript并没有实现我们在现实生活中使用的那种数学。浮点数学是“计算机的数学”。
- 不要太担心这个名字,也不要担心它到底是怎么工作的。很少有人知道它所有的微妙之处,这就是问题的关键!
- 它在实践中运行得足够好,以至于大多数时候你都不会去想它。尽管如此,让我们快速地看看是什么使它变得不同的
你曾经用过扫描仪把一张实物照片或一份文件变成数码照片吗?这个类比可以帮助我们理解JavaScript数字。 扫描仪通常最多能分辨1600万种颜色。如果你用红色蜡笔画一幅画并扫描它,扫描出来的图像也应该是红色的——但它将是我们的扫描仪从这1600万种颜色中挑选出的最接近红色的颜色。所以,如果你有两支颜色稍有不同的红色蜡笔,扫描仪可能会误以为它们的颜色是完全一样的! 我们可以说扫描仪使用颜色的精度有限。
我们可以把所有的JavaScript数字想象成一个轴。我们越接近0,数字就越精确,它们之间的“位置”也越接近
console.log(Number.MAX_SAFE_INTEGER); // 9007199254740991
console.log(Number.MAX_SAFE_INTEGER + 1); // 9007199254740992
console.log(Number.MAX_SAFE_INTEGER + 2); // 9007199254740992 (again!)
console.log(Number.MAX_SAFE_INTEGER + 3); // 9007199254740994
console.log(Number.MAX_SAFE_INTEGER + 4); // 9007199254740996
console.log(Number.MAX_SAFE_INTEGER + 5); // 9007199254740996 (again!)
幸运的是,任何在 Number.MIN_SAFE_INTEGER
和 Number.MAX_SAFE_INTEGER
之间的整数是正确的. 这就是为什么 10 + 20 === 30
.
但是当我们写0.1或0.2的时候,我们不会得到精确的0.1和0.2。我们在JavaScript中得到了最接近的可用数字。它们几乎一模一样,但可能会有细微的差别。这些微小的差异加起来,这就是为什么0.1 + 0.2和写0.3的数字不完全一样。
为什么需要浮点数字呢?
按照我的理解,JS宇宙中保存不了那么多的number类型的值,因为内存有限
由于计算机内存有限,无论使用二进制分数还是十进制分数,您都无法以无限精度存储数字:在某些时候您必须切断。但是需要多少准确度?它在哪里需要?有多少个整数位和多少个小数位?
- 对于建造高速公路的工程师来说,它是 10 米还是 10.0001 米宽并不重要——他们的测量结果可能一开始就没有那么准确。
- 对于设计微芯片的人来说,0.0001 米(十分之一毫米)是一个巨大的差异——但他们永远不必处理大于 0.1 米的距离。
- 物理学家需要在同一个计算中同时使用光速(约 300000000)和牛顿引力常数(约 0.0000000000667)。
为了满足工程师和芯片设计者的要求,数字格式必须为不同数量级的数字提供准确性。但是,只需要相对精度。为了让物理学家满意,必须能够进行涉及不同数量级的数字的计算。
基本上,具有固定数量的整数和小数位数是没有用的 - 解决方案是使用浮点格式。
Special Numbers
值得注意的是,浮点数学包括一些特殊的数字。你可能会遇到NaN,∞,-∞和-0。
它们的存在是因为有时您可能会执行1 / 0之类的操作,而JavaScript需要以某种方式表示它们的结果。
浮点数学标准指定了它们如何工作,以及使用它们时会发生什么。 以下是在你的代码中可能出现的特殊数字:
let scale = 0;
let a = 1 / scale; // Infinity
let b = 0 / scale; // NaN
let c = -a; // -Infinity
let d = 1 / c; // -0
在这些特殊的数字中,NaN特别有趣。NaN是0 / 0和其他一些无效数学运算的结果,表示“不是一个数字”。
您可能会困惑为什么它声称是一个数字
console.log(typeof(NaN)); // "number"
然而,这里没有诀窍。从JavaScript的角度来看,NaN是一个数值。它不是null, undefined,字符串或其他类型。
但在浮点数学中,这个术语的名称是“非数字”。所以它是一个数值。它碰巧被称为“非数字”,因为它表示一个无效的结果。
使用这些特殊的数字编写代码并不常见。然而,它们可能由于编码错误而出现。所以很高兴知道它们的存在。
BigInts
普通数字不能精确地表示大整数,因此BigInts填补了这一空白(字面上)。在我们的宇宙中有多少个BigInts ?说明书上说它们有任意的精度。这意味着在我们的JavaScript世界中,有无数个bigint—数学中每个整数对应一个bigint。
let alot = 9007199254740991n; // n at the end makes it a BigInt!
console.log(alot + 1n); // 9007199254740992n
console.log(alot + 2n); // 9007199254740993n
console.log(alot + 3n); // 9007199254740994n
console.log(alot + 4n); // 9007199254740995n
console.log(alot + 5n); // 9007199254740996n
BigInts 是最近才添加到 JavaScript 中的,因此您不会看到它们被广泛使用,如果您使用旧版浏览器,它们将无法工作。
Strings(字符串)
我们的下一站是字符串,它表示 JavaScript 中的文本。字符串有三种写法(单引号、双引号和反引号),但它们指的是同一个概念。这三个字符串文字产生相同的字符串值:
console.log(typeof("こんにちは")); // "string"
console.log(typeof('こんにちは')); // "string"
console.log(typeof(`こんにちは`)); // "string"
console.log(typeof('')); // "string"
Strings Aren’t Objects(字符串不是对象)
每个字符串都有一些内置属性
let cat = 'Cheshire';
console.log(cat.length); // 8
console.log(cat[0]); // "C"
console.log(cat[1]); // "h"
这并不意味着字符串就是对象!字符串属性是特殊的,它的行为方式与对象属性不同。例如,您不能将任何内容分配给cat[0]。字符串是基本类型,所有基本类型都是不可变的。
A Value for Every Conceivable String
在我们的宇宙中,每一个可能的字符串都有一个不同的值。
字符串是否已经“存在”或“创建”的问题不是我们可以从代码中测试的。在我们的心智模型中,这个问题没有任何意义。我们无法建立一个实验来判断字符串在我们的 JavaScript 世界中是“被创建”还是“被召唤”。
为了使我们的心智模型简单,我们将说所有可能的字符串值从一开始就已经存在——每个不同的字符串都有一个值。
Symbol(符号)
我们已经探索了相当多的 JavaScript 世界,但在我们游览的第一部分还有一个(快速)停留:符号。
知道符号的存在很重要,但如果不深入研究对象和属性,就很难解释它们的作用和行为。符号的用途与门钥匙相似:它们让您隐藏对象内部的一些信息并控制代码的哪些部分可以访问它。它们也相对稀有,所以在这次宇宙之旅中,我们将跳过它们。对不起,符号!
let alohomora = Symbol();
console.log(typeof(alohomora)); // "symbol"
回顾一下
现在我们已经满足了所有的原始值,我们将从我们的旅行中休息一下。让我们回顾一下到目前为止遇到的原始值!
- Undefined
- Null
- Booleans
- Numbers
- BigInts
- Strings
- Symbols
我们还了解了一些关于JavaScript数字的有趣事实
- 并非所有的数字都能在JavaScript中完美地表示出来。它们的小数部分在接近0时提供了更高的精度,而在远离0时提供了更低的精度。
- 来自无效数学运算的数字,如1 / 0或0 / 0是特殊的。NaN就是这样一个数字。它们可能是由于编码错误而出现的。
- typeof(NaN)是数字,因为NaN是数值。它被称为“非数字”,因为它代表了“无效”数字的概念。