最近在重温一些前端的基础知识,于是对看过的知识点进行归纳整理,防止老年痴呆看完就忘
let 和 const
先看结果,let 和 const 为ES6新增,与var的具体区别如下
| 区别 | var | let | const |
|---|---|---|---|
| 作用域 | 全局和函数 | 全局、函数、块级 | 全局、函数、块级 |
| 变量提升 | √ | X | X |
| 临时性死区 | X | √ | √ |
| 重复声明 | √ | X | X |
| 全局作用域下声明 | 挂在window或global下 | 不挂 | 不挂 |
| 重新赋值 | √ | √ | X |
关于作用域
- 全局作用域
var a = 1;
let b = 2;
const c = 3;
console.log(a, b, c); // 1 2 3
- 函数作用域
function test() {
var a = 1;
let b = 2;
const c = 3;
console.log('函数内', a, b, c); // 1 2 3
}
test();
console.log('函数外', a); // a is not defined
console.log('函数外', b); // b is not defined
console.log('函数外', c); // c is not defined
- 块级作用域
{
var a = 1;
let b = 2;
const c = 3;
console.log('in block', a, b, c); // 1 2 3
}
console.log('块级外', a); // 1
console.log('块级外', b); // b is not defined
console.log('块级外', c); // c is not defined
- 一个老生常谈的问题
// 输出5次5
for(var i = 0; i < 5; i++) {
setTimeout(function() {
console.log(i);
}, 100);
}
// 通过闭包解决
for(var i = 0; i < 5; i++) {
(function (i) {
setTimeout(function() {
console.log(i);
}, 100);
})(i);
}
// 通过let解决
for(let i = 0; i < 5; i++) {
setTimeout(() => {
console.log(i);
}, 100);
}
- 同时,通过闭包还能定义私有变量
var $ = (function (window) {
var a = 1;
var b = 2;
setTimeout(function() {
console.log('闭包', a, b)
}, 100);
return {
a,
b
}
})(window);
console.log($.a); // 1
console.log(a); // a is not defined
//
变量提升
当我们定义一个变量的时候,JS引擎会分三个步骤,创建、初始化、和赋值
- 对于var 代码如下
console.log(a, b); // undefined undefined
a = 1;
b = 2;
var a;
var b;
console.log(a, b); // 1 2
- 创建:先找出所有var声明的变量(a和b),并创建这写变量
- 初始化: 将这些变量初始化为undefined
这就可以解释就是指在引擎做了这两步为什么上面会输出undefined而不是报错;而通常我们所说的变量提升
- 开始执行代码
- 赋值:将a b赋值为1 2
- 对于let
console.log(a); // a is not defined
let a = 1;
a = 2;
- 创建:找出所有用let声明的变量,并创建这些变量
- 开始执行代码
- 初始化:将a初始化为1,如果是let a,则是初始化为undefined
- 赋值:将a赋值为2
const和let类似,但是没有赋值这一步,二手在初始化的时候直接将其初始成初始只,后续则不能重新赋值
以上就可以解释为什么let和const为什么必须先声明后使用了
临时性死区
- 对于var, 没有临时性死区
var a = 1;
{
a = 2;
console.log(a); // Cannot access 'a' before initialization
var a;
}
- 而对于let和const,一旦进入了如下的块级作用域,a变量就已经存在了(上面的变量提升的创建过程),此时必须等声明的那行代码执行完,才可以访问该变量
var a = 1;
{
a = 2;
console.log(a); // Cannot access 'a' before initialization
let a; // 或const a = 3;
}
重复声明和重新赋值
- let和const都不能重复声明,且const不能重新赋值
var a = 1;
var a = 2;
let b = 1;
let b = 2; //Identifier 'b' has already been declared
const c = 1;
c = 2; // Assignment to constant variable
全局作用域下定义变量
- 如果在全局作用域下定义变量,对于var,则会被挂到全局对象(window|global)下,而对于const 和let则不会
var a = 1;
let b = 2;
const c = 3;
console.log(a, b, c); // 1 2 3
console.log(window.a, window.b, window.c); // 1 undefined undefined
写在最后,推荐使用const, 如果有需要重新赋值的则使用let