ES6语法:let作用域

1.历史

ES6全程ECMAScript 6,参考书籍:ECMAScript 6入门 作者:阮一峰

在有js基础上,更好的理解ES6.

1996年11月,Netscape公司创造了Javascript,次年,被国际标准化组织(ECMA)定为国际标准。

该标准针对JavaScript,为避免版权冲突,这个标准被命名为ECMAScript,简称ES.

随着版本更替,2015年的ES2015做出了大幅度的改变,开始制定ES6规则,象征着新标准的改变,此后,ES6不仅仅表示了2015年的ES2015标准,也代表了“下一代JavaScript语言”。

2.配置

1)Babel转码器

Babel可以将ES6代码转化为ES5代码,从而支持老版本浏览器的执行。

例如:ES6标准写法:input.map(item => item + 1);通过Bable转码后:input.map(function (item) {  return item + 1; });

上述 => 的写法就是ES6写法,代替了函数返回。

2)polyfill

Babel默认只转换新的JS语法,而不转换新的API。比如ES6中新的API:Set,Map,Proxy,Aymbol等全局对象。需要安装core-jsregenerator-runtime为当前环境提供一个垫片。

但是需要注意一点,网页实时将ES6转换为ES5对性能会有影响。因此,生产环境需要加载已经转完码的脚本。

3.新语法

1)let命令

ES6新增的let命令类似于var,区别的是,var是全局变量,一处定义,全局有效。但let的语法只在代码块,作用域内有效,而且,只能先定义后使用。对于同一变量,let不允许重复定义,但var却可以。例如:

{

let a = 10;

var b = 10;

 

}

alert(a); //错误,a只能在上面{}的作用域内有效

alert(b); //正确,var全局有效

 

例如2:

{

alert(a); //错误,a是下面的let定义的变量,let定义的变量只能在他后面使用,在定义前使用是错误的,在这定义前的区域称为死区。

alert(b); //正确,var全局有效,不分定义先后顺序。这种不分顺序的原因其实是种“变量提升”现象,即变量可以在声明之前使用。
let a = 10;

var b = 10; 

}

 

那么,为什么要有let这个语法呢,var多方便啊,随便用的。正因随便二字使得var没有规范,可能使用的变量不知道在哪里已经定义过了,我们因该遵循哪里要用,那里定义,别处不能使用的原则,例如:

for循环中,使用let就很合适

for( let i = 0; i < 10; i ++){ console.log(i); }

 

这里很明显,我定义的i变量只希望用在for循环里面,除了for循环我用不到,也不希望别人误用,let定义的变量就比var好多了。

 2)块级作用域

其实在上述中已经有提到块级作用域了{},块级作用域就是为了避免一处定义全局可用的现象,我明明只希望在for循环中使用这个变量,结果for循环外你也能使用了,这不是泄露了我的变量了吗,再说,如果我定义完了变量,你在后面又重复定义了我的变量,这不是改变了我的变量了吗,这不乱套了。比如:

var tmp = new Date();

function f() {
  console.log(tmp);
  if (false) {
    var tmp = 'hello world';
  }
}

f(); // undefined

上面代码的原意是,if代码块的外部使用外层的tmp变量,内部使用内层的tmp变量。但是,函数f执行后,输出结果为undefined,原因在于变量提升,导致内层的tmp变量覆盖了外层的tmp变量。

块级作用域的用法:

function f1() {
  let n = 5;
  if (true) {
    let n = 10;
  }
  console.log(n); // 5
}

上面的函数有两个代码块,都声明了变量n,运行后输出 5。这表示外层代码块不受内层代码块的影响。如果两次都使用var定义变量n,最后输出的值才是 10。

上面是变量的作用域,函数也是一样的,但这里有一个很大的不同:

function f() { console.log('I am outside!'); }

(function () {
  if (false) {
    // 重复声明一次函数f
    function f() { console.log('I am inside!'); }
  }

  f();
}());

上面代码在 ES5 中运行,会得到“I am inside!”,因为在if内声明的函数f会被提升到函数头部。

ES6 就完全不一样了,理论上会得到“I am outside!”。因为块级作用域内声明的函数类似于let,对作用域之外没有影响。但是,如果你真的在 ES6 浏览器中运行一下上面的代码,是会报错的。

原来,如果改变了块级作用域内声明的函数的处理规则,显然会对老代码产生很大影响。为了减轻因此产生的不兼容问题,ES6 在附录 B里面规定,浏览器的实现可以不遵守上面的规定,有自己的行为方式:

  • 允许在块级作用域内声明函数。
  • 函数声明类似于var,即会提升到全局作用域或函数作用域的头部。
  • 同时,函数声明还会提升到所在的块级作用域的头部。

因此,考虑到环境导致的行为差异太大,应该避免在块级作用域内声明函数。如果确实需要,也应该写成函数表达式,而不是函数声明语句。

// 块级作用域内部的函数声明语句,建议不要使用
{
  let a = 'secret';
  function f() {
    return a;
  }
}

// 块级作用域内部,优先使用函数表达式
{
  let a = 'secret';
  let f = function () {
    return a;
  };
}

另外需要注意的是,ES6使用{}表示块级作用域的,如果没有{}会认为不存在块级作用域,这时使用let会报错,因为找不到作用域。

posted @ 2021-04-13 14:24  lv99  阅读(831)  评论(0编辑  收藏  举报