你是否还在为代码不优雅而烦恼?
你是否还在为长长的代码而半夜惊醒?
你是否还在为怎么成为最靓的仔而烦恼?
从今天起,让我们拥抱ES6,成为最靓的仔吧~
第一次发文,可能写的不是很 NICE !!
欢迎大家来一起讨论~文中如有错误欢迎指出~~
好了,闲话不多说,进入正题吧!!
今天要讲的是我们的新朋友 let
和 const
但是在介绍新朋友之前,先来讲讲我们的老朋友 var
关于 var
的特点相信大家都已经非常的熟悉了,那我就将他们都罗力出来吧
- 变量提升
- 可以重复声明
- 可以重复赋值
- 没有块级作用域
- 在全局作用域下声明的变量,会成为顶层对象(window)的属性
那么我们也将围绕着这几点来讲解 let
和 const
1、变量提升
let
和 const
都没有变量提升,也就是常说的暂时性死区,必须先声明变量,然后才能访问,否则会报错,例如:
// 以 let 为例
// BAD
console.log(a); // Uncaught ReferenceError: Cannot access 'a' before initialization
let a = 1;
// GOOD
let a = 1;
console.log(a); // 1
2、重复声明
let
和 const
都不支持同一个变量重复声明,否则会报错,例如:
// 以 let 为例
var a = 1;
let a = 1; // Uncaught SyntaxError: Identifier 'a' has already been declared
3、重复赋值
let
和 var
都支持给一个变量重复赋值,而 const
顾名思义,声明的是一个常量,一旦声明就不可修改了,否则会报错,例如:
const a = 1;
a = 2; // Uncaught TypeError: Assignment to constant variable
这里还需要注意两点:
const
在声明常量的时候,需要赋值,否则也会报错,例如:
// BAD
const a; // Uncaught SyntaxError: Missing initializer in const declaration
// GOOD
const a = 1;
const
实际上并不是保证变量的值不可修改,而是变量所指向的那个内存地址所保存的数据不可修改。
如果是基本数据额类型的话,是指向栈内存里的数据
如果是引用数据类型的话,指向的是保存在栈内存里指向堆内存的一个指针
所以指针指向的内存地址是不可修改的,否则会报错,例如:
const obj = {};
obj = {a: 1}; // index.html:86 Uncaught TypeError: Assignment to constant variable
但是对象内部的属性还是可以进行修改的,例如:
const obj = {
a:1
}
obj.a = 2;
console.log(obj.a); // 2
如果想让对象内部的属性也不能进行修改的话,可以使使用Object.freeze()方法,将对象冻结,例如:
const obj = Object.freeze({});
obj.a = 123;
console.log(obj); // {}
上面的代码中,对象 obj 指向的是一个冻结的对象,所以添加属性是不起作用的,如果要将对象彻底冻结,还是不够的,需要用到以下方法:
var constantize = (obj) => {
Object.freeze(obj);
Object.keys(obj).forEach( (key) => {
if ( typeof obj[key] === 'object' ) {
constantize( obj[key] );
}
});
};
4、块级作用域
let
和 const
与 var
不同的一点就是,它们不仅有全局作用域和函数作用域,还有块级作用域,例如:
(() => {
let n = 1;
if (true) {
let n = 2;
}
console.log(n); // 1
})();
以上代码中,我们在代码中用 let
命令对变量 n
进行了重复声明,但是输出的结果却是1,这表明外层代码块不受内层代码块的影响,所处的作用域不同,如果两次改用 var
声明变量 n
的话,输出的肯定是 2
5、在全局作用域下声明变量
我们的老朋友 var
命令在全局作用域下声明变量时,声明的变量会成为到顶层对象(window
)的属性,而 let
和 const
命令在全局作用域下声明的变量,不属于顶层对象(window
)的属性,例如:
var a = 1;
let b = 1;
const c = 1;
console.log(window.a); // 1
console.log(window.b); // undefined
console.log(window.c); // undefined
到这里,那么关于 let
和 const
的基本特性就已经讲的差不多了,如果遗漏或者有错误,欢迎指出,向各位大佬看齐~
6、应用场景
1、 let
简单的一些应用场景
最常见的就是for
循环,例如:
for (let i = 0, i < 5, i++) {
console.log(i); // 0 1 2 3 4
}
console.log(i); // Uncaught ReferenceError: i is not defined
以上代码在全局打印变量
i
的时候,提示没有定义,说明在for
循环里面定义的变量i
不会泄露到全局变量中
还有一种应用场景,在 for
循环里进行异步操作,例如:
for (let i = 0; i < 5; i++) {
setTimeout(() => console.log(i), 5000); // 0 1 2 3 4
}
以上代码中,变量
i
是let
声明的,而且i
只在本轮循环中有效, 也就是说每次循环都会产生一个新的代码块(块级作用域)和新的变量i
,并且 javascript 内部引擎会记住上一轮循环的值,初始化本轮变量i
时,就会在上一轮循环的基础上进行计算
如果想用 var
实现上面相同的结果的话,可以使用我们的老朋友闭包,例如:
for (var i = 0; i < 5; i++) {
((i) => setTimeout(() => console.log(i), 5000))(i); // 0 1 2 3 4
}
顺便补充一点,for
循环,循环变量那部分是一个父作用域,而循环体部分是一个子作用域,例如:
for (let i = 0; i < 2; i++) {
let i = 'a';
console.log(i); // a a
}
2、const
简单的一些应用场景
const
的应用场景也非常的广,一般定义一些不会更改数据,如常量、引入的数据和模块,或者请求的返回的数据等等,只要数据是不变更的,我们默认就用 const
,如下:
const fs = require("fs");
const ERR_CODE = 1;
简单梳理一下大概的内容
命令 | let | const | var |
---|---|---|---|
变量提升 | √ | ||
重复声明 | √ | ||
重复赋值 | √ | √ | |
块级作用域 | √ | √ | |
全局声明变量会成为顶层对象的属性 | √ |
好了,恭喜你,在成为最靓的仔的路上又前进了一步 ヾ(◍°∇°◍)ノ゙
欢迎补充和指出错误,也欢迎小手手~