ES6中的let,const和块级作用域

269 阅读2分钟

1.let和const不存在变量提升,并会导致暂时性死区

什么是变量提升?

es5之前的var 变量提升情况:

console.log(foo); //undefined

var foo=2;

let之后

console.log(foo); //ReferenceError

let foo=2;

什么是暂时性死区? 在代码块内,使用let命令声明变量之前,该变量都是不可用的,语法上成为暂时性死区(temporal dead zone)

{
tmp='abc' //ReferenceError
console.log(tmp) //ReferenceError

let tmp;
console.log(tmp) //undefined

tmp=123;
console.log(tmp) //123
}

暂时性死区的本质是:只要进入当前作用域,要使用的变量已经存在,但是不可获取,只有等声明变量的那一行代码出现,才可以获取和使用该变量。

2.块级作用域解决变量提升问题

var test=aaa;
function f(){
    console.log(test)
    if(false){
        var test = '111'
    }
}
f() //undefined
变量提升导致了内层的test变量覆盖了外层的test变量

另一个常见的就是for循环的i

var s='hiabu'
for(var i=0;i<s.length;i++){
    ...
}
console.log(i) //5
i只控制循环,但循环结束后,它并没有消失,而是泄露成了全局变量

块级作用域下:

let n=5;
{
    let n=10;
}
console.log(n) //5

3.块级作用域与函数声明 ES6中规定: *允许块级作用域内声明函数 *函数声明类似于var 会提升到全局作用域或函数作用域的头部 *函数声明还会提升到所在的块级作用域头部

function f(){console.log('i am out')}
(function(){
    if(false){
        function f(){console.log('i am in')}
    }
    f(); //f is not a function
}())

--如果确实需要声明 应使用函数表达式的形式,而非函数语句--

let f =function(){} //表达式
function f(){}  //语句

另外,块级作用域不含返回值,如果需要返回值可以借助do表达式

let x=do{
    let t =f();
    t*t+1;
}

4.const 只声明不赋值会报错

const foo;//会报错

const保证值不得改变,实际上是变量指向的内存地址不得改动,对于简单的数据,值就保存在变量指向的内存地址中,因此等同于常量。而复合类型的数据,变量指向的内存地址保存的是一个指针,const只能保证这个指针是固定的

const a =[];
a.push('hi'); //可执行
a.length=0; //可执行
a=['aaa'] //会报错

如果想要冻结对象,可以使用 Object.freeze方法 将对象彻底冻结的函数如下:

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

5.顶层对象 ES6开始,全局变量于顶层对象属性相隔离

var a=1;
window.a  //1

let b=1;
window.b  //undefined

获取顶层对象方法

var getGlobal=function(){
    if(typeof self !=='undefined'){return self;}
    if(typeof window !=='undefined'){return window;}
    if(typeof global !=='undefined'){return global;}
    throw new Error('unable to locate global object')
}