var let const fn变量提升

JS 变量的声明分为 创建create初始化initialize赋值assign

var 声明的过程

1
2
3
4
5
function fn() {
var x = 1;
var y = 2;
}
fn();
  1. 进入 fn,为 fn 创建一个环境。
  2. 找到 fn 中所有用 var 声明的变量,在这个环境中「创建」这些变量(即 xy)。
  3. 将这些变量「初始化」为 undefined
  4. 开始执行代码
  5. x = 1x 变量「赋值」为 1
  6. y = 2y 变量「赋值」为 2

var 例 1

1
2
3
4
5
6
7
8
9
var name = 'zky';
(function () {
if (typeof name === 'undefined') {
var name = 'xq';
console.log(1, name);
} else {
console.log(2, name);
}
})();
  1. 在自执行的 function 里的 var 经过变量提升,先初始化 nameundefined
  2. 然后在第二步则打印 1,xq

function 声明过程

1
2
3
4
5
6
function fn() {
fn2()

function fn2(){
console.log(2)
}
  1. 找到所有用 function 声明的变量,在环境中「创建」这些变量。
  2. 将这些变量「初始化」并「赋值」为 function(){ console.log(2) }
  3. 开始执行代码 fn2()

let 声明过程

1
2
3
4
{
let x = 1;
x = 2;
}
  1. 找到所有用 let 声明的变量,在环境中「创建」这些变量
  2. 开始执行代码(注意现在还没有初始化)
  3. 执行 x = 1,将 x 「初始化」为 1(这并不是一次赋值,如果代码是 let x,就将 x 初始化 4.为 undefined
  4. 执行 x = 2,对 x 进行「赋值」

例 1

1
2
3
4
5
let x = 'global';
{
console.log(x); // Uncaught ReferenceError: x is not defined
let x = 1;
}
  1. console.log(x) 中的 x 指的是下面的 x,而不是全局的 x
  2. 执行 logx 还没「初始化」,所以不能使用(也就是所谓的暂时死区)

例 2

1
2
3
4
5
6
var liList = document.querySelectorAll('li'); // 共5个li
for (let i = 0; i < liList.length; i++) {
liList[i].onclick = function () {
console.log(i);
};
}
  1. for( let i = 0; i< 5; i++) 这句话的圆括号之间,有一个隐藏的作用域
  2. for( let i = 0; i< 5; i++) { 循环体 } 在每次执行循环体之前,JS 引擎会把 i 在循环体的上下文中重新声明及初始化一次(即 let/const 在与 for 一起用时,会有一个 perIterationBindings 的概念)。

可理解为:

1
2
3
4
5
6
7
var liList = document.querySelectorAll('li'); // 共5个li
for (let i = 0; i < liList.length; i++) {
let i = 隐藏作用域中的i;
liList[i].onclick = function () {
console.log(i);
};
}

例 3

1
2
let x = x; // Uncaught ReferenceError: x is not defined
let x; //Identifier 'x' has already been declared
  1. 如果 let x 的初始化过程失败了,x 变量就将永远处于 created 状态。
  2. 无法再次对 x 进行初始化, x 永远处在暂时性死区.

当程序的控制流程在新的作用域(module function 或 block 作用域)进行实例化时,在此作用域中用 let/const 声明的变量会先在作用域中被创建出来,但因此时还未进行词法绑定,所以是不能被访问的,如果访问就会抛出错误。因此,在这运行流程进入作用域创建变量,到变量可以被访问之间的这一段时间,就称之为暂时性死区。

const 声明过程

const 过程跟 let 一样,但 const 只有「创建」和「初始化」,没有「赋值」过程。

总结

  1. let、const 的「创建」过程被提升了,但是初始化没有提升。
  2. var 的「创建」和「初始化」都被提升了。
  3. function 的「创建」「初始化」和「赋值」都被提升了。

git命令总结

参考链接

我用了两个月的时间才理解 let

---- 本文结束,感谢您的阅读 ----