理解
上下文和作用域是兩個(gè)完全不同的概念,從根本上來說,作用域是基于函數(shù)的帜篇,而上下文是基于對(duì)象的。 作用域涉及到所被調(diào)用函數(shù)中的變量訪問诫咱,不同的調(diào)用場(chǎng)景是不一樣的笙隙。上下文始終是this關(guān)鍵字的值,是控制當(dāng)前所執(zhí)行代碼的對(duì)象的引用坎缭。那么就涉及到變量作用域竟痰,this上下文签钩,聲明/執(zhí)行環(huán)境,作用域鏈閉包坏快,以及語法糖call / apply等概念铅檩。
變量作用域
一個(gè)變量可以被定義在局部或者全局作用域中,這建立了在運(yùn)行時(shí)(runtime)期間變量的訪問性的不同作用域范圍莽鸿。 任何全局變量昧旨,需要在函數(shù)體的外部被聲明,并且存活于整個(gè)運(yùn)行時(shí)(runtime)祥得,并且在任何作用域中都可以被訪問到兔沃。局部變量只能在其被調(diào)用期的作用域范圍內(nèi)被賦值、檢索级及、操縱粘拾。
var關(guān)鍵字聲明的變量有一個(gè)變量提升的過程
在ES6中,塊級(jí)作用域创千,let關(guān)鍵字來定義變量
this上下文
上下文通常取決于函數(shù)是如何被調(diào)用的缰雇。
- 當(dāng)一個(gè)函數(shù)被作為對(duì)象中的一個(gè)方法被調(diào)用的時(shí)候,this被設(shè)置為調(diào)用該方法的對(duì)象上
- 當(dāng)調(diào)用函數(shù)時(shí)使用new操作符來創(chuàng)建對(duì)象的實(shí)例的情況下追驴,在函數(shù)的作用域內(nèi)部this的值被設(shè)置為新創(chuàng)建的實(shí)例
- 直接調(diào)用函數(shù)時(shí)械哟,this默認(rèn)情況下是全局上下文,在瀏覽器中它指向window對(duì)象
```
var obj = {
foo: function(){
console.log(this);
}
};
obj.foo(); // obj
var a = obj.foo();
a();// window
```
```
function foo(){
console.log(this);
}
new foo() // foo
foo() // window
```
執(zhí)行環(huán)境
區(qū)分執(zhí)行環(huán)境和上下文殿雪,當(dāng)JavaScript解釋器初始化執(zhí)行代碼時(shí)暇咆, 它首先默認(rèn)進(jìn)入全局執(zhí)行環(huán)境(execution context),從此刻開始丙曙,函數(shù)的每次調(diào)用都會(huì)創(chuàng)建一個(gè)新的執(zhí)行環(huán)境爸业。
執(zhí)行環(huán)境(execution context),它定義了變量或函數(shù)有權(quán)訪問的其他數(shù)據(jù)亏镰,決定了它們各自的行為扯旷。
每個(gè)函數(shù)都有自己的執(zhí)行環(huán)境。當(dāng)執(zhí)行流進(jìn)入一個(gè)函數(shù)時(shí)索抓,函數(shù)的環(huán)境就會(huì)被推入一個(gè)環(huán)境棧中(execution stack)钧忽。在函數(shù)執(zhí)行完后,棧將其環(huán)境彈出逼肯, 把控制權(quán)返回給之前的執(zhí)行環(huán)境
執(zhí)行環(huán)境可以分為創(chuàng)建和執(zhí)行兩個(gè)階段耸黑。在創(chuàng)建階段,解析器首先會(huì)創(chuàng)建一個(gè)變量對(duì)象(variable object篮幢,也稱為活動(dòng)對(duì)象 activation object)大刊, 它由定義在執(zhí)行環(huán)境中的變量、函數(shù)聲明三椿、和參數(shù)組成缺菌。在這個(gè)階段曲尸,作用域鏈會(huì)被初始化,this的值也會(huì)被最終確定男翰。 在執(zhí)行階段另患,代碼被解釋執(zhí)行。
作用域鏈
作用域鏈包含了在環(huán)境棧中的每個(gè)執(zhí)行環(huán)境對(duì)應(yīng)的變量對(duì)象蛾绎。通過作用域鏈昆箕,可以決定變量的訪問和標(biāo)識(shí)符的解析,全局執(zhí)行環(huán)境的變量對(duì)象始終都是作用域鏈的最后一個(gè)對(duì)象租冠。
簡(jiǎn)單說鹏倘,就是一個(gè)執(zhí)行環(huán)境能夠訪問到的所有變量鏈
閉包(有什么特殊作用?)
在函數(shù)內(nèi)定義一個(gè)嵌套的函數(shù)時(shí)顽爹,就構(gòu)成了一個(gè)閉包纤泵, 它允許嵌套函數(shù)訪問外層函數(shù)的變量。
閉包是指有權(quán)訪問另一函數(shù)作用域中的變量的函數(shù)
模塊模式最流行的閉包類型之一镜粤,它允許你模擬公共的捏题、私有的、和特權(quán)成員
var Module = (function(){
var privateProperty = 'foo';
function privateMethod(args){
// do something
}
return {
publicProperty: '',
publicMethod: function(args){
// do something
},
privilegedMethod: function(args){
return privateMethod(args);
}
};
})();
(function() { ... })()匿名函數(shù)肉渴。全局環(huán)境中自執(zhí)行的匿名函數(shù)公荧,俗稱 立即執(zhí)行函數(shù)
Call和Apply
允許自定義上下文中執(zhí)行函數(shù),即this指向誰同规。不同點(diǎn)在于循狰,call函數(shù)需要參數(shù)列表,而apply函數(shù)需要你提供一個(gè)參數(shù)數(shù)組券勺。調(diào)用 xxx.call(執(zhí)行函數(shù)绪钥,arguments)
ES6中的箭頭函數(shù)
箭頭函數(shù)沒有它自己的this值, 它的this值繼承自外圍作用域