【JS】变量提升

88 阅读3分钟

js代码是按顺序执行的吗?

fn()
console.log(name)
var name = "qq"
function fn(){
    console.log('fn')
}
//fn
//qq

如上所示:变量(var/function)可在未声明定义前使用。

  • 当响应头content-type:application/javascript时,浏览器对js字符串进行词法解析。
  • 在词法解析阶段,let/const声明的变量会明确必然存在,所以此变量不可在声明前使用,称为 “暂时性死区”,不存在变量提升。

js执行流程

-一段js代码要经过编译阶段执行阶段

  • 编译阶段生成执行上下文与可执行代码
    • 执行上下文是代码的运行环境包括this,变量环境,词法环境等
  • 在编译阶段,var/function会被存放在变量环境中,默认值设置未undefined。在执行阶段去变量环境中查找。 image.png

变量提升

在js执行阶段,把var变量的声明部分与函数声明+定义提升到代码开头行为,会给var变量设置默认值undefined。

  • function在变量提升阶段已经声明+定义处理过,可以在声明前执行。
  • var 声明操作已经处理,但是赋值操作没有
  • if中无论条件是否成立,var都进行变量提升
  • 判断体中出现function,老版本:函数声明+定义,新版本:只声明+不定义 1667045944767.png
  • 函数表达式声明函数 const fun = function(){}
  • key in obj 判断一个对象是否存在某个属性,会沿着对象的原型链寻找所有的键值。
  • obj.hasOwnProperty(key) 则只会寻找对象自身的属性(不包括原型链)。

块级作用域

  • 作用域(scope):变量与函数的可访问范围。
  • es5只有全局作用域以及函数作用域,ES6引进块级作用域。
  • 除函数和对象的大括号外{例如:判断体,循环体} if(true){ } -如果在大括号中出现了let/const/function/class等关键词声明变量,产生一个块级上下文。var不受影响。

function

  1. 在新版本浏览器中,判断体中出现的function,不论条件是否成立,都只声明不定义。
  2. 判断体中出现function产生块级上下文,对function声明+定义(即在全局声明过,也在块级声明)
  3. 当执行到函数function(){}时,本行以上的代码对函数的所有操作,同步给全局一份 但是本行以后对函数的操作,对全局没有任何影响,只对块级上下文有效。
// 产生块级作用域,此时函数在全局只声明
console.log(afn)  //undefined
if(true){
    // 块级作用域声明+定义
    console.log(afn)  //ƒ afn(){}
    // 对函数的操作同步到全局一份
    function afn(){
    }
    // 此后对于函数的操作与全局无关
    afn = 1 
    console.log(afn) // 1
}
console.log(afn) //ƒ afn(){ }

image.png

(let /const)与 var

  • let 不存在变量提升,不允许在定义之前使用
  • let 不允许重复声明(不论基于何种方式声明过这个变量)
  • 全局上下文中,var/function 是给window(GO)设置的全局属性,基于let声明的变量是放在VO(G)中,与全局没有任何关系
  • let 会产生块级作用域
  • let 存在暂时性死区 不允许在定义之前使用
  • const 在声明时必须赋值
  • const 后期不允许改变指针指向 const obj = {n :1} obj.n= 8

ES6如何做到变量提升与块级作用域?

  • let与const声明的变量会放入词法环境中。在词法环境的内部也维护了一个小型栈结构。
  • 块级作用域就是通过词法环境的栈结构来实现了,而变量提升通过变量环境来实现。
1667049704522.png