ES6学习笔记(1):块级作用域绑定
1、var
声明及变量提升(Hoisting)机制
- 用
var
声明的变量会被当成在当前作用域(函数作用域或全局作用域)顶部声明的变量。
例子:
function getValue(condition){
if(condition){
var value = 'blue';
return value;
}else{
return null;
}
}
在预编译阶段,JavaScript引擎会把上面的函数修改如下:
function getValue(condition){
var value;
if(condition){
value = 'blue';
return value;
}else{
return null;
}
}
其中value
在函数开头就被声明,但没有初始化。所以在!condition
条件下,value
的值为undefined
。
2、块级声明
- JavaScript是没有块级作用域的。
- ES6引入块级作用域来强化对变量生命周期的控制。
- 块级作用域(词法作用域)存在于:
- 函数内部
- 块中(花括号{}之间的区域)
i)let
声明
let
声明不会被提升
例子:
function getValue(condition){
if(condition){
let value = 'blue';
return value;
}else{
return null;
}
}
在!condition
条件下,变量value
是不存在的。
ii)禁止重声明
- 在同一作用域中不能用
let
重复定义已经存在的变量
var count = 30;
let count = 40;
抛出语法错误。
- 在不同作用域中是可以用
let
重复声明的,但是内部块的变量会遮蔽外部块的变量
var count = 30;
if(condition){
let count = 40;
console.log(count);//40
}
console.log(count);//30
iii)const
声明
const
与let
不同之处:
- 声明同时必须初始化
- 不可以为
const
定义的常量再赋值 - 用
const
声明对象时,不可以修改绑定,但是可以修改对象的值
举例:
const person = {
name : "damian"
}
person.name = "logo";//允许修改对象的属性值
person = {//抛出语法错误
name : "logo"
}
iv) 临时死区(Temporal Dead Zone)
- JavaScript在发现变量声明时,要么提升至作用域顶部(如
var
),要么放入TDZ中(如let
、const
)。在TDZ中变量未声明之前访问该变量,会报错。即使是使用typeof
操作符也会报错。
if(condition){
console.log(typeof value);
let value = "blue";//引用错误
}
console.log(typeof value);//undefined
if(condition){
let value = "blue";
}
3、循环中的块作用域绑定
for (let i = 0;i < 10;i++){
process(item[i]);
}
console.log(i);//i不可访问
let
使得for
循环中的变量表现得和拥有块级作用域的语言(如C++)一样。
循环中的函数
- 举例:我们想要输出1~10
var funcs = [];
for(var i=0;i<10;i++){
funcs.push(function(){
console.log(i);
});
}
funcs.forEach(function(func){
func(); //输出10次数字10
});
显然不是我们想要的结果。原因循环内部创建的函数全部保留了对相同变量i
的引用,循环结束后i
的值为10。
- 使用立即调用函数表达式(IIFE)的解决办法
var funcs = [];
for(var i=0;i<10;i++){
funcs.push((function(value){
return function(){
console.log(value);
}
}(i)));
}
funcs.forEach(function(func){
func(); //0、1、2、3...9
});
在循环内部,为每一个i
都创建一个副本并保存为变量value
;
循环中的let
声明
var funcs = [];
for(let i=0;i<10;i++){
funcs.push(function(){
console.log(i);
});
}
funcs.forEach(function(func){
func(); //0、1、2...9
let
模仿通过IIFE的行为,得到我们想要的结果。
并且,对于for-in
和for-of
循环,let
也是适用的。
循环中的const
声明
const
声明常量,是不可变的,所以for(const i=0;;i++)
这种语句试图修改常量,会报错。for-in
和for-of
循环中可以使用const
,因为每次迭代不会修改已有的绑定,而是创建一个新绑定