JavaScript 编程精解 中文第三版 1、值,类型和运算符

来源: ApacheCN『JavaScript 编程精解 中文第三版』翻译项目

原文:Values, Types, and Operatorsjavascript

译者:飞龙html

协议:CC BY-NC-SA 4.0java

自豪地采用谷歌翻译git

部分参考了《JavaScript 编程精解(第 2 版)》github

在机器的表面之下,程序在运转。 它不费力就能够扩大和缩小。 在和谐的关系中,电子散开并从新聚合。 监视器上的表格只是水面上的涟漪。 本质隐藏在下面。apache

Master Yuan-Ma,《The Book of Programming》编程

计算机世界里只有数据。 你能够读取数据,修改数据,建立新数据 - 但不能说起不是数据的东西。 全部这些数据都以位的长序列存储,所以基本类似。函数

位是任何类型的二值的东西,一般描述为零和一。 在计算机内部,他们有一些形式,例如高电荷或低电荷,强信号或弱信号,或 CD 表面上的亮斑点或暗斑点。 任何一段离散信息均可以简化为零和一的序列,从而以位表示。测试

例如,咱们能够用位来表示数字 13。 它的原理与十进制数字相同,但不是 10 个不一样的数字,而只有 2 个,每一个数字的权重从右到左增长 2 倍。 如下是组成数字 13 的位,下方显示数字的权重:this

0   0   0   0   1   1   0   1
 128  64  32  16   8   4   2   1

所以,这就是二进制数00001101,或者8+4+1,即 13。

想象一下位之海 - 一片它们的海洋。 典型的现代计算机的易失性数据存储器(工做存储器)中,有超过 300 亿位。非易失性存储(硬盘或等价物)每每还有几个数量级。

为了可以在不丢失的状况下,处理这些数量的数据,咱们必须将它们分红表明信息片断的块。 在 JavaScript 环境中,这些块称为值。 虽然全部值都是由位构成的,但他们起到不一样的做用,每一个值都有一个决定其做用的类型。 有些值是数字,有些值是文本片断,有些值是函数,等等。

要建立一个值,你只须要调用它的名字。 这很方便。 你没必要为你的值收集建筑材料或为其付费。 你只须要调用它,而后刷的一下,你就有了它。 固然,它们并非真正凭空创造的。 每一个值都必须存储在某个地方,若是你想同时使用大量的值,则可能会耗尽内存。 幸运的是,只有同时须要它们时,这才是一个问题。 只要你再也不使用值,它就会消失,留下它的一部分做为下一代值的建筑材料。

本章将会介绍 JavaScript 程序当中的基本元素,包括简单的值类型以及值运算符。

数字

数字(Number)类型的值即数字值。在 JavaScript 中写成以下形式:

13

在程序中使用这个值的时候,就会将数字 13 以位序列的方式存放在计算机的内存当中。

JavaScript使用固定数量的位(64 位)来存储单个数字值。 你能够用 64 位创造不少模式,这意味着能够表示的不一样数值是有限的。 对于N个十进制数字,能够表示的数值数量是10^N。 与之相似,给定 64 个二进制数字,你能够表示2^64个不一样的数字,大约 18 亿亿(18 后面有 18 个零)。太多了。

过去计算机内存很小,人们倾向于使用一组 8 位或 16 位来表示他们的数字。 这么小的数字很容易意外地溢出,最终获得的数字不能放在给定的位数中。 今天,即便是装在口袋里的电脑也有足够的内存,因此你能够自由使用 64 位的块,只有在处理真正的天文数字时才须要担忧溢出。

不过,并不是全部 18 亿亿如下的整数都能放在 JavaScript 数值中。 这些位也存储负数,因此一位用于表示数字的符号。 一个更大的问题是,也必须表示非整数。 为此,一些位用于存储小数点的位置。 能够存储的实际最大整数更多地在 9 亿亿(15 个零)的范围内 - 这仍然至关多。

使用小数点来表示分数。

9.81

对于很是大或很是小的数字,你也能够经过输入e(表示指数),后面跟着指数来使用科学记数法:

2.998e8

2.998 * 10^8 = 299,800,000

当计算小于前文当中提到的 9000 万亿的整数时,其计算结果会十分精确,不过在计算小数的时候精度却不高。正如(pi)没法使用有限个数的十进制数字表示同样,在使用 64 位来存储分数时也一样会丢失一些精度。虽然说如此,但这类丢失精度只会在一些特殊状况下才会出现问题。所以咱们须要注意在处理分数时,将其视为近似值,而非精确值。

算术

与数字密切相关的就是算术。好比,加法或者乘法之类的算术运算会使用两个数值,并产生一个新的数字。JavaScript 中的算术运算以下所示:

100 + 4 * 11

咱们把+*符号称为运算符。第一个符号表示加法,第二个符号表示乘法。将一个运算符放在两个值之间,该运算符将会使用其旁边的两个值产生一个新值。

可是这个例子的意思是“将 4 和 100 相加,并将结果乘 11”,仍是是在加法以前计算乘法? 正如你可能猜到的那样,乘法首先计算。 可是和数学同样,你能够经过将加法包在圆括号中来改变它:

(100 + 4) * 11

运算符表示减法,/运算符则表示除法。

在运算符同时出现,而且没有括号的状况下,其运算顺序根据运算符优先级肯定。示例中的乘法运算符优先级高于加法。而/运算符和*运算符优先级相同,+运算符和运算符优先级也相同。当多个具备相同优先级的运算符相邻出现时,运算从左向右执行,好比1–2+1的运算顺序是(1–2)+1

你无需担忧这些运算符的优先级规则,不肯定的时候只须要添加括号便可。

还有一个算术运算符,你可能没法当即认出。 %符号用于表示取余操做。 X % YYX的余数。 例如,314 % 100产生14144 % 12产生0。 余数的优先级与乘法和除法的优先级相同。 你还常常会看到这个运算符被称为模运算符。

特殊数字

在 JavaScript 中有三个特殊的值,它们虽然是数字,但看起来却跟通常的数字不太同样。

前两个是Infinity-Infinity,它们表明正无穷和负无穷。 “无穷减一”仍然是“无穷”,依此类推。 尽管如此,不要过度信任基于无穷大的计算。 它在数学上不合理,而且很快致使咱们的下一个特殊数字:NaN

NaN表明“不是数字”,即便它是数字类型的值。 例如,当你尝试计算0/0(零除零),Infinity - Infinity或任何其余数字操做,它不会产生有意义的结果时,你将获得此结果。

字符串

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

`Down on the sea`
"Lie on the ocean"
'Float on the ocean'

只要字符串开头和结尾的引号匹配,就可使用单引号,双引号或反引号来标记字符串。

几乎全部的东西均可以放在引号之间,而且 JavaScript 会从中提取字符串值。 但少数字符更难。 你可能不可思议,如何在引号之间加引号。 当使用反引号( ` )引用字符串时,换行符(当你按回车键时得到的字符)可能会被包含,而无需转义。

若要将这些字符存入字符串,须要使用下列规则:当反斜杠(\)出如今引号之间的文本中时,表示紧跟在其后的字符具备特殊含义,咱们将其称之为转义符。当引号紧跟在反斜杠后时,并不意味着字符串结束,而表示这个引号是字符串的一部分。当字符n出如今反斜杠后时,JavaScript 将其解释成换行符。以此类推,\t表示制表符,咱们来看看下面这个字符串:

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

该字符串实际表示的文本是:

This is the first line
And this is the second

固然,在某些状况下,你但愿字符串中的反斜杠只是反斜杠,而不是特殊代码。 若是两个反斜杠写在一块儿,它们将合并,而且只有一个将留在结果字符串值中。 这就是字符串“A newline character is written like "\n".”的表示方式:

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

字符串也必须建模为一系列位,以便可以存在于计算机内部。 JavaScript 执行此操做的方式基于 Unicode 标准。 该标准为你几乎须要的每一个字符分配一个数字,包括来自希腊语,阿拉伯语,日语,亚美尼亚语,以及其余的字符。 若是咱们为每一个字符分配一个数字,则能够用一系列数字来描述一个字符串。

这就是 JavaScript 所作的。 可是有一个复杂的问题:JavaScript 的表示为每一个字符串元素使用 16 位,它能够描述多达 2 的 16 次方个不一样的字符。 可是,Unicode 定义的字符多于此 - 大约是此处的两倍。 因此有些字符,好比许多 emoji,在 JavaScript 字符串中占据了两个“字符位置”。 咱们将在第 5 章中回来讨论。

咱们不能将除法,乘法或减法运算符用于字符串,可是+运算符却能够。这种状况下,运算符并不表示加法,而是链接操做:将两个字符串链接到一块儿。如下语句能够产生字符串"concatenate"

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

字符串值有许多相关的函数(方法),可用于对它们执行其余操做。 咱们将在第 4 章中回来讨论。

用单引号或双引号编写的字符串的行为很是类似 - 惟一的区别是须要在其中转义哪一种类型的引号。 反引号字符串,一般称为模板字面值,能够实现更多的技巧。 除了可以跨越行以外,它们还能够嵌入其余值。

`half of 100 is ${100 / 2}`

当你在模板字面值中的$ {}中写入内容时,将计算其结果,转换为字符串并包含在该位置。 这个例子产生"half of 100 is 50"

一元运算符

并不是全部的运算符都是用符号来表示,还有一些运算符是用单词表示的。好比typeof运算符,会产生一个字符串的值,内容是给定值的具体类型。

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

咱们将在示例代码中使用console.log,来表示咱们但愿看到求值结果。更多内容请见下一章。

咱们所见过的绝大多数运算符都使用两个值进行操做,而typeof仅接受一个值进行操做。使用两个值的运算符称为二元运算符,而使用一个值的则称为一元运算符。减号运算符既可用做一元运算符,也可用做二元运算符。

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

布尔值

拥有一个值,它能区分两种可能性,一般是有用的,例如“是”和“否”或“开”和“关”。 为此,JavaScript 拥有布尔(Boolean)类型,它有两个值:truefalse,它们就写成这些单词。

比较

一种产生布尔值的方法以下所示:

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

><符号分别表示“大于”和“小于”。这两个符号是二元运算符,经过该运算符返回的结果是一个布尔值,表示其运算是否为真。

咱们可使用相同的方法比较字符串。

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

字符串排序的方式大体是字典序,但不真正是你指望从字典中看到的那样:大写字母老是比小写字母“小”,因此"Z"<"A",非字母字符(!-等)也包含在排序中。 比较字符串时,JavaScript 从左向右遍历字符,逐个比较 Unicode 代码。

其余相似的运算符则包括>=(大于等于),<=(小于等于),==(等于)和!=(不等于)。

console.log("Apple" == "Orange")
// → false

在 JavaScript 中,只有一个值不等于其自身,那就是NaN(Not a Number,非数值)。

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

NaN用于表示非法运算的结果,正因如此,不一样的非法运算结果也不会相等。

逻辑运算符

还有一些运算符能够应用于布尔值上。JavaScript 支持三种逻辑运算符:与(and),或(or)和非(not)。这些运算符能够用于推理布尔值。

&&运算符表示逻辑与,该运算符是二元运算符,只有当赋给它的两个值均为true时其结果才是真。

console.log(true && false)
// → false
console.log(true && 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

这个被称为条件运算符(或者有时候只是三元运算符,由于它是该语言中惟一的这样的运算符)。 问号左侧的值“挑选”另外两个值中的一个。 当它为真,它选择中间的值,当它为假,则是右边的值。

空值

有两个特殊值,写成nullundefined,用于表示不存在有意义的值。 它们自己就是值,但它们没有任何信息。

在 JavaScript 语言中,有许多操做都会产生无心义的值(咱们会在后面的内容中看到实例),这些操做会获得undefined的结果仅仅只是由于每一个操做都必须产生一个值。

undefinednull之间的意义差别是 JavaScript 设计的一个意外,大多数时候它并不重要。 在你实际上不得不关注这些值的状况下,我建议将它们视为几乎可互换的。

自动类型转换

在引言中,我提到 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"(从数字到字符串)。

当某些不能明显映射为数字的东西(如"five"undefined)转换为数字时,你会获得值NaNNaN进一步的算术运算会产生NaN,因此若是你发现本身在一个意想不到的地方获得了它,须要寻找意外的类型转换。

当相同类型的值之间使用==符号进行比较时,其运算结果很好预测:除了NaN这种状况,只要两个值相同,则返回true。但若是类型不一样,JavaScript 则会使用一套复杂难懂的规则来肯定输出结果。在绝大多数状况下,JavaScript 只是将其中一个值转换成另外一个值的类型。但若是运算符两侧存在nullundefined,那么只有两侧均为nullundefined时结果才为true

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

这种行为一般颇有用。 当你想测试一个值是否具备真值而不是nullundefined时,你能够用==(或!=)运算符将它与null进行比较。

可是若是你想测试某些东西是否严格为“false”呢? 字符串和数字转换为布尔值的规则代表,0NaN和空字符串("")计为false,而其余全部值都计为true。 所以,像'0 == false'"" == false这样的表达式也是真的。 当你不但愿发生自动类型转换时,还有两个额外的运算符:===!==。 第一个测试是否严格等于另外一个值,第二个测试它是否不严格相等。 因此"" === false如预期那样是错误的。

我建议使用三字符比较运算符来防止意外类型转换的发生,避免做茧自缚。但若是比较运算符两侧的值类型是相同的,那么使用较短的运算符也没有问题。

逻辑运算符的短路特性

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

例如,当左侧值能够转换为true时,||运算符会返回它,不然返回右侧值。 当值为布尔值时,这具备预期的效果,而且对其余类型的值作相似的操做。

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

咱们能够此功能用做回落到默认值的方式。 若是你的一个值多是空的,你能够把||和备选值放在它以后。 若是初始值能够转换为false,那么你将获得备选值。

&&运算符工做方式与其类似但不相同。当左侧的值能够被转换成false时,&&运算符会返回左侧值,不然返回右侧值。

这两个运算符的另外一个重要特性是,只在必要时求解其右侧的部分。 在true || X的状况下,无论X是什么 - 即便它是一个执行某些恶意操做的程序片断,结果都是true,而且X永远不会求值。 false && X也是同样,它是false的,而且忽略X。 这称为短路求值。

条件运算符以相似的方式工做。 在第二个和第三个值中,只有被选中的值才会求值。

本章小结

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

经过输入值的名称(truenull)或值(13"abc")就能够建立它们。你还能够经过运算符来对值进行合并和转换操做。本章已经介绍了算术二元运算符(+*/%),字符串链接符(+),比较运算符(==!====!==<><=>=),逻辑运算符(&&||)和一些一元运算符(表示负数,!表示逻辑非,typeof用于查询值的类型)。

这为你提供了足够的信息,将 JavaScript 用做便携式计算器,但并很少。 下一章将开始将这些表达式绑定到基本程序中。

相关文章
相关标签/搜索