发布日期 » 2017年9月27日 星期三

版权声明 » 帅华君原创文章,未经允许不得转载。

Eloquent JavaScript译文第二版 / 数值

作者: Marijn Haverbeke

在线阅读原文地址:http://eloquentjavascript.net/

这本书是关于 Javascriptprogrammingwonders of the digital

Licensed under a Creative Commons attribution-noncommercial license. All code in this book may also be considered licensed under an MIT license.

目录

  • 值,类型与运算符
  • 程序结构
  • 函数
  • 数据结构:对象与数组
  • 高阶函数
  • 对象的秘密
  • 项目:电子的生命

值,类型与运算符

“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

在电脑的世界里,只有数据。您可以读取数据,修改数据,创建新数据——不存在任何不能用数据表示的事物。所有这些数据作为长序列存储,因此基本相同。

可以表示任何一种两重的东西,通常被描述为零和一。在计算机中,它们以诸如高或低电位的形式,强或弱信号,或光盘表面有光泽或暗淡的斑点的形式存在。任何一条离散的信息都可以被一些0和1的序列以位来表示。

例如,想想你可能会如何用表示数字13。它的工作方式与编写十进制数的方式相同,但不是10个不同的数字,你只有2个数字,并且每个的权重从右到左增加2倍。下图为二进制表示的十进制13:

陈帅华-HUD未来交互界面

所以这是二进制数 00001101,或8 + 4 + 1,等于13。

Values

想象一下大海,他们的海洋。典型的现代计算机在其非永久存储设备(内存)中有超过300亿的,永久存储(硬盘或其他永久存储设备)往往有好几个数量级。

陈帅华-HUD未来交互界面

为了能够处理这样的数量的而不会迷失,您可以将它们分成代表信息块的块。在JavaScript环境中,这些块被称为值(Value)。虽然所有的值都是由位组成的,但它们扮演着不同的角色。每个值都有一个确定其作用的类型。JavaScript中有六种基本类型的值:numbers, strings, Booleans, objects, functions, 和 undefined 值。

要创建一个值,您只需调用其名称即可。这很方便。你不必付出任何代价,你只需要call它即可,当然他们也不是由空气组成的。每个值都必须存储在某个地方,如果你想在同一时间使用大量的数据,你可能会用完。幸运的是,只用当你同时使用它们时才会产生这样的问题。一旦你不再使用该值,它将消散,留下它的等待下一条数据。

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

Numbers

数字类型的值不出意料的是数值。 在JavaScript程序中,它们写成如下:

13

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

JavaScript使用固定数量的位,即其中64个存储单个数字值。 只有这么多的模式可以用64位,这意味着可以表示的不同数量的数量是有限的。 对于N个十进制数字,可以表示的数字量为10N。 类似地,给出64位二进制数字,您可以表示264个不同的数字,大约为18个数字(18个,18个之后)。 这很多

计算机内存过去要小一些,人们倾向于使用8位或16位的组来表示数字。 很容易意外地溢出这么小的数字 - 最终得到的数字不适合给定的位数。 今天,即使个人电脑有足够的记忆,所以你可以随意使用64位的块,这意味着只有在处理真正的天文数字时才需要担心溢出。

不过,并不是所有的全部数字都低于18 quintillion适合JavaScript编号。 那些位也存储负数,所以一位表示数字的符号。 一个更大的问题是也可以表示非空数。 为此,有些位用于存储小数点的位置。 可存储的实际最大整数更多在9千兆(15个零)的范围内,这仍然是巨大的。

使用点写入分数。

9.81

对于非常大或非常小的数字,您还可以使用科学符号添加“e”(对于“指数”),后跟数字的指数:

2.998e8

算式 2.998 × 108 = 299,800,000

小于上述9万亿次数的整数(也称为整数)的计算保证始终是精确的。 不幸的是,分数的计算通常不是。 正如π(pi)不能用有限数字的十进制数精确地表示,当只有64位可用于存储它们时,许多数字丢失一些精度。 这是一个耻辱,但它只会在具体情况下造成实际问题。 重要的是要注意它,并将分数字数字视为近似值,而不是精确值。

Arithmetic

与数字有关的主要事项是算术。 诸如加法或乘法的算术运算取两个数值,并从中产生一个新的数字。 以下是JavaScript中的内容:

100 + 4 * 11

+和*符号称为运算符。 第一个代表加法,第二个代表乘法。 将一个运算符放在两个值之间将它应用于这些值并产生一个新的值。

这个例子是否意味着“添加4和100,并将结果乘以11”,或者是在添加之前完成的乘法? 你可能猜到,乘法首先出现。 但是,在数学中,您可以通过将括号括起来来改变它。

(100 + 4) * 11

对于减法,有 - 运算符,并且可以使用/运算符进行除法。

当操作员一起显示而不带圆括号时,其应用顺序由操作员的优先级决定。 该示例显示乘法在添加之前。 /运算符与*的优先级相同。 对于+和 - 也是如此。 当具有相同优先级的多个运算符彼此相邻时,如1 - 2 + 1中,它们从左到右应用:(1 - 2)+ 1。

这些优先规则不是你应该担心的事情。 当有疑问时,只需加上括号。

还有一个算术运算符,您可能不会立即识别。 %符号用于表示余数运算。 X%Y是将X除以Y的剩余部分。例如,314%100产生14,144%12产生0.剩余的优先级与乘法和除法相同。 你经常会看到这个运算符称为模数,尽管技术上余数更准确。

Special numbers

JavaScript中有三个特殊值被视为数字,但不像正常数字那样表现。

前两者是无限和无限,它们代表了正面和负面的无穷大。 无限 - 1仍然是无限等等。 不要太信任基于无穷的计算。 它不是数学上坚实的,它会很快导致我们的下一个特殊号码:NaN。

NaN代表“不是数字”,即使它是数字类型的值。 例如,当您尝试计算0/0(零除以零),Infinity - Infinity或任何数量的其他不能产生精确,有意义的结果的数字运算时,您将得到此结果。

Strings

下一个基本数据类型是字符串。 字符串用于表示文本。 它们是用引号括起来写的。

"Patch my boat with chewing gum"
'Monkeys wave goodbye'

只要字符串的起始和末尾的引号相匹配,可以使用单引号和双引号来标记字符串。

引用之间几乎可以放置任何东西,而JavaScript将会产生一个字符串值。 但是几个字符更难。 你可以想象如何在引号之间放置引号可能很难。 换行符(当你按Enter键时你得到的字符)也不能放在引号之间。 字符串必须停留在一条线上。

为了使这样的字符可以包含在一个字符串中,使用以下符号:每当在引用文本内部找到反斜杠(\)时,它表示它后面的字符具有特殊的含义。 这被称为逃避角色。 之前带有反斜杠的引号将不会结束字符串,而是它的一部分。 当一个n字符出现在反斜杠之后时,它被解释为一个换行符。 类似地,反斜杠之后的t表示制表符。 采取以下字符串:

"This is the first line\nAnd this is the second"

包含的实际文字是:

This is the first line
And this is the second

当然,您希望在字符串中使用反斜杠作为反斜杠,而不是特殊代码。 如果两个反斜杠相互跟随,它们将一起折叠,并且只有一个将留在结果字符串值中。 这是字符串“换行符”如“\ n”。“可以表达:

"A newline character is written like \"\\n\"."

字符串不能被分割,相乘或相减,但可以使用+运算符。 它不添加,但它连接 - 它将两个字符串粘在一起。 以下行将产生字符串“concatenate”:

"con" + "cat" + "e" + "nate"

有更多的操纵字符串的方式,我们将在第4章中讨论方法时讨论。

Unary operators

并非所有操作员都是符号。 有些是写成单词。 一个例子是typeof运算符,它产生一个字符串值,命名你给它的值的类型。

console.log(typeof 4.5)
// → number
console.log(typeof "x")
// → string

我们将在示例代码中使用console.log来表示我们想要查看评估结果的结果。 当您运行这样的代码时,产生的值应该显示在屏幕上,尽管如何显示将取决于用于运行它的JavaScript环境。

我们看到的其他操作员都运行在两个值上,但type仅需一个。 使用两个值的运算符称为二进制运算符,而使用两个值的运算符称为一元运算符。 负运算符既可以用作二进制运算符,也可以用作一元运算符。

console.log(- (10 - 2))
// → -8

Boolean values

通常,您需要一个简单区分两种可能性的值,例如“是”,“否”或“开”和“关”。 为此,JavaScript有一个布尔类型,它只有两个值:true和false(简单地写成这些字)。

Comparisons

以下是生成布尔值的一种方法:

console.log(3 > 2)
// → true
console.log(3 < 2)
// → false

和<符号分别是“大于”和“小于”的传统符号。 它们是二进制运算符。 应用它们会产生一个布尔值,表示在这种情况下它们是否成立。

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

console.log("Aardvark" < "Zoroaster")
// → true

字符串的排列方式或多或少是字母大写的:大写字母总是小于小写字母,所以“Z”<“a”是真的,非字母字符(!, - 等)也包括在内 在订购。 实际的比较是基于Unicode标准。 本标准为您需要的每个字符分配一个数字,包括希腊语,阿拉伯语,日语,泰米尔语等中的字符。 具有这样的数字对于在计算机内存储字符串是有用的,因为它可以将它们表示为数字序列。 比较字符串时,JavaScript会从左到右,逐个比较字符的数字代码。

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

console.log("Itchy" != "Scratchy")
// → true

JavaScript中只有一个值不等于自身,而NaN则代表“不是数字”。

console.log(NaN == NaN)
// → false

NaN应该表示无意识计算的结果,因此它不等于任何其他无意义计算的结果。

Logical operators

还有一些可以应用于布尔值本身的操作。 JavaScript支持三个逻辑运算符:和,或,而不是。 这些可以用于“推理”布尔。

&&运算符表示逻辑。 它是一个二进制运算符,只有两个值都为真,它的结果才是真的。

console.log(true && false)
// → false
console.log(true && true)
// → true

|| 运算符表示逻辑或。 如果赋予它的任何一个值都为真,它将会生成。

console.log(false || true)
// → true
console.log(false || false)
// → false

不是写成感叹号(!)。 它是一个一元的运算符,翻转给它的值 - !true产生false,而false为true。

当将这些布尔运算符与算术运算符和其他运算符进行混合时,需要括号时并不总是很明显。 在实践中,您通常可以了解到目前为止所看到的运算符,|| 具有最低优先级,然后来到&&,然后比较运算符(>,==等),然后其余。 已经选择了这个顺序,使得在下面的典型表达式中,尽可能少的括号是必要的:

1 + 1 == 2 && 10 * 10 > 50

我将讨论的最后一个逻辑运算符不是一元的,而不是二进制,而是三进制,运行在三个值上。 它是用一个问号和一个冒号写的,如下所示:

console.log(true ? 1 : 2);
// → 1
console.log(false ? 1 : 2);
// → 2

这个称为条件运算符(或者有时只是三进制运算符,因为它是该语言中唯一的运算符)。 问号左边的值“挑选”其他两个值中的哪一个会出来。 当它是真的,中间值被选择,当它是假时,右边的值出来。

Undefined values

有两个特殊值,写为null和undefined,用于表示没有有意义的值。 他们本身就是价值观,但它们并不是信息。

许多语言中没有产生有意义价值的操作(稍后会看到一些),因为它们必须产生一些值才会产生未定义。

未定义和null之间的含义之间的差异是JavaScript设计的一个意外,大多数时候并不重要。 在你实际上必须关心这些价值观的情况下,我建议将它们视为可互换(稍后更多的)。

Automatic type conversion

在介绍中,我提到JavaScript不能接受几乎任何你给它的程序,甚至程序做奇怪的事情。 这通过以下表达式很好地证明:

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

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

当不明显地映射到数字的东西(例如“五”或未定义)被转换为一个数字时,产生值NaN。 NaN的进一步的算术运算不断产生NaN,所以如果你发现自己在意外的地方得到其中之一,那么寻找意外的类型转换。

当使用==比较相同类型的值时,结果很容易预测:除了NaN的情况之外,当两个值都相同时,应该得到true。 但是,当类型不同时,JavaScript会使用一组复杂且混乱的规则来确定该做什么。 在大多数情况下,它只是尝试将其中一个值转换为其他值的类型。 但是,如果在运算符的任一侧发生null或undefined,则只有当双方都为null或未定义时才会生效。

console.log(null == undefined);
// → true
console.log(null == 0);
// → false

最后一个行为通常是有用的。 当你想测试一个值是否具有一个实际值而不是null或者undefined时,你可以简单地将它与==(或!=)运算符进行比较。

但是,如果你想测试某些东西是否指的是错误的值呢? 将字符串和数字转换为布尔值的规则表明,0,NaN和空字符串(“”)计数为false,而所有其他值都为真。 因此,像0 == false和“”== false这样的表达式也是如此。 对于这种情况,您不希望任何自动类型转换发生,有两个额外的运算符:===和!==。 第一次测试一个值是否精确地等于另一个值,而第二个测试是否不完全相等。 所以“”===假如预期是假的。

我建议您防范地使用三个字符的比较运算符来防止意外的类型转换。 但是当你确定两边的类型是一样的时候,使用较短的运算符就没有问题。

Short-circuiting of logical operators

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

|| 例如,运算符将返回到左侧的值,当该值可以转换为true时,否则返回值。 此转换的工作方式与布尔值一样,并且应该类似于其他类型的值。

console.log(null || "user")
// → user
console.log("Karl" || "user")
// → Karl

此功能允许|| 运算符被用作回退到默认值的方式。 如果您给它一个可能在左边产生一个空值的表达式,那么在这种情况下,右侧的值将被用作替换。

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

这两个运营商的另一个重要特性是只有在必要时才对其右侧的表达进行评估。 在真实||的情况下 X,无论X是什么,即使它是一个表现可怕的结果 - 结果将是真的,X从来没有评估过。 对于false && X也是如此,它是false,将忽略X.这被称为短路评估。

条件运算符以类似的方式工作。 第一个表达式总是被评估,但是第二个或第三个值是不被选中的。

Summary

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

这些值通过键入其名称(true,null)或值(13,“abc”)创建。 您可以与运算符组合和转换值。 我们看到算术运算符(+, - ,*,/和%),字符串连接(+),比较(==,!=,===,!==,<,>,<=,> = )和逻辑(&&,||)以及几个一元运算符( - 否定一个数字,以逻辑取反,并找到一个值的类型)和一个三元运算符(?:)来选择两个 基于第三个值的值。

这给您足够的信息,使用JavaScript作为口袋计算器,但不是更多。 下一章将开始将这些表达式结合在一起成为基本程序。