完全是些零碎的总结↓
变量提升?
栗子:
function test(){
console.log(foo);
var foo=1;
}
对于可执行代码,在其执行之初会有一个分析的过程,分析时会预处理函数的活动对象(AO),此时AO内部的foo初值为undefined,只有当真正执行到var foo时,才会赋值1,由于console.log在var之前,所以打印的foo是undefined(此时AO.foo=undefined)
简而言之:变量能提升是因为分析过程中,var声明的键被初始化了。
思维导图?
- 可执行代码
- 全局代码
- 函数
- eval
- 执行上下文栈
-
变量对象(Variable object,VO):执行上下文相关的数据作用域,存储上下文定义的变量、声明
https://github.com/mqyqingfeng/Blog/issues/5 ←看这个 -
作用域链(Scope chain)
https://github.com/mqyqingfeng/Blog/issues/6 ←看这个 - this
-
变量对象(Variable object,VO):执行上下文相关的数据作用域,存储上下文定义的变量、声明
闭包?
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没有变化,当然被保存了呀,所以闭包