ES6新声明方式——let
let是ES6新的变量声明方式,相当于ES5中的var,那么相比于var,let又有什么新特性呢?今天就来聊聊let的特性。
1、let不属于顶层对象window
var声明的变量属于window对象,可以用 window.变量名 调用,但是let声明的变量不属于window对象。下面结合例子来说明一下:
var的例子
var a=5 //var定义该作用域内的全局变量
console.log(window.a)//5 (a是window的变量)
delete a//delete只能删除对象不能删除变量
console.log(a)//5 (a是window的变量不是对象,不能用delete删除)
这里补充另外一种情况是省略了var,赋值给未声明的变量,当执行时会隐式创建全局变量(成为window的对象)
b=6 //b成为window的对象
console.log(b)//6
console.log(window.b)//6
delete b
console.log(window.b)//打印失败 (b是window的对象,可以用delete删除)
接下来该说说let
let a=5
console.log(a)//5
console.log(window.a)//undefined (let声明的变量不属于window)
2、let不可以重复声明
这个很好理解,var可以重复声明变量
var a = 5
var a = 6
console.log(a) // 5
let不可以重复声明变量
let a = 5
let a = 6
// VM131:1 Uncaught SyntaxError: Identifier 'a' has already been declared
// at <anonymous>:1:1
3、let不存在变量提升
var 声明的变量会在任意代码执行前处理,这意味着在任意地方声明变量都等同于在作用域顶部声明——即声明提升(可以在声明语句之前使用)。
console.log(a)//undefine (打印出undefined而不是报错,可见var存在变量提升)
var a = 5
//相当于
// var a
// console.log(a)
// a=5
function foo(){
console.log(b)
var b=5
}
foo()//undefined
//相当于
//function foo(){
// var b
// console.log(b)
// b=5
//}
//foo()
let声明的变量不存在变量提升。
console.log(a)//报错
let a = 5
console.log(sum(2,3))//报错
let sum=function(x,y){
return x+y
}
let不存在变量提升的特性,符合ES6的规定的暂时性死区,可以防止变量在声明之前被使用。暂时性死区:
var a=5
if(true){
a=6
let a//会报错
}
//大括号{}内即为一个块作用域,作用域内let变量必须先声明才能赋值(使用)
更多关于变量提升建议阅读 (深入理解js中变量提升: https://github.com/creeperyang/blog/issues/16.)
4、块级作用域
常见的作用域分为以下几个类型:
对象 | 类型 |
---|---|
window/global | 全局作用域 |
function | 函数作用域/局部作用域 |
{} | 块状作用域 |
this | 动态作用域 |
更多关于作用域建议阅读(https://github.com/mqyqingfeng/Blog/issues/3)
块级作用域——对比var和let
例一:
//var没有块级作用域
for(var i=0;i<3;i++){
console.log("循环内:"+i)//0 1 2
}
console.log("循环外:"+i)//3
//let有块级作用域
for(let i=0;i<3;i++){
console.log("循环内:"+i)//0 1 2
}
console.log("循环外:"+i)//报错
例二:
//var没有块级作用域
if(false){
var a=5
}
console.log(a)//undefined
//a无块级作用域 a被声明但是取不到5
//let有块级作用域
if(false){
let a=5
}
console.log(a)//报错 a没有被声明
例三:
//var声明循环变量时出现的问题
for(var i=0;i<3;i++){
setTimeout(function(){
console.log(i)//3 3 3
})
}
//for循环是同步操作,会直接执行三次,有三个setTimeout函数,该函数是异步操作,不会直接执行,会等for循环(主线程)执行完时才统一执行
//此时可以用闭包函数解决
//闭包:内部函数引用外部函数的参数,使外部函数的参数不被释放(是ES5语法)
//(funtion(){})() 匿名函数格式
for(var i=0;i<3;i++){
(function(j){
setTimeout(function(){
console.log(j)//0 1 2
})
})(i)
}
//也可以用let解决
for(let i=0;i<3;i++){
setTimeout(function(){
console.log(i)//0 1 2
})
}
//经Babel编译后
var _loop = function _loop(i) {
setTimeout(function () {
console.log(i); //0 1 2
});
};
for (var i = 0; i < 3; i++) {
_loop(i);
}