JS -- (6) 变量提升 && 变量声明

34 阅读3分钟

一. 变量提升

变量提升: 造成变量提升的本质原因是js引擎在代码执行前有一个解析的过程,创建了执行上下文,初始化了一些代码执行时需要用到的对象。这个变量对象是执行上下文的一个属性,它包含了函数的形参、所有的函数和变量声明,这个对象的是在代码解析的时候创建的。

具体过程:

JS 在遇到一个变量或者一个函数时,会有两步操作:解析和执行!!

(1) 解析过程
  • JS 会对语法进行检查,并对函数进行预编译!!

  • 会创建一个全局执行上下文环境

  • 并创建该函数执行上下文的变量对象 AO

     - 在该变量对象 AO 中,会把代码中的变量、函数声明都找到,并作为属性添加到该函数中,并赋值为 undefined
    

补:

2137.png

(2) 为什么要进行变量提升?
  • 提高性能,可以为变量提前分配栈空间!!

在 JS代码执行之前,会进行语法检查和预编译,并且这一操作只进行一次。这么做是为了提高性能。如果没有这一步,那么每次执行代码前都必须重新解析一遍该变量(函数),而这时没有必要的。

  • 容错性更好
(3) 缺点:
  • 导致内存泄漏(意外声明全局变量)
  • 出现意外的错误

2138.png

如上:本来是想打印外层的 temp 变量,但打印出来的确是 undefined ,因为变量提升的问题!!

二. 变量声明

三种常见的声明:varletconst

是否有变量提升作用域是否可重复定义是否会成为windows对象的属性
var函数作用域可重复声明
let没有块级作用域不可重复不会
const没有块级作用域不可重复不会
  • var 不初始化的话,会默认是 undefined
  • let 没有变量提升,会出现 “暂时性死区”,即在let 声明之前的执行瞬间被称为"暂时性死区",在此阶段引用后面声明的变量都会报错!!!
  • const 声明的变量必须进行初始化!!!
  • 只有 var 声明的变量,会在代码执行前(解析时)被当作属性加入到提前创建的变量对象 AO中!! 《1》《2》
1》function foo() {
    console.log(a);
    a = 1;
}
foo(); // 报错,函数中的 "a" 并没有通过 var 关键字声明,所有不会被存放在 AO 中。【没有变量提升,执行时代码需要一步一步】2》function foo() {
    console.log(a);
    let a = 1;
}
foo(); // 报错,函数中的 "a" 并没有通过 var 关键字声明,所有不会被存放在 AO 中。3》function foo() {
    console.log(a);
    var a = 1;
}
foo(); // undefined
  • 直接 a = 1 ,会使变量成为全局变量,即会成为 window对象 的属性

const 声明的变量的值可以改变么?

const保证的并不是变量的值不能改动,而是变量指向的那个内存地址不能改动。

  • 对于基本类型的数据(数值、字符串、布尔值),其值就保存在变量指向的那个内存地址,因此等同于常量。《1》
  • 但对于引用类型的数据(主要是对象和数组)来说,变量指向数据的内存地址,保存的只是一个指针,const只能保证这个指针是固定不变的,至于它指向的数据结构是不是可变的,就完全不能控制了。《2》《3》
《1》
const a = 3;
a = 4;
console.log(a);   // 报错
《2》
const arr = [1,2,3];
arr = [];
console.log(arr);  // 报错
《3》
const arr = [1,2,3];
arr .push(2);
console.log(arr);  // [1,2,3,2]