这是用户在 2024-5-28 13:59 为 https://justjavascript.com/learn/05-meeting-the-primitive-values 保存的双语快照页面,由 沉浸式翻译 提供双语支持。了解如何保存?
Skip to content

Meeting the Primitive Values

episode 05

Until now, we have been observing our JavaScript universe from the surface of our planet. We have familiarized ourselves with the values that populate our universe from a distance, but in this module, we’re changing that. We’re going to hop in a spaceship and go exploring, introducing ourselves to every value in our JavaScript universe.
到目前为止,我们一直在从地球表面观察我们的 JavaScript 宇宙。我们已经从远处熟悉了填充我们宇宙的值,但在这个模块中,我们将改变这一点。我们将乘坐宇宙飞船去探索,向 JavaScript 宇宙中的每一个值介绍自己。

Spending the time to look at each value in detail might feel unnecessary, but you can only say there are “two apples” when you clearly see that they’re two distinct apples. Distinguishing values from one another is key to understanding equality in JavaScript—which will be our next topic.
花时间详细查看每个值可能感觉不必要,但只有当你清楚地看到它们是两个不同的苹果时,你才能说有“两只苹果”。区分不同的值是理解 JavaScript 中相等性的关键——这将是我们的下一个话题。

Our spaceship will guide us through the “celestial spheres” of JavaScript to meet different values. We’ll meet the primitive values first: Booleans, Numbers, Strings, and so on. Later, we’ll meet Objects and Functions. Consider it a sightseeing tour.
我们的宇宙飞船将引导我们穿越 JavaScript 的“天体球”去遇见不同的值。我们将首先遇到原始值:布尔值、数字、字符串等。之后,我们将遇到对象和函数。把它当作一次观光旅行。

Undefined 未定义

We’ll start our tour with the Undefined type. This is a very straightforward place to start, because there is only one value of this type—undefined.
我们将从未定义类型开始我们的旅程。这是一个非常简单的起点,因为这种类型只有一个值—— undefined

console.log(typeof(undefined)); // "undefined"

It’s called undefined, so you might think it’s not there—but it is a value, and a very real one! Like a black hole, undefined is grumpy and can often spell trouble. For example, reading a property from it will break your program:
它被称为未定义,所以你可能认为它不存在——但它确实是一个值,而且是一个非常真实的值!就像一个黑洞, undefined 是脾气暴躁的,常常会带来麻烦。例如,从它读取属性会使你的程序崩溃:

let person = undefined;
console.log(person.mood); // TypeError!

Oh, well. Luckily, there is only one undefined in our entire JavaScript universe. You might wonder: why does it exist at all? In JavaScript, it represents the concept of an unintentionally missing value.
哦,好吧。幸运的是,我们整个 JavaScript 宇宙中只有一个 undefined 。你可能会想:它为什么存在?在 JavaScript 中,它代表了一个无意中缺失的值的概念。

You could use it in your own code by writing undefined—like you write 2 or "hello". However, undefined also commonly “occurs naturally.” It shows up in some situations where JavaScript doesn’t know what value you wanted. For example, if you forget to assign a variable, it will point to undefined:
你可以通过编写 undefined 将其用于你自己的代码中——就像你编写 2"hello" 一样。然而, undefined 也常常“自然发生”。它会在某些情况下出现,当 JavaScript 不知道你想要什么值时。例如,如果你忘记分配一个变量,它将指向 undefined

let bandersnatch;
console.log(bandersnatch); // undefined

Then you can point it to another value, or to undefined again if you want.
然后你可以将其指向另一个值,或者如果你愿意,可以再次指向 undefined

Don’t get too hung up on its name. It’s tempting to think of undefined as some kind of variable status, e.g. “this variable is not yet defined.” But that’s a completely misleading way to think about it! In fact, if you read a variable that was actually not defined (or before the let declaration), you will get an error:
不要太纠结于它的名字。将 undefined 视为某种变量状态是很诱人的,例如“这个变量尚未定义”。但这是完全误导的想法!事实上,如果你读取一个实际上未定义的变量(或在 let 声明之前),你会得到一个错误:

console.log(jabberwocky); // ReferenceError!
let jabberwocky;

That has nothing to do with undefined.

Really, undefined is a regular primitive value, like 2 or "hello".
真的, undefined 是一个常规的原始值,就像 2"hello"

Handle it with care. 小心处理。


The next stop on our tour is Null. You can think of null as undefined’s sister; there is only one value of this type—null. It behaves very similarly to undefined. For example, it will also throw a fuss when you try to access its properties:
我们旅行的下一站是空。你可以把 null 看作 undefined 的姐妹;这种类型只有一个值—— null 。它的行为与未定义非常相似。例如,当你试图访问它的属性时,它也会引发错误:

let mimsy = null;
console.log(mimsy.mood); // TypeError!

Fun Fact 有趣的事实

null is the only value of its own type. However, null is also a liar. Due to a bug in JavaScript, it pretends to be an object:
null 是其自身类型的唯一值。然而, null 也是个骗子。由于 JavaScript 中的一个错误,它假装是一个对象:

console.log(typeof(null)); // "object" (a lie!)

You might think this means null is an object. Don’t fall into this trap! It is a primitive value, and it doesn’t behave in any way like an object.
你可能认为这意味着 null 是一个对象。不要掉进这个陷阱!它是一个原始值,并且它的行为完全不像一个对象。

Unfortunately, typeof(null) is a historical accident that we’ll have to live with forever.
不幸的是, typeof(null) 是一个我们将永远不得不忍受的历史事故。

In practice, null is used for intentionally missing values. Why have both null and undefined? This could help you distinguish a coding mistake (which might result in undefined) from valid missing data (which you might express as null). However, this is only a convention, and JavaScript doesn’t enforce this usage. Some people avoid both of them as much as possible!
实际上, null 用于有意缺失的值。为什么要同时有 nullundefined ?这可以帮助你区分编码错误(可能导致 undefined )和有效的缺失数据(你可能会表示为 null )。然而,这只是一个约定,JavaScript 并不强制执行这种用法。有些人尽可能避免使用它们!

I don’t blame them. 我不怪他们。

Booleans 布尔值

Next on our tour, we’ll meet booleans! Like day and night or on and off, there are only two boolean values: true and false.
接下来,我们将遇到布尔值!就像白天和黑夜或开和关一样,只有两个布尔值: truefalse

console.log(typeof(true)); // "boolean"
console.log(typeof(false)); // "boolean"

We can perform logical operations with them:

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?

Before continuing our tour of the JavaScript universe, let’s check our mental model. Use the sketchpad below or a piece of paper and draw the variables (remember to think of them as wires) and the values for the above lines of code.
在继续我们的 JavaScript 宇宙之旅之前,让我们检查一下我们的心理模型。使用下面的草图板或一张纸,画出变量(记住要把它们当作电线)和上述代码行的值。


Drawing canvas 画布
Answer 答案
Don’t reveal until you have finished sketching.
Answer 答案

Check your answer against this picture:

First, verify that isHappy points to false, isFeeling points to true, and isConfusing points to false. (If you got different answers, there is a mistake somewhere along the way—walk through each line step by step.)
首先,验证 isHappy 指向 falseisFeeling 指向 trueisConfusing 指向 false 。(如果你得到不同的答案,说明某个地方出了错——逐行检查每一步。)

Next, verify that there is only one true and one false value on your sketch. This is important! Regardless of how booleans are stored in the memory, in our mental model there are only two of them.
接下来,验证你的草图上只有一个 true 和一个 false 值。这很重要!无论布尔值在内存中如何存储,在我们的心智模型中只有两个。

Numbers 数字

So far, we have introduced ourselves to four values: null, undefined, true, and false.
到目前为止,我们已经介绍了四个值: nullundefinedtruefalse

Hold on tight, as we add eighteen quintillion, four hundred and thirty-seven quadrillion, seven hundred and thirty-six trillion, eight hundred and seventy-four billion, four hundred and fifty-four million, eight hundred and twelve thousand, six hundred and twenty-four more values to our mental model!

I am, of course, talking about numbers:

console.log(typeof(28)); // "number"
console.log(typeof(3.14)); // "number"
console.log(typeof(-140)); // "number"

At first, numbers might seem unremarkable, but let’s get to know them a little better!

Math for Computers 计算机数学

JavaScript numbers don’t behave exactly the same way as regular mathematical numbers do. Here is a snippet that demonstrates it:
JavaScript 数字的行为与常规数学数字的行为并不完全相同。以下是一个演示它的代码片段:

console.log(0.1 + 0.2 === 0.3); // false
console.log(0.1 + 0.2 === 0.30000000000000004); // true

This might look very surprising! Contrary to popular belief, this doesn’t mean that JavaScript numbers are broken. This behavior is common in different programming languages. It even has a name: floating-point math.
这看起来可能非常令人惊讶!与普遍的看法相反,这并不意味着 JavaScript 数字是有问题的。这种行为在不同的编程语言中很常见。它甚至有一个名字:浮点数学。

You see, JavaScript doesn’t implement the kind of math we use in real life. Floating-point math is “math for computers.” Don’t worry too much about this name or how it works exactly. Very few people know about all its subtleties, and that’s the point! It works well enough in practice that most of the time you won’t think about it. Still, let’s take a quick look at what makes it different.
你看,JavaScript 并没有实现我们在现实生活中使用的那种数学。浮点数学是“计算机的数学”。不要太担心这个名字或它的具体工作原理。很少有人了解它的所有细微之处,这就是重点!它在实践中运行得足够好,以至于大多数时候你不会想到它。不过,让我们快速看一下它的不同之处。

Colors and Numbers 颜色和数字

Have you ever used a scanner to turn a physical photo or a document into a digital one? This analogy can help us understand JavaScript numbers.
你有没有用过扫描仪将实物照片或文档变成数字文件?这个类比可以帮助我们理解 JavaScript 数字。

Scanners usually distinguish at most 16 million colors. If you draw a picture with a red crayon and scan it, the scanned image should come out red too—but it will have the closest red color our scanner picked from those 16 million colors. So if you have two red crayons with ever so slightly different colors, the scanner might be fooled into thinking their color is exactly the same!
扫描仪通常最多能区分 1600 万种颜色。如果你用红色蜡笔画一幅画并扫描它,扫描后的图像也应该是红色的——但它将是扫描仪从 1600 万种颜色中选出的最接近的红色。所以,如果你有两支颜色稍有不同的红色蜡笔,扫描仪可能会误以为它们的颜色完全一样!

We can say that a scanner uses colors with limited precision.

Floating-point math is similar. In real math, there is an infinite set of numbers. But in floating-point math, there are only 18 quintillion of them. So when we write numbers in our code or do calculations with them, JavaScript picks the closest numbers that it knows about—just like our scanner does with colors.
浮点数学也是类似的。在真实的数学中,有一组无限的数字。而在浮点数学中,只有 18 quintillion 个数字。因此,当我们在代码中写数字或进行计算时,JavaScript 会选择它所知道的最接近的数字—就像我们的扫描仪对颜色所做的一样。

In other words, JavaScript uses numbers with limited precision.
换句话说,JavaScript 使用的是精度有限的数字。

We can imagine all of the JavaScript numbers on an axis. The closer we are to 0, the more precision numbers have, and the closer they “sit” to each other:
我们可以想象所有的 JavaScript 数字在一条轴线上。我们越接近 0 ,数字的精度就越高,它们彼此之间的距离也越近:

This is because relatively small numbers occur more often in our programs, and we usually want them to be precise.

As we move from 0 in either direction, we start losing precision. At some point, even two closest JavaScript numbers stay further apart than by 1:
当我们从 0 向任意方向移动时,我们开始失去精度。在某些时候,即使是两个最接近的 JavaScript 数字之间的距离也超过了 1

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!)

Luckily, any whole numbers between Number.MIN_SAFE_INTEGER and Number.MAX_SAFE_INTEGER are exact. This is why 10 + 20 === 30.
幸运的是, Number.MIN_SAFE_INTEGERNumber.MAX_SAFE_INTEGER 之间的任何整数都是精确的。这就是为什么 10 + 20 === 30

But when we write 0.1 or 0.2, we don’t get exactly 0.1 and 0.2. We get the closest available numbers in JavaScript. They are almost exactly the same, but there might be a tiny difference. These tiny differences add up, which is why 0.1 + 0.2 doesn’t give us exactly the same number as writing 0.3.
但是当我们写 0.10.2 时,我们并没有得到完全的 0.10.2 。我们得到了 JavaScript 中最接近的数字。它们几乎完全相同,但可能会有微小的差异。这些微小的差异会累积,这就是为什么 0.1 + 0.2 不会给我们与写 0.3 完全相同的数字。

If this is still confusing, don’t worry. You can learn more about floating-point math, but you already know more than I did when I started writing this guide! Unless you work on finance apps, you likely won’t need to worry about this.

Special Numbers 特殊数字

It is worth noting that floating-point math includes a few special numbers. You might occasionally run into NaN, Infinity, -Infinity, and -0. They exist because sometimes you might execute operations like 1 / 0, and JavaScript needs to represent their result somehow. The floating-point math standard specifies how they work, and what happens when you use them.
值得注意的是,浮点数学包括一些特殊数字。你可能偶尔会遇到 NaNInfinity-Infinity-0 。它们的存在是因为有时你可能会执行像 1 / 0 这样的操作,而 JavaScript 需要以某种方式表示它们的结果。浮点数学标准规定了它们的工作原理,以及使用它们时会发生什么。

Here’s how special numbers may come up in your code:

let scale = 0;
let a = 1 / scale; // Infinity
let b = 0 / scale; // NaN
let c = -a; // -Infinity
let d = 1 / c; // -0

Out of these special numbers, NaN is particularly interesting. NaN, which is the result of 0 / 0 and some other invalid math, stands for “not a number.”
在这些特殊数字中, NaN 特别有趣。 NaN ,这是 0 / 0 和一些其他无效数学的结果,代表“不是一个数字”。

You might be confused by why it claims to be a number:

console.log(typeof(NaN)); // "number"

However, there is no trick here. From a JavaScript perspective, NaN is a numeric value. It is not null, undefined, a string, or some other type. But in the floating-point math, the name for that term is “not a number”. So it is a numeric value. It happens to be called “not a number” because it represents an invalid result.
然而,这里没有任何技巧。从 JavaScript 的角度来看, NaN 是一个数值。它不是 null、undefined、字符串或其他类型。但在浮点数学中,该术语的名称是“不是一个数字”。所以它是一个数值。它被称为“不是一个数字”是因为它代表一个无效的结果。

It’s uncommon to write code using these special numbers. However, they might come up due to a coding mistake. So it’s good to know they exist.

BigInts 大整数

If numbers expanded our JavaScript universe, the next stop on our tour, BigInts, will really keep us busy exploring. In fact, we could explore them forever!
如果数字扩展了我们的 JavaScript 宇宙,那么我们旅行的下一站,大整数,真的会让我们忙于探索。事实上,我们可以永远探索它们!

Regular numbers can’t represent large integers with precision, so BigInts fill that gap (literally). How many BigInts are there in our universe? The specification says they have arbitrary precision. This means that in our JavaScript universe, there is an infinite number of BigInts—one for each integer in math.
常规数字无法精确表示大整数,因此 BigInts 填补了这一空白(字面意思)。我们的宇宙中有多少个 BigInts?规范说它们具有任意精度。这意味着在我们的 JavaScript 宇宙中,有无限数量的 BigInts——每个数学中的整数都有一个。

If this sounds strange, consider that you’re already comfortable with the idea of there being infinite integers in math. (If you’re not, give it a few moments!) It’s not much of a leap then from a “math universe” to a “JavaScript universe.”
如果这听起来很奇怪,请考虑一下你已经习惯了数学中有无限整数的想法。(如果你还没有,给它几分钟!)从“数学宇宙”到“JavaScript 宇宙”并不是很大的飞跃。

(And from there, we can go straight to the Pepsi Universe.)

You can see the idea of arbitrary precision illustrated here:

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

No funny business with the rounding! BigInts are great for financial calculations where precision is especially important.
没有四舍五入的搞笑操作!BigInts 非常适合金融计算,因为精度特别重要。

But keep in mind that nothing is free. Operations with truly huge numbers may take time and resources—we can’t fit all the possible BigInts inside the computer memory. If we tried, at some point it would crash or freeze. But conceptually, we could tour our JavaScript universe for eternity and never reach every single BigInt.
但请记住,没有什么是免费的。处理真正巨大的数字可能需要时间和资源——我们无法将所有可能的 BigInts 都放入计算机内存中。如果我们尝试,在某个时候它会崩溃或冻结。但从概念上讲,我们可以在 JavaScript 宇宙中永远漫游,永远无法达到每一个 BigInt。

BigInts were only recently added to JavaScript, so you won’t see them used widely yet and if you use an older browser, they won’t work.
BigInt 只是最近才被添加到 JavaScript 中,所以你还不会广泛看到它们的使用,如果你使用较旧的浏览器,它们将无法工作。

Strings 字符串

Our next tour stop is Strings, which represent text in JavaScript. There are three ways to write strings (single quotes, double quotes, and backticks), but they refer to the same concept. These three string literals result in the same string value:
我们的下一个游览站是字符串,它们在 JavaScript 中表示文本。有三种方法可以编写字符串(单引号、双引号和反引号),但它们指的是相同的概念。这三种字符串字面量产生相同的字符串值:

console.log(typeof("こんにちは")); // "string"
console.log(typeof('こんにちは')); // "string"
console.log(typeof(`こんにちは`)); // "string"

An empty string is a string, too:

console.log(typeof('')); // "string"

Strings Aren’t Objects 字符串不是对象

All strings have a few built-in properties.

let cat = 'Cheshire';
console.log(cat.length); // 8
console.log(cat[0]); // "C"
console.log(cat[1]); // "h"

This doesn’t mean that strings are objects! String properties are special and don’t behave the way object properties do. For example, you can’t assign anything to cat[0]. Strings are primitives, and all primitives are immutable.
这并不意味着字符串是对象!字符串属性是特殊的,不像对象属性那样表现。例如,你不能给 cat[0] 赋值。字符串是原始类型,所有原始类型都是不可变的。

A Value for Every Conceivable String

In our universe, there is a distinct value for every conceivable string. Yes, this includes your grandmother’s maiden name, the fanfic you published ten years ago under an alias, and the script of Matrix 5 which hasn’t been written yet.
在我们的宇宙中,每个可以想象的字符串都有一个独特的值。是的,这包括你祖母的娘家姓氏,你十年前用别名发表的同人小说,以及尚未写成的《黑客帝国 5》的剧本。

Of course, all possible strings can’t literally fit inside a computer memory chip. But the idea of every possible string can fit inside your head. Our JavaScript universe is a model for humans, not for computers!
当然,所有可能的字符串不可能真的适合在计算机内存芯片中。但每个可能的字符串的想法可以适合在你的脑海中。我们的 JavaScript 宇宙是为人类建模的,而不是为计算机!

This might prompt a question. Does this code create a string?

// Try it in your console
let answer = prompt('Enter your name');
console.log(answer); // ?

Or does it merely summon a string that already exists in our universe?

The answer to this question depends on whether we’re studying JavaScript “from the outside” or “from the inside.”
这个问题的答案取决于我们是从“外部”还是“内部”研究 JavaScript。

Outside our mental model, the answer depends on a specific implementation. Whether a string is represented as a single block of memory, multiple blocks, or a special data structure like a rope, is up to the JavaScript engine.
在我们的心理模型之外,答案取决于具体的实现。字符串是表示为单个内存块、多个内存块,还是像绳子一样的特殊数据结构,取决于 JavaScript 引擎。

But as we discussed in Studying from the Inside, we have agreed to talk about the JavaScript universe as if we lived inside of it. We won’t make statements about it that we can’t verify from inside the universe—by running some code.
但正如我们在《从内部研究》中讨论的那样,我们已经同意将 JavaScript 宇宙视为我们生活在其中。我们不会对它做出无法从宇宙内部通过运行一些代码来验证的声明。

The question of whether a string already “exists” or is “created” is not something we can test from the code. Inside our mental model, this question doesn’t mean anything. We can’t set up an experiment to say whether strings “get created” or “get summoned” within our JavaScript universe.
我们无法从代码中测试一个字符串是已经“存在”还是“创建”的。在我们的心理模型中,这个问题没有任何意义。我们无法进行实验来判断字符串在我们的 JavaScript 宇宙中是“被创建”还是“被召唤”。

To keep our mental model simple, we will say that all conceivable string values already exist from the beginning—one value for every distinct string.

Symbols 符号

We’ve already explored quite a bit of our JavaScript universe, but there is just one more (quick) stop on the first part of our tour: Symbols.
我们已经探索了很多 JavaScript 的世界,但在我们旅行的第一部分还有一个(快速的)停留:符号。

let alohomora = Symbol();
console.log(typeof(alohomora)); // "symbol"

It’s important to know that Symbols exist, but it’s hard to explain their role and behavior without diving deeper into objects and properties. Symbols serve a similar purpose to door keys: they let you hide away some information inside an object and control which parts of the code can access it. They are also relatively rare, so in this tour of our universe, we’re going to skip them. Sorry, symbols!

To Be Continued 待续

Now that we’ve met all of the primitive values, we’ll take a small break from our tour. Let’s recap the primitive values we’ve encountered so far!

  • Undefined 未定义
  • Null 
  • Booleans 布尔值
  • Numbers 数字
  • BigInts 大整数
  • Strings 字符串
  • Symbols 符号

We’ve also learned a few interesting facts about JavaScript numbers:
我们还了解了一些关于 JavaScript 数字的有趣事实:

  • Not all numbers can be perfectly represented in JavaScript. Their decimal part offers more precision closer to 0, and less precision further away from it.
    并非所有数字都能在 JavaScript 中完美表示。它们的小数部分在接近 0 时提供更多精度,而在远离它时提供更少精度。
  • Numbers from invalid math operations like 1 / 0 or 0 / 0 are special. NaN is one of such numbers. They may appear due to coding mistakes.
    来自无效数学运算的数字如 1 / 00 / 0 是特殊的。 NaN 是其中之一。这些数字可能由于编码错误而出现。
  • typeof(NaN) is a number because NaN is a numeric value. It’s called “Not a Number” because it represents the idea of an “invalid” number.
    typeof(NaN) 是一个数字,因为 NaN 是一个数值。它被称为“非数字”,因为它代表了“无效”数字的概念。

We will continue our sightseeing tour by meeting the non-primitive values, specifically, objects and functions.

Exercises 练习

This module also has exercises for you to practice!

Don’t skip them! 不要跳过它们!

Even though you’re likely familiar with the concept of primitive values, these exercises will help you cement the mental model we’re building. We need this foundation before we can get to more complex topics.