第一部分 JavaScript 编程语言
JavaScript 基础知识
2.5 数据类型
JavaScript 中有八种基本的数据类型(译注:前七种为基本数据类型,也称为原始数据类型,而 object 为复杂数据类型)。
- 七种原始数据类型:
number用于任何类型的数字:整数或浮点数,在±(253-1)范围内的整数。bigint用于任意长度的整数。string用于字符串:一个字符串可以包含 0 个或多个字符,所以没有单独的单字符类型。boolean用于true和false。null用于未知的值 —— 只有一个null值的独立类型。undefined用于未定义的值 —— 只有一个undefined值的独立类型。symbol用于唯一的标识符。
- 以及一种非原始数据类型:
object用于更复杂的数据结构。
2.7 类型转换
| 值 | 变成… |
|---|---|
undefined |
NaN |
null |
0 |
true 和 false |
1 and 0 |
string |
去掉首尾空白字符(空格、换行符 \n、制表符 \t 等)后的纯数字字符串中含有的数字。如果剩余字符串为空,则转换结果为 0。否则,将会从剩余字符串中“读取”数字。当类型转换出现 error 时返回 NaN。 |
| 值 | 变成… |
|---|---|
直观上为“空”的值:0, null, undefined, NaN, "" |
false |
| 其他值 | true |
有三种常用的类型转换:转换为 string 类型、转换为 number 类型和转换为 boolean 类型。
- 字符串也可显示转换:
String(value) - 数字型也可显示转换:
Number(value) - 布尔型也可显示转换:
Boolean(value)
上述的大多数规则都容易理解和记忆。人们通常会犯错误的值得注意的例子有以下几个:
- 对
undefined进行数字型转换时,输出结果为NaN,而非0。 - 对
"0"和只有空格的字符串(比如:" ")进行布尔型转换时,输出结果为true。
2.9 值的比较
比较运算符始终返回布尔值。
字符串的比较,会按照“词典”顺序逐字符地比较大小。
当对不同类型的值进行比较时,它们会先被转化为数字(不包括严格相等检查(
===))再进行比较。在非严格相等
==下,null和undefined相等且各自不等于任何其他的值。1
2
3
4
5// 当使用 null 或 undefined 与其他值进行比较时,其返回结果常常出乎你的意料。
alert( null == undefined ); // true。JavaScript 存在一个特殊的规则,会判定它们相等。它们俩就像“一对恋人”,仅仅等于对方而不等于其他任何的值(只在非严格相等下成立)。
alert( null === undefined ); // false。它们不相等,因为它们属于不同的类型。在使用
>或<进行比较时,需要注意变量可能为null/undefined的情况。比较好的方法是单独检查变量是否等于null/undefined。
🤣
2.11 逻辑运算符
或运算寻找第一个真值
上文提到的逻辑处理多少有些传统了。下面让我们看看 JavaScript 的“附加”特性。
拓展的算法如下所示。
给定多个参与或运算的值:
1 | result = value1 || value2 || value3; |
或运算符 || 做了如下的事情:
- 从左到右依次计算操作数。
- 处理每一个操作数时,都将其转化为布尔值。如果结果是
true,就停止计算,返回这个操作数的初始值。 - 如果所有的操作数都被计算过(也就是,转换结果都是
false),则返回最后一个操作数。
返回的值是操作数的初始形式,不会做布尔转换。
换句话说,一个或运算 || 的链,将返回第一个真值,如果不存在真值,就返回该链的最后一个值。
与运算寻找第一个假值
给出多个参加与运算的值:
1 | result = value1 && value2 && value3; |
与运算 && 做了如下的事:
- 从左到右依次计算操作数。
- 在处理每一个操作数时,都将其转化为布尔值。如果结果是
false,就停止计算,并返回这个操作数的初始值。 - 如果所有的操作数都被计算过(例如都是真值),则返回最后一个操作数。
换句话说,与运算返回第一个假值,如果没有假值就返回最后一个值。
上面的规则和或运算很像。区别就是与运算返回第一个假值,而或运算返回第一个真值。
2.12 空值合并运算符 ‘??’
空值合并运算符(nullish coalescing operator)的写法为两个问号 ??。
由于它对待 null 和 undefined 的方式类似,所以在本文中我们将使用一个特殊的术语对其进行表示。为简洁起见,当一个值既不是 null 也不是 undefined 时,我们将其称为“已定义的(defined)”。
a ?? b 的结果是:
- 如果
a是已定义的,则结果为a, - 如果
a不是已定义的,则结果为b。
换句话说,如果第一个参数不是 null/undefined,则 ?? 返回第一个参数。否则,返回第二个参数。
空值合并运算符并不是什么全新的东西。它只是一种获得两者中的第一个“已定义的”值的不错的语法。
2.14 “switch” 语句
强调一下,这里的相等是严格相等(===)。被比较的值必须是相同的类型才能进行匹配。
比如,我们来看下面的代码:
1 | let arg = prompt("Enter a value?") |
- 在
prompt对话框输入0、1,第一个alert弹出。 - 输入
2,第二个alert弹出。 - 但是输入
3,因为prompt的结果是字符串类型的"3",不严格相等===于数字类型的3,所以case 3不会执行!因此case 3部分是一段无效代码。所以会执行default分支。
Object(对象):基础知识
4.2 对象引用和复制
对象与原始类型的根本区别之一是,对象是“通过引用”存储和复制的,而原始类型:字符串、数字、布尔值等 —— 总是“作为一个整体”复制。
克隆与合并,Object.assign
那么,拷贝一个对象变量会又创建一个对相同对象的引用。
但是,如果我们想要复制一个对象,那该怎么做呢?
我们也可以使用 Object.assign 方法来达成同样的效果。
语法是:
1 | Object.assign(dest, [src1, src2, src3...]) |
- 第一个参数
dest是指目标对象。 - 更后面的参数
src1, ..., srcN(可按需传递多个参数)是源对象。 - 该方法将所有源对象的属性拷贝到目标对象
dest中。换句话说,从第二个开始的所有参数的属性都被拷贝到第一个参数的对象中。 - 调用结果返回
dest。
Object.assign()只拷贝了一层,并不是深拷贝。
我们可以使用递归来实现深拷贝。或者为了不重复造轮子,采用现有的实现,例如 lodash 库的 _.cloneDeep(obj)。
