欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

ES6初探-let与块级作用域

程序员文章站 2022-06-13 15:50:17
...


很久没有写博客,日子一天天过得很快,觉得有时候写点东西会让人沉静下来边思考边整理,一直纠结let是个什么东西,看了些面试题好多都关于这个的,今天终觉恍然大悟啊,然后整个人就开心起来了,终究学习还是使人快乐啊!

    进入正题吧~~

首先我们说一下块级作用域的定义:任何一对花括号({和})中的语句集都属于一个块,在这之中定义的所有变量在代码块外都是不可见的,我们称之为块级作用域。

/*利用匿名函数表达式可以模拟出块级作用域*/  
    (function (){  
        var i = 100;  
        console.log("block:" + i);  
    })();  
  

   除此之外我们可以用let来实现块级作用域。

  ES6 新增了let命令,用来声明变量。它的用法类似于var,但是所声明的变量,只在let命令所在的代码块内有效。


没有块级作用域会带来什么样的麻烦呢?

1.由于ES5只有全局作用域和函数作用域,没有块级作用域,会带来很多问题,比如说向下面的例子,内层变量可能会覆盖外层变量。


var tmp = new Date();

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

f(); // undefined

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


2.用来计数的循环变量泄露为全局变量。

var s = 'hello';

for (var i = 0; i < s.length; i++) {
  console.log(s[i]);
}

console.log(i); // 5
上面代码中,变量i只用来控制循环,但是循环结束后,它并没有消失,泄露成了全局变量。


let实现块级作用域例子:

function f1() {
  let n = 5;
  if (true) {
    let n = 10;
  }
  console.log(n); // 5
}
上面的函数有两个代码块,都声明了变量n,运行后输出5。这表示外层代码块不受内层代码块的影响。如果使用var定义变量n,最后输出的值就是10。


let声明变量的特点:

     1.var命令会发生”变量提升“现象,即变量可以在声明之前使用,值为undefined。这种现象多多少少是有些奇怪的,按照一般的逻辑,变量应该在声明语句之后才可以使用。

为了纠正这种现象,let命令改变了语法行为,它所声明的变量一定要在声明后使用,否则报错。

    

// var 的情况
console.log(foo); // 输出undefined
var foo = 2;

// let 的情况
console.log(bar); // 报错ReferenceError
let bar = 2;


     2.只要块级作用域内存在let命令,它所声明的变量就“绑定”(binding)这个区域,不再受外部的影响。

var tmp = 123;

if (true) {
  tmp = 'abc'; // ReferenceError
  let tmp;
}

       上面代码中,存在全局变量tmp,但是块级作用域内let又声明了一个局部变量tmp,导致后者绑定这个块级作用域,所以在let声明变量前,对tmp赋值会报错。

ES6明确规定,如果区块中存在letconst命令,这个区块对这些命令声明的变量,从一开始就形成了封闭作用域。凡是在声明之前就使用这些变量,就会报错。

总之,在代码块内,使用let命令声明变量之前,该变量都是不可用的。这在语法上,称为“暂时性死区”(temporal dead zone,简称 TDZ)。


      3.let不允许在相同作用域内,重复声明同一个变量。

 

/ 报错
function () {
  let a = 10;
  var a = 1;
}

// 报错
function () {
  let a = 10;
  let a = 1;
}

以上是学习自阮一峰老师的ECMAScript 6入门,我觉得介绍得非常清楚,适合对初学ECMAScript 6的孩子们。网址:http://es6.ruanyifeng.com/