javascript变量提升-堆栈原理

310 阅读2分钟

var function的变量提升(无条件)

打开一个标签页浏览器就会分配一块内存作为全局执行上下文栈(ECStack) 全局执行上下文(EC(G))压入栈内,随后全局的作用域下词法解析,变量提升=>代码自上而下依次解析遇到var就要变量提前声明,遇到function就要提前声明并赋值

var function的变量提升(条件内)

老版浏览器 无论function是否在条件内,变量提升都是声明并定义

新版浏览器 function和var定义在条件代码块中,var还是会在块的外部只声明,但function也是只声明不会定义,在块的内部如果有let const function就会产生块级作用域,在这里的function会变量提升,并且代码在执行到function时会把块级作用域前面的改变映射到上级作用域

例子

var a=0
if(true){
    a=1
    function a(){}
    a=21
    console.log(a)
}
console.log(a)

在老版浏览器(ie10及以下)

首先浏览器从内存中条中开辟一块栈内存(ECStack),将一个全局执行上下文压入栈内,开辟一块堆内存,存储GO对象,window指向GO对象,在压入的全局作用域中词法解析(一般像let的重复声明就会报错),变量提升

在新版浏览器下

如果function的声明在条件内(不论条件是否成立function都只声明,并且像if或for这种块存在let/function/const就会产生块级作用域)

变量提升:var a           //这里的function在条件语句中只声明
a=0

块级作用域start
   变量提升: function a(){}
    a=1     //function之上映射到全局
    function a(){} =>不执行
    a=21
    console.log(a)  =>21
块级作用域end    
cosole.log(a)   =>1

在块级作用域中不能重复声明变量

if(true){
    function a(){}
    var a=0
}
//报错
总结

新版浏览器中存在块级作用域=>块中使用了let/const/function就会形成块级作用域, 因为既要兼容es3 es5 又要兼顾es6所以在块中的var 和function都会在全局声明,但并不定义,在全集会变量提升块中用var 和 function定义的变量(function不赋值),在块级作用域中function变量提升并赋值,执行function之前的代码要映射到全局(function在全局声明过,与全局有关-为了兼顾es3),映射到全局的内容包含块级作用域的变量提升