var b = 'outerB';
function foo() {
var b = 'foo';
bar();
}
function bar() {
console.log(b)
}
foo() // outerB
對(duì)輸出的結(jié)果有沒有疑惑呢?下面分析為什么是這個(gè)結(jié)果
// 模擬偽代碼瓢剿,加深印象
// 創(chuàng)建的時(shí)候,會(huì)插入一個(gè)全局對(duì)象Global Object(簡(jiǎn)寫:GO)
foo.[[scope]] = {
GO: {
...,
b: undefined,
foo: function () {...},
bar: function () {...}
}
}
// 創(chuàng)建bar函數(shù)
bar.[[scope]] = {
GO: {
...,
b: undefined,
foo: function () {...},
bar: function () {...}
}
}
函數(shù)調(diào)用的時(shí)候悠轩,會(huì)生成一個(gè)執(zhí)行環(huán)境(也叫上下文環(huán)境)间狂,然后復(fù)制函數(shù)的[[Scope]]屬性中的對(duì)象構(gòu)建起執(zhí)行環(huán)境的作用域鏈。同時(shí)還有一個(gè)活動(dòng)對(duì)象創(chuàng)建并被推入執(zhí)行環(huán)境作用域鏈的前端火架。
// 偽代碼如下:
1. 復(fù)制foo函數(shù)的[[Scope]]屬性
foo.執(zhí)行環(huán)境 = {
GO: {
...,
b: outerB,
foo: function () {...},
bar: function () {...}
}
}
2. 給foo函數(shù)創(chuàng)建一個(gè)活動(dòng)對(duì)象(AO)前标,并且推入執(zhí)行環(huán)境作用域的前端
foo.執(zhí)行環(huán)境 = {
AO: {
this: window,
arguments: [],
...,// 如果函數(shù)有參數(shù)的話,這里是一些參數(shù)的值
b: foo
},
GO: {
...,
b: outerB,
foo: function () {...},
bar: function () {...}
}
}
// bar調(diào)用距潘,同樣
1. 復(fù)制bar函數(shù)的[[Scope]]屬性
bar.執(zhí)行環(huán)境 = {
GO: {
...,
b: outerB,
foo: function () {...},
bar: function () {...}
}
}
2. 給bar函數(shù)創(chuàng)建一個(gè)活動(dòng)對(duì)象(AO),并且推入執(zhí)行環(huán)境作用域的前端
bar.執(zhí)行環(huán)境 = {
AO: {
this: window,
arguments: [],
...// 如果函數(shù)有參數(shù)的話只搁,這里是一些參數(shù)的值
},
GO: {
...,
b: outerB,
foo: function () {...},
bar: function () {...}
}
}
調(diào)用完成后foo和bar的執(zhí)行環(huán)境都會(huì)被銷毀音比,但是注意的是,函數(shù)的[[Scope]]屬性始終會(huì)保留到函數(shù)中氢惋,函數(shù)再次調(diào)用的時(shí)候洞翩,同樣會(huì)以這種方式再次創(chuàng)建執(zhí)行環(huán)境
再繼續(xù)看下面這段代碼,結(jié)果和你想的結(jié)果是一樣的嗎?
var b = 'outerB'
function foo() {
var b = 'foo';
function bar() {
console.log(b)
}
bar()
}
foo(); // foo
可以仿照之前的例子焰望,一步一步的解析出作用域鏈
// 模擬偽代碼骚亿,加深印象
// 創(chuàng)建foo函數(shù),會(huì)插入一個(gè)全局對(duì)象Global Object(簡(jiǎn)寫:GO)
foo.[[scope]] = {
GO: {
...,
b: undefined,
foo: function () {...}
}
}
// 創(chuàng)建bar函數(shù)
bar.[[scope]] = {
AO: { // foo函數(shù)的活動(dòng)對(duì)象,在創(chuàng)建的時(shí)候就會(huì)被插入到這個(gè)對(duì)象中
...,
b: undefined,
bar: function () {...}
},
GO: {
...,
b: undefined,
foo: function () {...}
}
}
// 偽代碼如下:
1. 復(fù)制foo函數(shù)的[[Scope]]屬性
foo.執(zhí)行環(huán)境 = {
GO: {
...,
b: outerB,
foo: function () {...},
bar: function () {...}
}
}
2. 給foo函數(shù)創(chuàng)建一個(gè)活動(dòng)對(duì)象(AO)熊赖,并且推入執(zhí)行環(huán)境作用域的前端
foo.執(zhí)行環(huán)境 = {
AO: {
this: window,
arguments: [],
...,// 如果函數(shù)有參數(shù)的話来屠,這里是一些參數(shù)的值
b: foo
},
GO: {
...,
b: outerB,
foo: function () {...},
bar: function () {...}
}
}
// bar調(diào)用,同樣
1. 復(fù)制bar函數(shù)的[[Scope]]屬性
bar.執(zhí)行環(huán)境 = {
AO: { // foo函數(shù)的活動(dòng)對(duì)象震鹉,在創(chuàng)建的時(shí)候就會(huì)被插入到這個(gè)對(duì)象中
...,
b: foo,
bar: function () {...}
},
GO: {
...,
b: outerB,
foo: function () {...}
}
}
2. 給bar函數(shù)創(chuàng)建一個(gè)活動(dòng)對(duì)象(AO)俱笛,并且推入執(zhí)行環(huán)境作用域的前端
bar.執(zhí)行環(huán)境 = {
AO(bar): {
this: window,
arguments: [],
...// 如果函數(shù)有參數(shù)的話,這里是一些參數(shù)的值
},
AO(foo): {
...,
b: foo,
bar: function () {...}
},
GO: {
...,
b: outerB,
foo: function () {...}
}
}