前端开发那些事儿

小记·作用域|闭包|变量提升

2021-05-28  本文已影响0人  某时橙

完全是些零碎的总结↓

变量提升?

栗子:

function test(){
console.log(foo);
var foo=1;
}

对于可执行代码,在其执行之初会有一个分析的过程,分析时会预处理函数的活动对象(AO),此时AO内部的foo初值为undefined,只有当真正执行到var foo时,才会赋值1,由于console.log在var之前,所以打印的foo是undefined(此时AO.foo=undefined)

简而言之:变量能提升是因为分析过程中,var声明的键被初始化了。

思维导图?

闭包?

JS是词法(静态)作用域,其作用域在创建(而不是执行时)确定,所以

let value = 1;
function foo() {
    console.log(value);
}
function bar() {
    let value = 2;
    foo();
}
bar();

结果是value=1
原因是
1.foo和bar被在全局代码中被创建,此时会初始化AO,作用域链,this,
2.foo和bar的作用域链都是[自己的AO,global.AO]
3.所以打印结果是1

这里涉及的作用域链,其完全与函数内部一个叫做[[Scopes]]的属性有关,不信看下例闭包

function foo() {
    let a=1
    function bar() {
      console.log(a)
    }
   return bar
}
console.dir(foo());
//打印结果↓↓
f bar()
arguments: null
caller: null
length: 0
name: "bar"
prototype: {constructor: ƒ}
__proto__: ƒ ()
[[FunctionLocation]]: VM50:3
[[Scopes]]: Scopes[2]
0: Closure (foo) {a: 1}
1: Global {window: Window, self: Window, document: document, name: "", location: Location, …}

[[Scopes]]内包含的就是变量对象VO,函数执行时找变量就是从Scopes的VO按序遍历来寻找的。
根据上面的解析过程,我们也可以如法炮制
原因:
1.全局代码下foo被创建,初始化AO,作用域链,this,此时foo的作用域链是[foo.AO,global.AO]
2.执行foo
3.bar被创建,此时bar的作用域链是[bar.AO,foo.[[Scopes]]]==[bar.AO,foo.AO,global.AO]
4.返回bar
5.bar的scopes没有变化,当然被保存了呀,所以闭包

上一篇 下一篇

猜你喜欢

热点阅读