ES6-1-块级绑定

var 变量提升

使用关键字 var 声明的变量 无论其实际位置在何处,都会被视为声明于在所在函数的顶部,如果不在函数顶部,则视为在全局作用域的顶部

例:

1
2
3
4
5
6
7
8
9
10
11
function getVal(condition){
if(condition) {
var value = 'a';
return value;
}else{
//此处也能访问到value,只是没有对其赋值
return null;
}
//此处也能访问到value,只是没有对其赋值
}
//var 声明的变量 声明被提升到函数或者全局作用域,但是初始化(赋值)保留在原处

块级声明 let const

让所声明的变量在指定的作用域外无法被访问。又被称为词法作用域
创建形式
1.在一个函数体内
2.在一个代码块(花括号)内部

let 声明

let 声明和 var 声明语法基本一致,只是 let 声明会将声明的变量的作用域定在当前代码块内,并且声明并不会提到作用域顶部,需要手动放置到顶部
区别

1
2
3
4
5
6
7
8
1.使用 let 声明前都是不能够访问到的,var 声明在作用内一开始就可能访问,只是他的值是 undefined 
2.var 声明变量,可重复声明,只是后面会覆盖前面的声明,
let如果在同一作用域内重复声明会报错。不在同一作用域内是可以重复声明的
```

#### cont 常量声明
const 声明的变量会被认为是常量,值被设置完之后就不能改变了。因为所有const声明需要在声明的时候就初始化(赋值)
注意

1.const声明无法重新赋值,只要重新赋值就会报错
2.使用const声明对象,const不会组织对变量成员的修改,因此修改const声明的对象中的属性,是可以的

1
2
3

#### 暂时性死区
例:

typeof value;//undefined
if(condition){
typeof value;//此处会报引用错误,不能在value声明前引用他
let value = 1;
}

1
2
3
4
js执行时遇到var变量声明会将变量提升到函数或者全局作用域顶部。而面对let或const声明时会将声明放在 '暂时性死区' 任何在暂时性死区访问变量的企图都会导致引用错误。只有执行到声明语句,才会将变量移除暂时性死区。
在代码块之外,因为未曾声明value,因此typeof可以正确返回undefined

#### 循环中的块级绑定

var funcs = [];
for(var i = 0;i < 10;i++){
funcs.push(function(){console.log(i)})
}
funcs.forEach(v=>{v()}) //输出10次10
//var定义的变量会导致提升到作用域顶部,因此之后也能访问到,
//并且i在循环中被共享了。循环结束后他们因此引用的一个变量i,因此都变成了10

//解决办法可以使用匿名函数,每次迭代的时候都创建变量的一个新副本
for(var i = 0;i < 10;i++){
funcs.push((function(value){return function(){console.log(value)}}(i)))
}
for(var i = 0;i < 10;i++){
funcs.push((function(value){return function(){console.log(value)}})(i))
}
//以上2中方式都是匿名函数写法
funcs.forEach(v=>{v()})//依次输出0-9

1
2
#### 循环内的let声明
let声明仿照上面匿名函数,每次执行都创建一个新的同名变量,因此不共享一个变量

var funcs = [];
for(let i = 0;i < 10;i++){
funcs.push(function(){console.log(i)});//i每次迭代都是一个新的变量
}
funcs.forEach(v=>{v()}) //依次输出0-9

1
2
3
4
5
6
let声明同样适用for-in for-of循环

let 声明在循环内部的行为是特别定义的。这是后来添加的

循环内的常量(const)声明
常规for循环中初始化可以使用const,但是不能企图修改它的值

for(const i = 0; i < 10;i++){//在迭代一次后执行i++时候因为会企图修改变量i的值,因此会报错

}
//在使用for-in for-of循环中与let效果一样,因为没有修改声明的值,每次迭代都是声明一个新的key

1
2
3
4

#### 全局块级绑定
当在全局作用域中使用var创建的全局变量,会成为全局对象window的一个属性。这会导致可能覆盖全局属性
例:

var RegExp = ‘hello’;
console.log(Regexp);//输出hello
window.RegExp === RegExp;//返回true

1
如果使用let或const来在全局作用域中创建变量,就不会导致全局对象被污染

let RegExp = ‘hello’;
window.RegExp === RegExp;//返回false
//let/const创建的变量并不会绑定到全局对象window成为window的属性
`
PS:如果想让代码能从window访问还是需要使用var。跨窗口访问也用的var

块级绑定的最佳实践

变量声明的方式使用let替代var,对受保护的变量使用const
默认使用const声明变量,只有知道变量需要修改再使用let