声明命令


块级作用域

ES5 只有全局作用域和函数作用域(例如,我们必须将代码包在函数内来限制作用域),这导致很多问题:
1、内层变量覆盖外层变量。2、变量泄露,成为全局变量。3、不再需要立即执行的函数表达式。4、循环体中的闭包不再有问题。

var

用 var 定义的全部变量,有时候会污染整个 js 的作用域。

1
2
3
4
{
var a = 1;
}
console.log(a); // 因为 var 是全局声明的,所以,即使是在区块里声明,但仍然在全局起作用。

let

let使js有块作用域,且变量不提升
1
2
3
4
5
6
7
8
9
{
let a = '1'
b = '2'
var b
console.log(c) // referenceError: c is not defined
let c = '3'
}
console.log(a) // referenceError: a is not defined.引用报错
console.log(b) // 2
经典案例
1
2
3
4
5
6
7
8
9
10
var a = []
for(var i = 0; i < 6; i++) {
a[i] = function () {
console.log(i)
}
}
i = 10
a[4]() // 10
a[5]() // 10
// 理由:i是全局变量,每次遍历i都会增加,到最后调用函数的时候i已经为6了
解决方案

给函数体里唯一的变量,这样就不会受外界的影响了

1
2
3
4
5
6
7
8
var a = []
for(let i = 0; i < 6; i++) {
a[i] = function () {
console.log(i)
}
}
a[4]() // 4
a[5]() // 5

for循环里有2个作用域

设置循环变量的那部分是一个父作用域,而循环体内部是一个单独的子作用域

1
2
3
4
5
6
7
for (let i = 0; i < 3; i++) {
let i = 'abc';
console.log(i);
}
// abc
// abc
// abc

暂时性死区

Es6规定:在块作用域内存在let和const时,凡是在声明前使用这些变量,就会报错

1
2
3
4
5
6
7
8
9
var tmp = 123;

if (true) {
tmp = 'abc'; // ReferenceError
typeof tmp
let tmp;
console.log(tmp) // 'undefined'
typeof tmp // 'undefined'
}

const

const定义的时候就必须赋值,且只保证变量的内存地址不变,所以只要变量的内存地址不变,还是可以改变变量的属性。将对象进行冻结

1
2
3
4
5
6
7
8
9
10
11
const foo = Object.freeze({});
foo.prop = 123; // 报错

var constantize = (obj) => {
Object.freeze(obj);
Object.keys(obj).forEach( (key, i) => {
if ( typeof obj[key] === 'object' ) {
constantize( obj[key] );
}
});
};

es6一共有几种声明变量

全局变量:window,指的是浏览器窗口对象
顶级变量:没有实质意义,也是window

1
2
var, function // 定义了会变成顶级变量和全局变量, window.a // 正确
let, const, import, class // 不会变成顶级变量和全局变量 window.a // 报错