ES6(一):let和const

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/caomage/article/details/83586048

ES6(一):let和const

一、let

1. let基本用法

  相当于var,但是又与var不同,因为let声明的变量只能在let所在的代码块中有效。
  从以下两段代码以及对应的输出结果可以很明显的看出var与let的区别。
code:

for (var i = 0; i < 5; i++) {
    console.log(i);
}
console.log(i);

result:

0
1
2
3
4
5

code:

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

result:

0
1
2
3
4
ReferenceError: i is not defined

2. 块级作用域

  众所周知,在ES5中只有全局作用域和函数作用域,没有我们所谓的块级作用域。
  这不禁让我想起一个面试题:
code:

for (var i = 0; i < 5; i++) {
    setTimeout(function() {
        console.log(new Date, i);
    }, 1000);
}

console.log(new Date, i);

  问:上面这段代码输出的结果是什么?
  仔细琢磨一下我们很容易得出正确的答案:

result:

2018-10-31T06:55:30.020Z 5
2018-10-31T06:55:31.021Z 5
2018-10-31T06:55:31.021Z 5
2018-10-31T06:55:31.022Z 5
2018-10-31T06:55:31.022Z 5
2018-10-31T06:55:31.022Z 5

  仔细看一下发现:由于setTimeout会被JavaScript延迟执行,因此是先输出最底部的console.log,隔一秒之后再执行循环里面的consol.log,此时i已经全部是5。
  那我们怎么样才能使输出结果变成想要的0,1,2,3,4呢?
  明白了let的原理之后其实问题变得很简单:
code:

for (let i = 0; i < 5; i++) {
    setTimeout(function() {
        console.log(new Date, i);
    }, 1000);
}

console.log(new Date, i);

  这样就行了吗?
result:

ReferenceError: i is not defined

  哈哈,刚刚还说过let只在所在的代码块里面有效,这里最外层的console.log很明显找不到i,所以报出引用错误。想要得到正确答案其实还需要去掉最后一行console.log。
  当然这个题目要搁以前的话,首先想到的解决方案应该是IIFE(Immediately Invoked Function Expression:声明即执行的函数表达式)来解决闭包造成的问题。
code:

for (var i = 0; i < 5; i++) {
    (function(j) {  
        setTimeout(function() {
            console.log(new Date, j);
        }, 1000);
    })(i);
}

console.log(new Date, i);

result:

2018-10-31T07:17:45.825Z 5
2018-10-31T07:17:46.827Z 0
2018-10-31T07:17:46.827Z 1
2018-10-31T07:17:46.827Z 2
2018-10-31T07:17:46.827Z 3
2018-10-31T07:17:46.827Z 4

  由此我们是不是就可以得出一个结论,有了let,我们就可以抛弃IIFE了?
  这个暂时还不好说,我们还是继续看看let的其他特性。

3. 没有变量提升

  var命令会产生变量提升的现象,这使得js这门语言变得并不严谨,这一点是特点也是鸡肋。用var声明的变量,如果我们在声明之前使用,则它的值为undefined。
  而当我们用let定义变量时,就必须严格按照先定义再使用的原则了,反之则会抛出一个大大的引用错误(ReferenceError),显然这更符合人们的使用习惯。
code:

console.log(a);
var a = 2;

console.log(b);
let b = 2;

result:

undefined
ReferenceError: b is not defined

4. 暂时性死区及不能重复声明

  ES6 明确规定,如果区块中存在let和const命令,这个区块对这些命令声明的变量,从一开始就形成了封闭作用域。凡是在声明之前就使用这些变量,就会报错。
  总之,在代码块内,使用let命令声明变量之前,该变量都是不可用的。这在语法上,称为“暂时性死区”(temporal dead zone,简称 TDZ)。
  “暂时性死区”也意味着typeof不再是一个百分之百安全的操作。
  let不允许在相同作用域内,重复声明同一个变量。

二、const

1. const基本用法

  const命令是声明一个常量,用法和let一样。

  • 和let的相同之处是:
    • const与let作用域相同,都是只在声明的代码块中起作用
    • const也不会提升所声明的常量
    • const也不能重复声明
  • 不同之处是const声明的常量在声明时就必须赋值,因为一旦声明就不能改变改常量的值

2. 真的不能改变吗?

  const实际上保证的,并不是变量的值不得改动,而是变量指向的那个内存地址所保存的数据不得改动。对于简单类型的数据(数值、字符串、布尔值),值就保存在变量指向的那个内存地址,因此等同于常量。但对于复合类型的数据(主要是对象和数组),变量指向的内存地址,保存的只是一个指向实际数据的指针,const只能保证这个指针是固定的(即总是指向另一个固定的地址),至于它指向的数据结构是不是可变的,就完全不能控制了。因此,将一个对象声明为常量必须非常小心。
code&result:

const a=1;
a=2;//TypeError
const obj={
    b:3,
    c:4
}
obj.b=5;
console.log(obj);//{b:5,c:4}

参考资料

猜你喜欢

转载自blog.csdn.net/caomage/article/details/83586048