JS 基础:变量声明
JS 变量的声明分为 创建create、初始化initialize 和 赋值assign。
var 声明的过程
javascript
function fn() {
var x = 1;
var y = 2;
}
fn();- 进入
fn,为fn创建一个环境。 - 找到
fn中所有用var声明的变量,在这个环境中「创建」这些变量(即x和y)。 - 将这些变量「初始化」为
undefined。 - 开始执行代码
x = 1将x变量「赋值」为1y = 2将y变量「赋值」为2
var 例 1
js
var name = 'zky';
(function () {
if (typeof name === 'undefined') {
var name = 'xq';
console.log(1, name);
} else {
console.log(2, name);
}
})();- 在自执行的
function里的var经过变量提升,先初始化name为undefined。 - 然后在第二步则打印
1,xq。
function 声明过程
javascript
function fn() {}
fn2();
function fn2() {
console.log(2);
}- 找到所有用
function声明的变量,在环境中「创建」这些变量。 - 将这些变量「初始化」并「赋值」为
function(){ console.log(2) }。 - 开始执行代码
fn2()
let 声明过程
javascript
{
let x = 1;
x = 2;
}- 找到所有用
let声明的变量,在环境中「创建」这些变量 - 开始执行代码(注意现在还没有初始化)
- 执行
x = 1,将x「初始化」为 1(这并不是一次赋值,如果代码是let x,就将x初始化为undefined) - 执行
x = 2,对x进行「赋值」
例 1
javascript
let x = 'global';
{
console.log(x); // Uncaught ReferenceError: x is not defined
let x = 1;
}console.log(x)中的x指的是下面的x,而不是全局的x- 执行
log时x还没「初始化」,所以不能使用(也就是所谓的暂时死区)
例 2
javascript
var liList = document.querySelectorAll('li'); // 共5个li
for (let i = 0; i < liList.length; i++) {
liList[i].onclick = function () {
console.log(i);
};
}for( let i = 0; i< 5; i++)这句话的圆括号之间,有一个隐藏的作用域for( let i = 0; i< 5; i++) { 循环体 }在每次执行循环体之前,JS引擎会把i在循环体的上下文中重新声明及初始化一次(即let/const在与for一起用时,会有一个perIterationBindings的概念)。
可理解为:
javascript
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
javascript
let x = x; // Uncaught ReferenceError: x is not defined
let x; //Identifier 'x' has already been declared- 如果
let x的初始化过程失败了,x变量就将永远处于created状态。 - 无法再次对
x进行初始化,x永远处在暂时性死区.
当程序的控制流程在新的作用域(module function 或 block 作用域)进行实例化时,在此作用域中用 let/const 声明的变量会先在作用域中被创建出来,但因此时还未进行词法绑定,所以是不能被访问的,如果访问就会抛出错误。因此,在这运行流程进入作用域创建变量,到变量可以被访问之间的这一段时间,就称之为暂时性死区。
const 声明过程
const 过程跟 let 一样,但 const 只有「创建」和「初始化」,没有「赋值」过程。
总结
let、const的「创建」过程被提升了,但是初始化没有提升。var的「创建」和「初始化」都被提升了。function的「创建」「初始化」和「赋值」都被提升了。
