Loading...
墨滴

逸之

2022/01/12  阅读:30  主题:红绯

值、类型和运算符

Chapter 1 第一章Values, Types, and Operators 值、类型和运算符

Below the surface of the machine, the program moves. Without effort, it expands and contracts. In great harmony, electrons scatter and regroup. The forms on the monitor are but ripples on the water. The essence stays invisibly below.

在机器的表面之下,程序运行。没有努力,它就会扩张和收缩。在极大的和谐中,电子散射和重新组合。显示器上的形状不过是水面上的波纹。精华在下面是看不见的。

Master Yuan-Ma, The Book of Programming元马大师: 《程序设计之书》

![Picture of a sea of bits](img/chapter_picture_1.jpg)

Inside the computer’s world, there is only data. You can read data, modify data, create new data—but that which isn’t data cannot be mentioned. All this data is stored as long sequences of bits and is thus fundamentally alike.

在计算机的世界里,只有数据。你可以读取数据、修改数据、创建新数据,但是不能提及非数据。所有这些数据都被存储为长长的比特序列,因此基本上是相似的。

Bits are any kind of two-valued things, usually described as zeros and ones. Inside the computer, they take forms such as a high or low electrical charge, a strong or weak signal, or a shiny or dull spot on the surface of a CD. Any piece of discrete information can be reduced to a sequence of zeros and ones and thus represented in bits.

比特是任何一种两值的东西,通常被描述为0和1。在计算机内部,它们以各种形式存在,比如高电荷或低电荷,强信号或弱信号,或者 CD 表面的光点或暗点。任何一个离散的信息都可以被简化为一个由0和1组成的序列,因此可以用比特表示。

For example, we can express the number 13 in bits. It works the same way as a decimal number, but instead of 10 different digits, you have only 2, and the weight of each increases by a factor of 2 from right to left. Here are the bits that make up the number 13, with the weights of the digits shown below them:

例如,我们可以用比特表示数字13。它的工作原理与十进制数相同,但是你只有2个数字,而不是10个不同的数字,而且每个数字的重量从右向左增加了2倍。下面是组成数字13的位,下面显示的是数字的权重:

[](#c_+fMMNc3yUt)   0   0   0   0   1   1   0   1
 128  64  32  16   8   4   2   1

So that’s the binary number 00001101. Its non-zero digits stand for 8, 4, and 1, and add up to 13.

这就是二进制数00001101。它的非零数字代表8、4和1,加起来是13。

Values 价值观

Imagine a sea of bits—an ocean of them. A typical modern computer has more than 30 billion bits in its volatile data storage (working memory). Nonvolatile storage (the hard disk or equivalent) tends to have yet a few orders of magnitude more.

想象一个比特的海洋ーー它们的海洋。一台典型的现代计算机在其易失性数据存储器(工作存储器)中有超过300亿位。非易失性存储器(硬盘或类似数量级)往往还要多几百万。

To be able to work with such quantities of bits without getting lost, we must separate them into chunks that represent pieces of information. In a JavaScript environment, those chunks are called values. Though all values are made of bits, they play different roles. Every value has a type that determines its role. Some values are numbers, some values are pieces of text, some values are functions, and so on.

为了能够处理如此大量的位而不会丢失,我们必须将它们分成代表信息片段的块。在 JavaScript 环境中,这些块称为值。尽管所有的值都是由位组成的,但它们扮演着不同的角色。每个值都有一个确定其角色的类型。有些值是数字,有些值是文本片段,有些值是函数,等等。

To create a value, you must merely invoke its name. This is convenient. You don’t have to gather building material for your values or pay for them. You just call for one, and whoosh, you have it. They are not really created from thin air, of course. Every value has to be stored somewhere, and if you want to use a gigantic amount of them at the same time, you might run out of memory. Fortunately, this is a problem only if you need them all simultaneously. As soon as you no longer use a value, it will dissipate, leaving behind its bits to be recycled as building material for the next generation of values.

要创建值,只需调用其名称即可。这很方便。你不必为自己的价值观搜集建筑材料,也不必为此付出代价。你只需要打一个电话,然后嗖的一声,你就得到了。当然,它们并不是从稀薄的空气中产生的。每个值都必须存储在某个地方,如果您想同时使用大量的值,则可能会耗尽内存。幸运的是,只有当你同时需要它们时,这才是一个问题。一旦你不再使用一个值,它就会消失,留下它的位作为下一代值的建筑材料被回收。

This chapter introduces the atomic elements of JavaScript programs, that is, the simple value types and the operators that can act on such values.

本章介绍了 JavaScript 程序的原子元素,即简单的值类型和可以作用于这些值的操作符。

Numbers 数字

Values of the number type are, unsurprisingly, numeric values. In a JavaScript program, they are written as follows:

数字类型的值是数值,这并不奇怪。在 JavaScript 程序中,它们是这样写的:

[](#c_/u5ErTZbax)13

Use that in a program, and it will cause the bit pattern for the number 13 to come into existence inside the computer’s memory.

在程序中使用它,它将使数字13的位模式在计算机内存中产生。

JavaScript uses a fixed number of bits, 64 of them, to store a single number value. There are only so many patterns you can make with 64 bits, which means that the number of different numbers that can be represented is limited. With N decimal digits, you can represent 10N numbers. Similarly, given 64 binary digits, you can represent 264 different numbers, which is about 18 quintillion (an 18 with 18 zeros after it). That’s a lot.

使用固定数量的位,其中64位,来存储一个数值。你只能用64位制造出那么多的模式,这意味着可以表示的不同数字的数量是有限的。用 n 个十进制数字,可以表示10n 个数字。类似地,给定64个二进制数字,您可以表示264个不同的数字,大约是18的18次方(18后面有18个零)。这是很多。

Computer memory used to be much smaller, and people tended to use groups of 8 or 16 bits to represent their numbers. It was easy to accidentally overflow such small numbers—to end up with a number that did not fit into the given number of bits. Today, even computers that fit in your pocket have plenty of memory, so you are free to use 64-bit chunks, and you need to worry about overflow only when dealing with truly astronomical numbers.

计算机内存过去要小得多,人们倾向于用8位或16位的组来表示他们的数字。这么小的数字很容易不小心溢出,最终得到的数字不符合给定的比特数。今天,即使是放在口袋里的计算机也有足够的内存,所以你可以自由使用64位块,只有在处理真正的天文数字时,你才需要担心溢出。

Not all whole numbers less than 18 quintillion fit in a JavaScript number, though. Those bits also store negative numbers, so one bit indicates the sign of the number. A bigger issue is that nonwhole numbers must also be represented. To do this, some of the bits are used to store the position of the decimal point. The actual maximum whole number that can be stored is more in the range of 9 quadrillion (15 zeros)—which is still pleasantly huge.

不过,并不是所有小于18的整数都适合 JavaScript 数字。这些位也存储负数,所以一位表示数字的符号。一个更大的问题是,非整数也必须被表示。为了做到这一点,一些位被用来存储小数点的位置。实际可以存储的最大整数在9千万亿(15个零)范围内,这仍然是一个令人愉快的巨大数字。

Fractional numbers are written by using a dot.

小数是用点来表示的。

[](#c_tM8nqv41Gp)9.81

For very big or very small numbers, you may also use scientific notation by adding an e (for exponent), followed by the exponent of the number.

对于非常大或非常小的数字,您也可以使用科学记数法,方法是加上一个 e (表示指数) ,然后是数字的指数。

[](#c_6ew5w+VhSM)2.998e8

That is 2.998 × 108 = 299,800,000.

也就是2.998 × 108 = 299,800,000。

Calculations with whole numbers (also called integers) smaller than the aforementioned 9 quadrillion are guaranteed to always be precise. Unfortunately, calculations with fractional numbers are generally not. Just as π (pi) cannot be precisely expressed by a finite number of decimal digits, many numbers lose some precision when only 64 bits are available to store them. This is a shame, but it causes practical problems only in specific situations. The important thing is to be aware of it and treat fractional digital numbers as approximations, not as precise values.

整数(也称为整数)小于上述9千万亿次的计算保证总是精确的。不幸的是,使用小数的计算通常不是这样。正如 π (π)不能用有限数目的十进制数字精确表示一样,当只有64位可用来存储时,许多数字会失去某些精度。这是一种耻辱,但它只在特定的情况下引起实际问题。重要的是要意识到这一点,并把分数数字作为近似值,而不是精确值。

Arithmetic 算术

The main thing to do with numbers is arithmetic. Arithmetic operations such as addition or multiplication take two number values and produce a new number from them. Here is what they look like in JavaScript:

数字的主要功能是算术。加法或乘法之类的算术运算取两个数值,并从中产生一个新的数字。下面是它们在 JavaScript 中的样子:

[](#c_bSU4Vtv/mt)100 + 4 * 11

The + and * symbols are called operators. The first stands for addition, and the second stands for multiplication. Putting an operator between two values will apply it to those values and produce a new value.

和 * 符号称为操作符。第一个代表加法,第二个代表乘法。在两个值之间放置一个运算符会将其应用于这些值并生成一个新值。

But does the example mean “add 4 and 100, and multiply the result by 11,” or is the multiplication done before the adding? As you might have guessed, the multiplication happens first. But as in mathematics, you can change this by wrapping the addition in parentheses.

但是,这个例子的意思是“加4和100,然后将结果乘以11”,还是说乘法是在加法之前完成的?正如你可能已经猜到的,乘法首先发生。但是就像在数学中一样,你可以通过用括号包装加法来改变这一点。

[](#c_ij6V90ZZBQ)(100 + 4) * 11

For subtraction, there is the - operator, and division can be done with the / operator.

对于减法,有-运算符,除法可以用/运算符完成。

When operators appear together without parentheses, the order in which they are applied is determined by the precedence of the operators. The example shows that multiplication comes before addition. The / operator has the same precedence as *. Likewise for + and -. When multiple operators with the same precedence appear next to each other, as in 1 - 2 + 1, they are applied left to right: (1 - 2) + 1.

当运算符没有括号一起出现时,它们的应用顺序由运算符的优先级决定。这个例子说明乘法先于加法。运算符的优先级与 * 相同。+ 和-也是如此。当具有相同优先级的多个运算符相邻出现时,如在1-2 + 1中,它们被从左向右应用: (1-2) + 1。

These rules of precedence are not something you should worry about. When in doubt, just add parentheses.

您不必担心这些优先级规则。如果有疑问,只需添加括号即可。

There is one more arithmetic operator, which you might not immediately recognize. The % symbol is used to represent the remainder operation. X % Y is the remainder of dividing X by Y. For example, 314 % 100 produces 14, and 144 % 12 gives 0. The remainder operator’s precedence is the same as that of multiplication and division. You’ll also often see this operator referred to as modulo.

还有一个算术运算符,您可能无法立即识别。% 符号用于表示余数运算。X% y 是 x 除以 y 的余数。例如,314% 100得到14,144% 12得到0。余数运算符的优先级与乘法和除法的优先级相同。您还会经常看到这个操作符被称为模。

Special numbers 特别号码

There are three special values in JavaScript that are considered numbers but don’t behave like normal numbers.

在 JavaScript 中有三个特殊的值被认为是数字,但是它们的行为不像普通的数字。

The first two are Infinity and -Infinity, which represent the positive and negative infinities. Infinity - 1 is still Infinity, and so on. Don’t put too much trust in infinity-based computation, though. It isn’t mathematically sound, and it will quickly lead to the next special number: NaN.

前两个是无穷大和-无穷大,它们代表正无穷大和负无穷大。Infinity-1仍然是 Infinity 等等。不过,不要太相信基于无穷大的计算。这在数学上是不可靠的,并且很快就会导致下一个特殊的数字: NaN。

NaN stands for “not a number”, even though it is a value of the number type. You’ll get this result when you, for example, try to calculate 0 / 0 (zero divided by zero), Infinity - Infinity, or any number of other numeric operations that don’t yield a meaningful result.

NaN 表示“ not a number”,即使它是数字类型的值。例如,当您尝试计算0/0(0除以0)、 Infinity-Infinity 或任何其他不会产生有意义结果的数值操作时,就会得到这个结果。

Strings 弦乐

The next basic data type is the string. Strings are used to represent text. They are written by enclosing their content in quotes.

下一个基本数据类型是字符串。字符串用于表示文本。他们是通过把内容加引号而写成的。

[](#c_JcfC82q1V/)`Down on the sea`
"Lie on the ocean"
'Float on the ocean'

You can use single quotes, double quotes, or backticks to mark strings, as long as the quotes at the start and the end of the string match.

您可以使用单引号、双引号或回勾来标记字符串,只要字符串开头和结尾的引号匹配即可。

Almost anything can be put between quotes, and JavaScript will make a string value out of it. But a few characters are more difficult. You can imagine how putting quotes between quotes might be hard. Newlines (the characters you get when you press enter) can be included without escaping only when the string is quoted with backticks (```).

几乎任何东西都可以放在引号之间,JavaScript 会从中生成一个字符串值。但是有几个角色就比较难了。你可以想象在引号之间加引号是多么的困难。只有当字符串使用回标引号(‘)时,才可以包含换行符(当您按 enter 键时得到的字符)而不必转义。

To make it possible to include such characters in a string, the following notation is used: whenever a backslash (\) is found inside quoted text, it indicates that the character after it has a special meaning. This is called escaping the character. A quote that is preceded by a backslash will not end the string but be part of it. When an n character occurs after a backslash, it is interpreted as a newline. Similarly, a t after a backslash means a tab character. Take the following string:

为了能够在字符串中包含这样的字符,使用了以下符号: 每当在引用文本中发现反斜杠()时,它表明后面的字符具有特殊含义。这叫做转义字符。前面加反斜杠的引号不会结束字符串,而是字符串的一部分。当一个 n 字符出现在一个反斜杠后面时,它被解释为换行符。类似地,反斜杠后面的 t 表示制表符。以下面的字符串为例:

[](#c_L1XyfWLjvh)"This is the first line\nAnd this is the second"

The actual text contained is this:

实际内容如下:

[](#c_dbS7S3Fqly)This is the first line
And this is the second

There are, of course, situations where you want a backslash in a string to be just a backslash, not a special code. If two backslashes follow each other, they will collapse together, and only one will be left in the resulting string value. This is how the string “A newline character is written like "\n".” can be expressed:

当然,在某些情况下,您希望字符串中的反斜杠只是一个反斜杠,而不是一个特殊的代码。如果两个反斜杠相继出现,它们将一起折叠,结果字符串值中只剩下一个反斜杠。这就是字符串“ a newline character”如何写成“ n”的方式可以表达为:

[](#c_AuMrnbfo/X)"A newline character is written like \"\\n\"."

Strings, too, have to be modeled as a series of bits to be able to exist inside the computer. The way JavaScript does this is based on the Unicode standard. This standard assigns a number to virtually every character you would ever need, including characters from Greek, Arabic, Japanese, Armenian, and so on. If we have a number for every character, a string can be described by a sequence of numbers.

字符串也必须被建模为一系列位,以便能够存在于计算机内部。做这件事的方式是基于 Unicode 标准的。这个标准实际上为你需要的每个字符分配一个数字,包括希腊字符、阿拉伯字符、日语字符、亚美尼亚字符等等。如果我们对每个字符都有一个数字,那么一个字符串可以由一系列的数字来描述。

And that’s what JavaScript does. But there’s a complication: JavaScript’s representation uses 16 bits per string element, which can describe up to 216 different characters. But Unicode defines more characters than that—about twice as many, at this point. So some characters, such as many emoji, take up two “character positions” in JavaScript strings. We’ll come back to this in Chapter 5.

这就是 JavaScript 所做的。但是还有一个复杂的问题: JavaScript 的表示法每个字符串元素使用16位,可以描述多达216个不同的字符。但 Unicode 定义了更多的字符——目前大约是这个数字的两倍。因此,一些字符,比如很多表情符号,在 JavaScript 字符串中占据了两个“字符位置”。我们将在第五章回到这个问题。

Strings cannot be divided, multiplied, or subtracted, but the + operator can be used on them. It does not add, but it concatenates—it glues two strings together. The following line will produce the string "concatenate":

字符串不能被分割、相乘或减去,但是可以对它们使用 + 运算符。它不添加,但是它连接ー它把两个字符串粘在一起。下面的行将生成字符串“ concatenate”:

[](#c_eCO7oekmP9)"con" + "cat" + "e" + "nate"

String values have a number of associated functions (methods) that can be used to perform other operations on them. I’ll say more about these in Chapter 4.

字符串值有许多相关联的函数(方法) ,可用于对它们执行其他操作。我会在第四章详细说明这些。

Strings written with single or double quotes behave very much the same—the only difference is in which type of quote you need to escape inside of them. Backtick-quoted strings, usually called template literals, can do a few more tricks. Apart from being able to span lines, they can also embed other values.

使用单引号或双引号编写的字符串的行为非常相似ー唯一的区别在于需要在其中转义哪种类型的引号。回勾引用字符串,通常称为模板字符,可以做一些更多的技巧。除了能够跨越行之外,它们还可以嵌入其他值。

[](#c_1ObyeNEDOw)`half of 100 is ${100 / 2}`

When you write something inside ${} in a template literal, its result will be computed, converted to a string, and included at that position. The example produces “half of 100 is 50”.

当您在模板文本中的 ${}中写入内容时,其结果将被计算,转换为字符串,并包含在该位置。这个例子产生了“100的一半是50”。

Unary operators 一元操作符

Not all operators are symbols. Some are written as words. One example is the typeof operator, which produces a string value naming the type of the value you give it.

并非所有的运算符都是符号。有些是以文字的形式写成的。一个例子是 typeof 运算符,它产生一个字符串值,命名您给它的值的类型。

[](#c_iWT//VyY7j)console.log(typeof 4.5)
// → number
console.log(typeof "x")
// → string

We will use console.log in example code to indicate that we want to see the result of evaluating something. More about that in the next chapter.

在示例代码中,我们将使用 console.log 来表示我们希望看到计算结果。下一章会详细介绍。

The other operators shown all operated on two values, but typeof takes only one. Operators that use two values are called binary operators, while those that take one are called unary operators. The minus operator can be used both as a binary operator and as a unary operator.

显示的其他操作符都对两个值进行操作,但 typeof 只对一个值进行操作。使用两个值的运算符称为二元运算符,而使用一个值的运算符称为一元运算符。减号运算符既可以用作二元运算符,也可以用作一元运算符。

[](#c_VpL89RFAPj)console.log(- (10 - 2))
// → -8

Boolean values 布尔值

It is often useful to have a value that distinguishes between only two possibilities, like “yes” and “no” or “on” and “off”. For this purpose, JavaScript has a Boolean type, which has just two values, true and false, which are written as those words.

使用一个只能区分两种可能性的值,如“是”和“否”或“开”和“关”,通常是有用的。为此,JavaScript 有一个布尔类型,只有两个值 true 和 false,这两个值被写成这两个单词。

Comparison 比较

Here is one way to produce Boolean values:

这里有一种产生布尔值的方法:

[](#c_GaxnXrIPwC)console.log(3 > 2)
// → true
console.log(3 < 2)
// → false

The > and < signs are the traditional symbols for “is greater than” and “is less than”, respectively. They are binary operators. Applying them results in a Boolean value that indicates whether they hold true in this case.

和 < 符号分别是“大于”和“小于”的传统符号。它们是二进制运算符。应用它们会得到一个布尔值,该值指示在这种情况下它们是否为真。

Strings can be compared in the same way.

字符串可以以同样的方式进行比较。

[](#c_Qud5plnVuV)console.log("Aardvark" < "Zoroaster")
// → true

The way strings are ordered is roughly alphabetic but not really what you’d expect to see in a dictionary: uppercase letters are always “less” than lowercase ones, so "Z" < "a", and nonalphabetic characters (!, -, and so on) are also included in the ordering. When comparing strings, JavaScript goes over the characters from left to right, comparing the Unicode codes one by one.

字符串的排列方式大致是按字母顺序排列的,但并不是您期望在字典中看到的那样: 大写字母总是“小于”小写字母,因此“ z”< “ a”和非字母字符(!,-,等等)也包括在订购。当比较字符串时,JavaScript 从左到右遍历字符,逐个比较 Unicode 代码。

Other similar operators are >= (greater than or equal to), <= (less than or equal to), == (equal to), and != (not equal to).

其他类似的运算符是 > = (大于或等于)、 < = (小于或等于)、 = = (等于)和!= (不等于)。

[](#c_9h4L8Mnvdg)console.log("Itchy" != "Scratchy")
// → true
console.log("Apple" == "Orange")
// → false

There is only one value in JavaScript that is not equal to itself, and that is NaN (“not a number”).

JavaScript 中只有一个值不等于它自己,那就是 NaN (“不是一个数字”)。

[](#c_Vhz09Rgw3h)console.log(NaN == NaN)
// → false

NaN is supposed to denote the result of a nonsensical computation, and as such, it isn’t equal to the result of any other nonsensical computations.

NaN 被认为是表示无意义计算的结果,因此,它不等于任何其他无意义计算的结果。

Logical operators 逻辑运算符

There are also some operations that can be applied to Boolean values themselves. JavaScript supports three logical operators: and, or, and not. These can be used to “reason” about Booleans.

还有一些操作可以应用于布尔值本身。支持三个逻辑运算符: and,or,and,not。这些可以用来“推理”布尔值。

The && operator represents logical and. It is a binary operator, and its result is true only if both the values given to it are true.

& 运算符表示逻辑和。它是一个二元运算符,只有当给它的两个值都为真时,它的结果才为真。

[](#c_SHi38sNkwM)console.log(true && false)
// → false
console.log(true && true)
// → true

The || operator denotes logical or. It produces true if either of the values given to it is true.

| | 操作符表示逻辑值或。如果给它的值中有一个为真,它就会生成 true。

[](#c_diXyv7iPd1)console.log(false || true)
// → true
console.log(false || false)
// → false

Not is written as an exclamation mark (!). It is a unary operator that flips the value given to it—!true produces false, and !false gives true.

Not 被写成了一个叹号.它是一元运算符,它翻转赋予它的值ー! true 生成 false,and!虚假就是真实。

When mixing these Boolean operators with arithmetic and other operators, it is not always obvious when parentheses are needed. In practice, you can usually get by with knowing that of the operators we have seen so far, || has the lowest precedence, then comes &&, then the comparison operators (>, ==, and so on), and then the rest. This order has been chosen such that, in typical expressions like the following one, as few parentheses as possible are necessary:

当将这些布尔运算符与算术运算符和其他运算符混合使用时,在需要括号时并不总是显而易见的。在实践中,通常可以知道我们目前看到的运算符中 | | 的优先级最低,然后是 & & ,然后是比较运算符(> ,= = ,等等) ,然后是其他运算符。这个顺序的选择使得在典型的表达式中,比如下面的表达式中,尽可能少的括号是必要的:

[](#c_6eZ07bDo11)1 + 1 == 2 && 10 * 10 > 50

The last logical operator I will discuss is not unary, not binary, but ternary, operating on three values. It is written with a question mark and a colon, like this:

我要讨论的最后一个逻辑运算符不是一元运算符,也不是二元运算符,而是三元运算符。它是用问号和冒号写的,像这样:

[](#c_G7eVm8ilWm)console.log(true ? 1 : 2);
// → 1
console.log(false ? 1 : 2);
// → 2

This one is called the conditional operator (or sometimes just the ternary operator since it is the only such operator in the language). The value on the left of the question mark “picks” which of the other two values will come out. When it is true, it chooses the middle value, and when it is false, it chooses the value on the right.

这个操作符被称为条件运算符操作符(或者有时仅仅是三元操作符,因为它是语言中唯一的这样的操作符)。问号左边的值“选择”其他两个值中的哪一个。当它为真时,它选择中间值,当它为假时,它选择右边的值。

Empty values 空值

There are two special values, written null and undefined, that are used to denote the absence of a meaningful value. They are themselves values, but they carry no information.

有两个特殊值(写为 null 和未定义)用于表示没有有意义的值。它们本身就是价值观,但它们没有携带任何信息。

Many operations in the language that don’t produce a meaningful value (you’ll see some later) yield undefined simply because they have to yield some value.

语言中的许多操作不产生有意义的值(您将在后面看到一些) ,因为它们必须产生一些值而产生未定义的操作。

The difference in meaning between undefined and null is an accident of JavaScript’s design, and it doesn’t matter most of the time. In cases where you actually have to concern yourself with these values, I recommend treating them as mostly interchangeable.

Undefined 和 null 之间的意义差异是 JavaScript 设计的一个偶然事件,而且大多数时候并不重要。如果您实际上不得不关注这些值,我建议您将它们视为大部分是可互换的。

Automatic type conversion 自动类型转换

In the Introduction, I mentioned that JavaScript goes out of its way to accept almost any program you give it, even programs that do odd things. This is nicely demonstrated by the following expressions:

在前言中,我提到 JavaScript 会不遗余力地接受你给它的几乎任何程序,甚至是做奇怪事情的程序。下面的表达式很好地说明了这一点:

[](#c_QqYG9KqZ2/)console.log(8 * null)
// → 0
console.log("5" - 1)
// → 4
console.log("5" + 1)
// → 51
console.log("five" * 2)
// → NaN
console.log(false == 0)
// → true

When an operator is applied to the “wrong” type of value, JavaScript will quietly convert that value to the type it needs, using a set of rules that often aren’t what you want or expect. This is called type coercion. The null in the first expression becomes 0, and the "5" in the second expression becomes 5 (from string to number). Yet in the third expression, + tries string concatenation before numeric addition, so the 1 is converted to "1" (from number to string).

当运算符被应用到“错误的”值类型时,JavaScript 会悄悄地将该值转换为它需要的类型,使用一组通常不是您想要或期望的规则。这就是所谓的类型强制。第一个表达式中的 null 变为0,第二个表达式中的“5”变为5(从字符串到数字)。然而在第三个表达式中,+ 在数值加法之前尝试字符串串联,所以1被转换为“1”(从数字转换为字符串)。

When something that doesn’t map to a number in an obvious way (such as "five" or undefined) is converted to a number, you get the value NaN. Further arithmetic operations on NaN keep producing NaN, so if you find yourself getting one of those in an unexpected place, look for accidental type conversions.

当不以明显的方式映射到数字的事物(例如“ five”或未定义)转换为数字时,您将得到值 NaN。NaN 上的进一步算术运算不断产生 NaN,因此如果您发现自己在意想不到的地方获得了其中的一个,请查找意外的类型转换。

When comparing values of the same type using ==, the outcome is easy to predict: you should get true when both values are the same, except in the case of NaN. But when the types differ, JavaScript uses a complicated and confusing set of rules to determine what to do. In most cases, it just tries to convert one of the values to the other value’s type. However, when null or undefined occurs on either side of the operator, it produces true only if both sides are one of null or undefined.

当使用 = = 比较相同类型的值时,结果很容易预测: 当两个值相同时,结果应该为 true,但 NaN 例外。但是当类型不同时,JavaScript 使用一组复杂而混乱的规则来决定要做什么。在大多数情况下,它只是尝试将其中一个值转换为另一个值的类型。但是,当运算符的任何一边出现 null 或未定义时,只有当两边都为 null 或未定义时才会产生 true。

[](#c_qmGDPdETlf)console.log(null == undefined);
// → true
console.log(null == 0);
// → false

That behavior is often useful. When you want to test whether a value has a real value instead of null or undefined, you can compare it to null with the == (or !=) operator.

这种行为通常是有用的。当您想要测试一个值是否有一个真正的值,而不是 null 或未定义的值时,您可以将它与 = = (或!=)操作符。

But what if you want to test whether something refers to the precise value false? Expressions like 0 == false and "" == false are also true because of automatic type conversion. When you do not want any type conversions to happen, there are two additional operators: === and !==. The first tests whether a value is precisely equal to the other, and the second tests whether it is not precisely equal. So "" === false is false as expected.

但是,如果您想要测试某个值是否指向精确值 false,该怎么办呢?由于自动类型转换,像0 = = false 和””= = false 这样的表达式也是 true。当您不希望发生任何类型转换时,还有两个附加运算符: = = 和!==.第一个测试一个值是否精确地等于另一个值,第二个测试它是否精确地不等于。所以“”= = = false 正如预期的那样是假的。

I recommend using the three-character comparison operators defensively to prevent unexpected type conversions from tripping you up. But when you’re certain the types on both sides will be the same, there is no problem with using the shorter operators.

我建议防御性地使用三个字符的比较运算符,以防止出现意外的类型转换。但是当你确定两边的类型是相同的时候,使用较短的操作符是没有问题的。

Short-circuiting of logical operators 逻辑运算符短路

The logical operators && and || handle values of different types in a peculiar way. They will convert the value on their left side to Boolean type in order to decide what to do, but depending on the operator and the result of that conversion, they will return either the original left-hand value or the right-hand value.

逻辑运算符 & & 和 | | | 以一种特殊的方式处理不同类型的值。它们将左侧的值转换为布尔类型以决定要做什么,但是根据操作符和转换的结果,它们将返回原始左侧值或右侧值。

The || operator, for example, will return the value to its left when that can be converted to true and will return the value on its right otherwise. This has the expected effect when the values are Boolean and does something analogous for values of other types.

例如,当可以将值转换为 true 时,| | 运算符将把值返回到其左侧,否则将返回其右侧的值。当值为布尔值时,这有预期的效果,并且与其他类型的值类似。

[](#c_ENjxHGMklb)console.log(null || "user")
// → user
console.log("Agnes" || "user")
// → Agnes

We can use this functionality as a way to fall back on a default value. If you have a value that might be empty, you can put || after it with a replacement value. If the initial value can be converted to false, you’ll get the replacement instead. The rules for converting strings and numbers to Boolean values state that 0, NaN, and the empty string ("") count as false, while all the other values count as true. So 0 || -1 produces -1, and "" || "!?" yields "!?".

我们可以使用这个功能作为回到默认值的一种方式。如果有一个值可能是空的,可以在后面添加一个替换值。如果初始值可以转换为 false,那么您将得到替换。将字符串和数字转换为布尔值的规则指出,0、 NaN 和空字符串(“”)计为 false,而所有其他值计为 true。所以0 | |-1生成 -1,还有“ |”! ”让步”.

The && operator works similarly but the other way around. When the value to its left is something that converts to false, it returns that value, and otherwise it returns the value on its right.

& 操作符的工作方式相似,但是相反。当其左侧的值转换为 false 时,它返回该值,否则返回其右侧的值。

Another important property of these two operators is that the part to their right is evaluated only when necessary. In the case of true || X, no matter what X is—even if it’s a piece of program that does something terrible—the result will be true, and X is never evaluated. The same goes for false && X, which is false and will ignore X. This is called short-circuit evaluation.

这两个运算符的另一个重要特性是,只有在必要时才对其权限的部分进行评估。在 true | | x 的情况下,无论 x 是什么,即使它是一个做了可怕事情的程序片段,结果都是真实的,而且 x 永远不会被求值。同样的情况也适用于 false & x,它是 false 并且会忽略 x。这就是所谓的短路求值。

The conditional operator works in a similar way. Of the second and third values, only the one that is selected is evaluated.

条件运算符的工作方式与此类似。在第二个和第三个值中,只计算选定的值。

Summary 摘要

We looked at four types of JavaScript values in this chapter: numbers, strings, Booleans, and undefined values.

在本章中,我们讨论了四种类型的 JavaScript 值: 数字、字符串、布尔值和未定义的值。

Such values are created by typing in their name (true, null) or value (13, "abc"). You can combine and transform values with operators. We saw binary operators for arithmetic (+, -, *, /, and %), string concatenation (+), comparison (==, !=, ===, !==, <, >, <=, >=), and logic (&&, ||), as well as several unary operators (- to negate a number, ! to negate logically, and typeof to find a value’s type) and a ternary operator (?:) to pick one of two values based on a third value.

这些值是通过输入它们的名称(true,null)或值(13,“ abc”)创建的。可以使用运算符组合和转换值。我们看到了用于算术(+ ,-,* ,/,和%)、字符串连接(+)、比较(= = ,!=,===,!= = ,< ,> ,< = ,> =) ,逻辑(& & ,| |) ,以及几个一元运算符(- 对一个数,!逻辑上是否定的,而 typeof 则是查找值的类型)和三元运算符(?:)从基于第三个值的两个值中选择一个。

This gives you enough information to use JavaScript as a pocket calculator but not much more. The next chapter will start tying these expressions together into basic programs.

这给了你足够的信息来使用 JavaScript 作为一个计算器/代码,但是仅此而已。下一章将开始把这些表达式组合成基本程序。

逸之

2022/01/12  阅读:30  主题:红绯

作者介绍

逸之