《深入理解ES6》——块级作用域绑定

一、var声明及变量提升(Hoisting)机制

    在函数作用域或全局作用域中通过关键字var声明的变量,无论实际上是在哪里声明的,都会被当成在当前作用域顶部声明的变量,这就是我们常说的提升(Hoisting)机制。下面以一个函数为例来说明:

function getValue(condition){
    if(condition){
      var value = "blue";
      //其他代码
      return value;
    }else{
      //此处可访问变量value,其值为undefined
      return null;
    }
   //此处可访问value,其值为undefined
}

    如果你不熟悉JavaScript,可能会认为只有当condition的值为true时才会创建变量value。事实上,无论如何变量value都会被创建。在预编译阶段,JavaScript引擎会将上面的getValue函数修改成下面这样:

function getValue(condition){
    var value;
    if(condition){
      value = "blue";
      //其他代码
      return value;
    }else{
      return null;
    }
}

    变量value的声明被提升至函数顶部,而初始化操作依然留在原处执行,这就意味着在else子句中也可以访问到该变量,且由于此时变量尚未初始化,所以其值为undefined。

二、块级声明

    块级声明用于声明在指定块的作用域之外无法访问的变量。块级作用域(也称为词法作用域)存在于:

  • 函数内部
  • 块中(字符{和}之间的区域)

let声明

    let声明的用法与var相同。用let代替var来声明变量,就可以把变量的作用域限制在当前代码块中。由于let声明不会被提升,因此开发者通常将let声明语句放在封闭代码块的顶部,以便整个代码块都可以访问。下面是let声明的实例:

function getValue(condition){
    if(condition){
      let value = "blue";
      //其他代码
      return value;
    }else{
      //变量value在此处不存在
      return null;
    }
   //变量value在此处不存在
}

禁止重声明

    假设作用域中已经存在某个标识符,此时再使用let关键字声明它就会抛出错误,举例来说:

var count = 30;

//抛出语法错误
let count = 40;

    但如果当前作用域内嵌另一个作用域,便可在内嵌的作用域中用let声明同名变量,如下:

var count = 30;
if(condition){
   //不会抛出错误
   let count = 40;
   //更多代码
}

    由于此处的let是在if块内声明了新变量count,因此不会抛出错误。内部块中的count会遮蔽全局作用域中的count,后者只有在if块外才能访问到。

const声明

    ES6标准还提供了const关键字。使用const声明的是变量,其值一旦被设定后不可更改。因此,每个通过const声明的常量必须进行初始化。如下:

//有效的常量
const maxItems = 30;
//语法错误,常量未初始化
const name;

const与let

    const与let声明的都是块级作用域,所以常量也只在当前代码块内有效,一旦执行到块外会立即被销毁。常量同样也不会被提升至作用域顶部,示例如下:

if(condition){
  const maxItems = 5;
  //更多代码
}
//此处无法访问maxItems

    在这段代码中,在if语句中声明了常量maxItems,语句执行一结束,maxItems即刻被销毁,在代码块外访问不到这个常量。

    与let相似,在同一作用域用const声明已经存在的标识符也会导致语法错误,无论该标识符是使用var(在全局或函数作用域中),还是let(在块级作用域中)声明的。

用const声明对象

    记住,const声明不允许修改绑定,但允许修改值。这也就意味着用const声明对象后,可以修改该对象的属性值。

 const person={
    name: "Nicholas"
};
//可以修改对象属性的值
person.name = "Gerg";
//抛出语法错误
person = {
    name: "Greg"
};

临时死区(Temporal Dead Zone)

    与var不同,let和const声明的变量不会被提升到作用域顶部,如果在声明之前访问这些变量,即使是相对安全的typeof操作符也会触发引用错误,如下:

if(condition){
   console.log(typeof value);//引用错误
   let value = "blue";
}

    由于console.log(typeof value)语句会抛出错误,因此用let定义并初始化变量value的语句不会执行。此时的value还位于JavaScript社区所谓的“临时死区”或TDZ中。但在let声明的作用域外对该变量使用typeof则不会报错,如下:

console.log(typeof value);//“undefined”
if(condition){
   let value = "blue";
}

    typeof是在声明变量value的代码块外执行的,此时value并不在TDZ中。这也就意味着不存在value这个绑定,typeof操作最终返回“undefined”。

 

 

你可能感兴趣的:(ES6)