严格模式
对整个脚本开启严格模式,在脚本开头加上这一行 :
也可以加在函数体开头,使整个函数开启严格模式。
变量
var关键字
var可以定义一个变量,用来保存不同类型的值,且定义后,变量保存的值以及类型均可改变。
var message = "hi";
message = 100; // 合法,但不推荐
-
作用域
使用var在函数体内声明的变量为局部变量,但省略var可以创建全局变量 ( 但不推荐 ) 。
var可以同时声明 ( 以及初始化 ) 多个变量,使用逗号隔开即可。
-
声明提升
var会把所有变量声明都拉到函数作用域的顶部,此外,反复多次使用 var 声明同一个变量也没有问题。
let声明
与 var 类似,但 let 声明的范围是块作用域 ( 大括号分隔 ) , 而 var 声明的范围是函数作用域。
块作用域是函数作用域的子集。
let不允许同一个块作用域中出现冗余声明。
-
暂时性死区
let 声明的变量不会在作用域中被提升,在 let 声明之前的执行瞬间被称为“暂时性死区”(temporal dead zone)。
-
全局声明
使用 let 在全局作用域中声明的变量不会成为 window 对象的属性(var 声明的变量则会)。
-
条件声明
在使用 var 声明变量时,由于声明会被提升,JavaScript 引擎会自动将多余的声明在作用域顶部合并为一个声明。因为 let 的作用域是块,检查它的时候是在块作用域内,所以无法检查前面是否已经使用 let 声明过同名变量。
-
for 循环中的 let 声明
使用 var 关键字,for 循环定义的迭代变量会渗透到循环体外部 :
for (var i = 0; i < 5; ++i) {
// 循环逻辑
}
console.log(i); // 5
let定义的迭代变量的作用域仅限于 for 循环块内部 :
for (let i = 0; i < 5; ++i) {
// 循环逻辑
}
console.log(i); // ReferenceError: i 没有定义
var在for循环中:
for (var i = 0; i < 5; ++i) {
setTimeout(() => console.log(i), 0)
}
// 你可能以为会输出0、1、2、3、4
// 实际上会输出5、5、5、5、5
之所以会这样,是因为在退出循环时,迭代变量保存的是导致循环退出的值 : 5 。在之后执行超时逻辑时,所有的 i 都是同一个变量,因而输出的都是同一个最终值。
而在使用 let 声明迭代变量时,JavaScript 引擎在后台会为每个迭代循环声明一个新的迭代变量。 每个 setTimeout 引用的都是不同的变量实例:
for (let i = 0; i < 5; ++i) {
setTimeout(() => console.log(i), 0)
}
// 会输出0、1、2、3、4
这种每次迭代声明一个独立变量实例的行为适用于所有风格的 for 循环,包括 for-in 和 for-of 循环。
const声明
与 let 相同,const 的作用域也是块,且不允许重复声明。
const 声明变量时必须同时初始化变量,且尝试修改 const 声明的变量会导致运行时错误,这个限制只适用于它指向的变量的引用。如果 const 变量引用的是一个对象, 那么修改这个对象内部的属性并不违反 const 的限制:
const person = {};
person.name = 'Matt'; // ok
不能用 const 来声明迭代变量(因为迭代变量会自增)
for (const i = 0; i < 10; ++i) {} // TypeError:给常量赋值
但是可以用 const 声明一个不会被修改的 for 循环变量,每次迭代只是创建一个新变量。
let i = 0;
for (const j = 7; i < 5; ++i) {
console.log(j);
}
// 7, 7, 7, 7, 7
for (const key in {a: 1, b: 2}) {
console.log(key);
}
// a, b
for (const value of [1,2,3,4,5]) {
console.log(value);
}
// 1, 2, 3, 4, 5
最佳实践
- 不使用 var
- const 优先,let 次之
数据类型
ECMAScript 有 6 种简单数据类型(也称为原始类型) : Undefined、Null、Boolean、Number、String 和 Symbol;
复杂数据类型 : Object ( 对象 )。
typeof 操作符
typeof操作符的结果为以下字符串 : undefined,boolean,string,number,object,function,symbol。
调用 typeof null 返回的是"object"
Undefined类型
undefined表示未初始化变量。
对未声明的变量,只能执行一个有用的操作,就是对它调用 typeof。(也可以调用delete,但没意义)
对于未初始化及未声明化的变量调用typeof时,返回结果均为"undifined"。
Null类型
null值表示一个空对象指针,所以调用typeof返回值为"object"。
在定义将来要保存对象值的变量时,使用 null 来初始化,方便后续判断是否变量被指向一个新的引用。
console.log(null == undefined); // true
Boolean类型
所有其他 ECMAScript 类型的值都有相应布尔值的等价形式,调用Boolean()函数即可:

严格模式
对整个脚本开启严格模式,在脚本开头加上这一行 :
也可以加在函数体开头,使整个函数开启严格模式。
变量
var关键字
var可以定义一个变量,用来保存不同类型的值,且定义后,变量保存的值以及类型均可改变。
作用域
使用var在函数体内声明的变量为局部变量,但省略var可以创建全局变量 ( 但不推荐 ) 。
var可以同时声明 ( 以及初始化 ) 多个变量,使用逗号隔开即可。
声明提升
var会把所有变量声明都拉到函数作用域的顶部,此外,反复多次使用 var 声明同一个变量也没有问题。
let声明
与 var 类似,但 let 声明的范围是块作用域 ( 大括号分隔 ) , 而 var 声明的范围是函数作用域。
块作用域是函数作用域的子集。
let不允许同一个块作用域中出现冗余声明。
暂时性死区
let 声明的变量不会在作用域中被提升,在 let 声明之前的执行瞬间被称为“暂时性死区”(temporal dead zone)。
全局声明
使用 let 在全局作用域中声明的变量不会成为 window 对象的属性(var 声明的变量则会)。
条件声明
在使用 var 声明变量时,由于声明会被提升,JavaScript 引擎会自动将多余的声明在作用域顶部合并为一个声明。因为 let 的作用域是块,检查它的时候是在块作用域内,所以无法检查前面是否已经使用 let 声明过同名变量。
for 循环中的 let 声明
使用 var 关键字,for 循环定义的迭代变量会渗透到循环体外部 :
let定义的迭代变量的作用域仅限于 for 循环块内部 :
var在for循环中:
之所以会这样,是因为在退出循环时,迭代变量保存的是导致循环退出的值 : 5 。在之后执行超时逻辑时,所有的 i 都是同一个变量,因而输出的都是同一个最终值。
而在使用 let 声明迭代变量时,JavaScript 引擎在后台会为每个迭代循环声明一个新的迭代变量。 每个 setTimeout 引用的都是不同的变量实例:
这种每次迭代声明一个独立变量实例的行为适用于所有风格的 for 循环,包括 for-in 和 for-of 循环。
const声明
与 let 相同,const 的作用域也是块,且不允许重复声明。
const 声明变量时必须同时初始化变量,且尝试修改 const 声明的变量会导致运行时错误,这个限制只适用于它指向的变量的引用。如果 const 变量引用的是一个对象, 那么修改这个对象内部的属性并不违反 const 的限制:
不能用 const 来声明迭代变量(因为迭代变量会自增)
但是可以用 const 声明一个不会被修改的 for 循环变量,每次迭代只是创建一个新变量。
最佳实践
数据类型
ECMAScript 有 6 种简单数据类型(也称为原始类型) :
Undefined、Null、Boolean、Number、String 和 Symbol;复杂数据类型 : Object ( 对象 )。
typeof 操作符
typeof操作符的结果为以下字符串 :
undefined,boolean,string,number,object,function,symbol。调用 typeof null 返回的是"object"
Undefined类型
undefined表示未初始化变量。
对未声明的变量,只能执行一个有用的操作,就是对它调用 typeof。(也可以调用delete,但没意义)
对于未初始化及未声明化的变量调用typeof时,返回结果均为
"undifined"。Null类型
null值表示一个空对象指针,所以调用typeof返回值为
"object"。在定义将来要保存对象值的变量时,使用 null 来初始化,方便后续判断是否变量被指向一个新的引用。
Boolean类型
所有其他 ECMAScript 类型的值都有相应布尔值的等价形式,调用Boolean()函数即可: