浮生逆旅

变量声明之const、let的正确用法

字数统计: 951阅读时长: 3 min
2019/11/07 Share

导读

迄今为止,ES6(ES2015) 发版已经 4 年了,ES6 其中一个特性是加入了新的变量声明方式,鼓励使用constlet关键字声明的块级作用域变量取代var关键字声明的函数作用域变量,这一愿景到现在也普遍得到了实现。但我在功能迭代修改一个同事代码时发现了一个问题,他使用constlet的方式让我感到非常疑惑,我去询问 他得到了他的解释:声明基本数据类型变量时使用let,声明对象类型变量时使用const

随即我找到了关于constlet正确用法的文档,交给了我的同事,也由此有了这篇博客。


为何推出块级作用域取代函数作用域

函数作用域——var

相信大家都遇到过相似问题,如果我们使用”for”循环来向一个数组 push 函数,函数中使用了”for”的循环值”i”,在循环结束后,我们发现执行这个数组中任意的函数,他们中的”i”的值都是一样的

1
2
3
4
5
var arr = [];
for (var i = 0; i < 10; i++) {
arr[i] = () => console.log(i);
}
arr[6](); // 10

这种情况与我们期望的不一样,我们想要得到的值是 “6”,为什么在这里变成了 “10”?

原因是使用var声明的”i”变量提升了,V8 引擎执行前就将变量”i”的声明提升到了这段代码所在的函数体中(若”for”不在函数中则提升到所在 js 文件中),此时的”i”是已被声明,但未被定义具体值

1
2
3
4
5
6
var arr = [];
console.log(i); // undefined
for (var i = 0; i < 10; i++) {
arr[i] = () => console.log(i);
}
arr[6](); // 10

所以在”for”执行完成之后,被提升到函数作用域中的”i”在最后一次”i++”后变成了循环边界值”++”也就是 “10”

为了解决这一问题,我们不得不使用可能引起内存泄漏的闭包来达到我们想要的效果

1
2
3
4
5
var arr = [];
for (var i = 0; i < 10; i++) {
arr[i] = (i => () => console.log(i))(i);
}
arr[6](); // 6

由此,应该也感受到了在这个变量提升这一点上 JavaScript 对我们“浓浓的恶意”


块级作用域——const、let

千呼万唤始出来,2015 年 ECMA 终于推出了ES6 推出了新特性块级作用域(关键字constlet),接上面的例子,将var关键字改为let关键字

1
2
3
4
5
const arr = [];
for (let i = 0; i < 10; i++) {
arr[i] = () => console.log(i);
}
arr[6](); // 6

只是将var关键字换为let关键字,就得到了我们想要的结果,也避免了使用闭包导致内存泄漏的风险,是不是很神奇?我们再看一下”i”有没有被提升

1
2
3
4
5
6
const arr = [];
console.log(i); // ReferenceError: i is not defined
for (let i = 0; i < 10; i++) {
arr[i] = () => console.log(i);
}
arr[6](); // 6

很棒,”i” 没有被提升


const、let的区别

那么同样是声明块级作用域变量的constlet,它们有什么区别呢?

const:常量,常数

let:允许,让;出租;假设;妨碍

跟字面意思相同,const声明的变量不能够再次被修改 基本类型不能更改值,引用类型不能更改引用,但可以更改属性值

1
2
3
4
5
6
7
8
9
10
11
12
const num = 10;
num = 11; // TypeError: Assignment to constant variable.

const stu = {
name: '张三',
age: 20
};
stu.age = 21;
stu = { // TypeError: Assignment to constant variable.
name: '李四',
age: 23
};

let声明的变量可以随意进行赋值

1
2
3
4
5
let obj = 10;
obj = 11;
obj = {
name: ''
}

后记

关注生态,可能情况下尝试使用新的东西,我们可能更早的体验到一些好东西 也许是新特性,也许是语法糖(可能甜的齁人)

拜~


CATALOG
  1. 1. 导读
  2. 2. 为何推出块级作用域取代函数作用域
    1. 2.1. 函数作用域——var
    2. 2.2. 块级作用域——const、let
  3. 3. const、let的区别
  4. 4. 后记