JavaScript 红宝书笔记 - 第 3 章. 语言基础
严格模式
在脚本开头写下以下预处理指令即可开启。
1 | ; |
也可以指定一个函数在严格模式下执行,将该预处理指令放在函数体开头即可。
变量
var 声明
使用
var
操作符定义变量的时候,如果没有初始化将会保存一个特殊值undefined
。使用
var
定义的变量会成为包含它的函数的局部变量,函数退出时销毁。函数内定义变量时省略
var
操作符则可以创建一个全局变量。(但是不推荐,严格模式下将会抛出ReferenceError
)var
的声明提升(hoist):使用var
声明的变量会自动提升到函数作用域顶部(仅声明提升,赋值不会提升)。如下列两段代码等价。1
2
3
4
5function foo() {
console.log(age);
var age = 26;
}
foo(); // undefined1
2
3
4
5
6function foo() {
var age;
console.log(age);
age = 26;
}
foo(); // undefined反复使用
var
声明变量也没有问题。
let 声明
let
与var
的区别let
声明的范围是块作用域,而var
声明的范围是函数作用域。let
不允许同一块作用域中出现冗余声明(var
也一样),否则报错SyntaxError
。- 嵌套使用相同的标识符不会报错。
暂时性死区:在
let
声明之前的执行瞬间。此阶段引用任何后面才声明的变量都会抛出ReferenceError
。全局声明:使用
let
在全局作用域中声明的变量不会成为window
对象的属性(var
声明的变量则会)。let
无法使用条件声明,但是这是好的。for
循环中的let
声明
也就是说,
let
+ 超时的时候 JS 引擎回味每个循环迭代声明一个新的变量,而var
则不会。
const 声明
- 与
let
基本相同,唯一区别就是声明变量的时候也需要同时初始化变量,且尝试修改const
声明的变量会导致运行时错误。 - 但是
const
的限制只适用于它指向的变量的引用,如果引用的是一个对象,修改对象内部的属性是允许的。
关于声明风格
- 不使用
var
,提高代码质量.jpg - 优先使用
const
,更好查找 bug。
数据类型
6 种简单数据类型和 1 种复杂数据类型
Undefined
/ Null
/ Boolean
/ Number
/ String
/ Symbol
+ Object
typeof 操作符
- 用于确定任意变量的数据类型
- 除了 6 种简单数据类型之外,还可能返回
object
和function
- 函数也是一种对象,但是可以用
typeof
来区分。
Undefined 类型
- 只有一个值
Undefined
,声明了但未初始化的时候就相当于赋了该值。 - 与空对象指针
null
不同,但是表面相等(使用==
)。 - 需要注意,
typeof
对未声明和未初始化的变量都会返回undefined
。 - 是一个假值,检验时需要注意。
Null 类型
- 只有一个值
Null
,表示空对象指针。 - 建议定义将来要保存对象值的变量的时候,使用
null
初始化。 - 是一个假值,检验时需要注意。
Boolean 类型
- 可以使用
Boolean()
将其他值转换为布尔值。if
等流控制语句会自动执行其他类型值到布尔值的转换。
Number 类型
- 整数用八进制字面量表示的时候,第一个数字必须是 0,但是如果字面量超出了范围就会忽略前缀 0。同时,八进制在严格模式下是无效的(需要前缀
0o
)。 - 十六进制字面量则需要前缀
0x
。 - 对于浮点数,ECMAScript 总会想办法将值转换为整数。如
1.
、10.0
都会被转换。 - 科学记数法是允许的,如
3.125e7
。 - 不要测试浮点值,不要测试浮点值,不要测试浮点值。(由于 IEEE 754 数值的问题,会出现舍入错误以至于不能测试)
- 由于内存限制,Number 可以表示的数有限,超出则会变为
±Infinity
,此时不可以用于计算,确定一个值是否有限大可以用isFinite()
函数,若为真值则为有限大。 NaN
表示 “不是数值”,在0/0
、-0/+0
的情况下会出现。而在5/0
这种情况下会得到Infinity
。- 同时 NaN 不等于 NaN。
- 可以使用
isNaN()
来测试对象(但是不常见),其中false
表示可以转换为数值。
数值转换(转换到数字)
Number()
万能转换捏。- 对于对象调用
valueOf()
方法,如果结果是NaN
则调用toString()
方法并按照字符串转换的规则转换。
- 对于对象调用
parseInt()
只要第一个不是数值、加减号就会返回NaN
。- 空字符串也会返回
NaN
,而Number()
会返回 0。 "1234abc"
会返回 1234。- 向下舍入,因为小数点不是有效的整数字符。
- 不含前缀的十六进制字符串也可以被转换,但是需要传入 16 作为第二个参数(也就是可以按不同进制解析字符串)。
- 空字符串也会返回
parseFloat()
基本同上,只解析第一个小数点,同时只解析十进制。
String 类型
- 可以用单双反引号标示。
\'\"
和\反引号
可以在字符串中表达原意。- 字符串不可变,因此每次重定义都会重新创建与销毁。
转换到字符串
toString()
- 如果是
null
,则返回"null"
,如果是undefined
则返回"undefined"
。
- 如果是
值 + ""
也可以将其转换为字符串。
模板字面量
可以用反引号跨行定义字符串。如
1
2
3let myMultiLine = `first line
second line`;
console.log(myMultiLine[0] === 'first line'); // true使用模板字面量完成字符串插值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16let value = 5;
let exponent = 'second';
// 之前常用的版本
let chaString = value + 'rua' + exponent;
// 使用模板字面量的版本
let chaChaString = `${ value }rua${ exponent }`;
// 一些无需转义的存在
console.log(`Hello, ${ `World` }!`);
// 将表达式转为字符串会调用 toString()
let foo = { toString: () => 'World'};
console.log(`Hello, ${ foo }!`);
// 插值表达式中可以调用函数和方法
console.log(`${ capitalize('hello')}`);
// 也可以插入自己之前的值
let value = '';
value = `${value}abc`;模板字面量标签函数
1
// TODO: P42,暂时略过,有缘再看
可以使用
String.raw
标签函数获取原始模板字面量内容。1
2
3
4// 如
console.log(`a\nb`);
console.log(String.raw`a\nb`);
// 但是对实际的换行符就不行惹也可以通过标签函数的第一个参数获取原始内容。
1
2
3for (const rawString of strings.raw) {
console.log(rawString);
}
Symbol 类型
- 是 ES6 新增的数据类型。符号是原始值,且符号实例唯一不可变。
- 用途是确保对象属性使用唯一标识符,不会发生属性冲突的危险。
- 需要使用
Symbol()
函数初始化。 - 具有隐藏性,
for···in
,object.keys()
不能访问 - 全局注册并登记的方法:
Symbol.for()
1 | // TODO: P46 符号相关,可以重新深入阅读 |
Object 类型
- 对象!
操作符
1 | // TODO: 可以重新深入阅读 |
**指数操作符 ****
- 于 ES7 新增,相当于
Math.pow()
语句
for-in
语句:用于枚举对象中的非符号键属性。for-of
语句:用于遍历可迭代对象的元素,比如数组中的所有元素。会按照可迭代对象中的next()
方法产生值的顺序迭代元素。- 标签语句:可以与
continue
和break
使用用来返回代码中的特定位置,通常在嵌套循环中使用。 with
语句:类似于 Python 中的with
,但是严格模式中不允许使用with
语句,且影响性能难于调试代码,通常不推荐使用。
函数
第十章会更详细地介绍函数。
- 不指定返回值的函数实际上会返回特殊值
undefined
。