0
点赞
收藏
分享

微信扫一扫

JS的变量声明与提升

JS中的let与var的变量提升

实际上无论var,let,还是function都存在变量的三个过程,而const只存在前两个

  1. 创建 create
  2. 初始化 initialize
  3. 赋值 assign

1.声明var变量的过程

有如下代码(下面是函数作用域,不过var在全局声明也是同理)

function text(){
    var num1 = 1;
    var num2 = 2;
}
test(); 

在执行这个test函数时,会发生以下的过程,还有其他过程这里不详细说

  1. 进去test函数,为test函数创建一个环境

  2. 寻找函数中所有使用var关键字声明的变量并创建(create)这些变量

  3. 将这些变量的值初始化( initialize)为 undefined

  4. 执行代码

    •   num1 = 1;
        num2 = 2;
      
  5. num1变量赋值为1,num2变量赋值为2

从上面的过程我们可以得知,var声明的变量在JS引擎解析的时候会首先被创建并赋初始值undefined,即所谓的变量提升概念

2.声明function的过程

有如下代码

test();

function test(){
    console.log("hello world!");
}

同样的JS引擎在解析代码时会有如下过程

  1. 找到所有用 function 声明的变量,在对应的环境中创建这些变量。
  2. 讲这些变量初始化并赋值为对应的函数体
  3. 执行test函数

由此可见function变量会在函数执行前就提前完成三个过程

问题来了如果var声明的变量名与function声明的函数名一样呢?
var test;
function test(){
    conslole.log("hello world!");
}
console.log(test);  //  ƒ test(){
   // conslole.log("hello world!");
// }  

结果显而易见,秉承函数优先的原则,函数是直接在执行代码之前就被赋值了,相等于覆盖了undefined值,因此会打印函数

另一种情况
var test = 1;
function test(){
    conslole.log("hello world!");
}
console.log(test);  //  1 

这种情况下相当于在执行test=1这个赋值语句代码之前,test变量的值是函数体,但执行了test=1之后,test变量的值被覆盖为1了,因此会打印1;下面例子可以证明

console.log(test);  /* 执行赋值代码之前 打印函数体 ƒ test(){
                    conslole.log("hello world!");
                    } 
                    */
var test = 1;
function test(){
    conslole.log("hello world!");
}

3.声明let的过程

初识let印象

  • let 声明的变量的作用域是块级的
  • let 不能重复声明已存在的变量
  • let 有暂时性的死区,不会被提升
  • let 全局变量不会是window的属性

如下代码

{
    let num1 = 1;
    num1 = 2;
}

由于let是块级作用域,我们只看{}里面的过程

  1. 找到块级作用域中所有用 let 声明的变量,在环境中创建这些变量
  2. 开始执行代码(注意现在还没有进行初始化)
  3. 执行 x = 1,将 x 初始化为 1(这并不是一次赋值,如果代码是 let x,就将 x 初始化为 undefined)
  4. 执行 x = 2,对 x 进行赋值为2
因此这便解释了为什么在let x之前使用x会报错的现象
{
    console.log(x);
    let x = 1;
}  //Uncaught ReferenceError: Cannot access 'x' before initialization

仅由报错信息就可以看出,x没被初始化之前是不能被使用的,而let的初始化过程是必须通过执行相应的代码完成的,即形成了所谓的暂时性死区

let与for循环结合使用的奇效

//  有过JS基础的朋友应该知道如果循环体的循环变量是var 声明的 i ,那么一定会打印五次5
//  而用let声明后则会打印 0 1 2 3 4
var liList = document.querySelectorAll('li'); // 获取五个li
for( let i=0; i<liList.length; i++){
  liList[i].onclick = function(){
    console.log(i)
  }
}

原理简单来说就是由于let的块级作用域特点,使得let声明的循环变量 i 在对应的循环体中都保存了对应的值,而且只有循环体内部能访问到这个值

const声明

const声明变量的过程只有创建和初始化两个步骤,声明同时必须初始化,之后不可再被赋值

const a = 1;
a = 2; //Uncaught TypeError: Assignment to constant variable. 报错 不能修改值
const a; //Uncaught SyntaxError: Missing initializer in const declaration  报错,没有初始化

其余特性跟let相同

举报

相关推荐

0 条评论