this的定義
this指的是函數(shù)運行時所在的環(huán)境。(不是定義時所在的環(huán)境)
怎么理解這句話呢?看如下例子:
var w = 1;
var wFunction=function(){
console.log(this.w)
}
var wObj = {
w:2,
wFunction:wFunction
}
wFunction()//1
wObj.wFunction()//2
在這個例子中,首先第一個輸出因妙,因為wFunction是運行在全局環(huán)境中,所以this指向全局環(huán)境票髓,所以輸出1攀涵;第二個輸出,因為wFunction運行在wObj環(huán)境中洽沟,所以this指向wObj以故,而wObj的w屬性值為2,所以輸出2裆操;
那么問題來了怒详,為什么第二個說是在wObj環(huán)境中運行呢,運行環(huán)境是怎么來判別的呢踪区?這得從內存的數(shù)據(jù)結構說起昆烁。
內存的數(shù)據(jù)結構
首先,是考慮到內存的數(shù)據(jù)結構缎岗,才設計這個this的静尼。那內存的數(shù)據(jù)結構是怎樣的呢,先看個例子:
var wObj = {
w:5
}
console.log(wObj.w)//5
這里传泊,javaScript引擎會在內存里先生成一個對象{w:5}鼠渺,然后把這個對象的內存地址(reference)賦值給wObj變量。
如果通過wObj.w來讀取這個對象的屬性w,則引擎會先從wObj這個變量拿到對象的內存地址眷细,然后從該地址讀出這個對象拦盹,返回w屬性。
在看下面一個例子:
var wFunction = function(){
...
}
var wObj = {
wFunc:wFunction
}
console.log(wObj.wFunc())
這里薪鹦,javaScript引擎會先將函數(shù)function(){...}單獨保存在內存中掌敬。然后javaScript引擎會在內存里生成一個對象{wFunc:wFunction},而wFunction則是函數(shù)的內存地址(reference)池磁。然后把這個對象的內存地址賦值給wObj變量奔害。
如果通過wObj.wFunc()執(zhí)行函數(shù),則引擎會先從wObj這個變量拿到對象的內存地址地熄,然后從該地址讀出這個對象华临,返回wFunc屬性,而wFunc屬性的值是函數(shù)function(){...}的內存地址(reference)端考,因為這個是單獨的一個值雅潭,所以可以在不同環(huán)境(上下文)執(zhí)行揭厚。在這里函數(shù)是通過wObj找到的(wObj的屬性wFunc),所以在wObj環(huán)境中執(zhí)行的扶供。
這里解釋了為啥函數(shù)是可以在不同的環(huán)境中執(zhí)行筛圆。那么問題來了,這動態(tài)的執(zhí)行環(huán)境椿浓,怎么獲取呢太援?
this設計機制
針對獲取執(zhí)行環(huán)境問題,this就這么設計出來了扳碍,它的設計目的就是在函數(shù)體內部提岔,指代函數(shù)當前的運行環(huán)境。
回到文章開頭例子笋敞,并加以深化如下:
var w = 1;
var wFunction=function(){
console.log(this.w)
}
var wObj = {
w:2,
wFunction:wFunction
}
wFunction()//1
wObj.wFunction()//2
let wObjFunc = wObj.wFunction;
wObjFunc()//1
第一個輸出碱蒙,函數(shù)執(zhí)行時,是通過全局變量wFunction找到函數(shù)引用地址的夯巷,它的執(zhí)行環(huán)境則是全局赛惩,因此輸出全局w,為1鞭莽;
第二個輸出坊秸,函數(shù)執(zhí)行時,是通過wObj指向的對象里的wFunction屬性找到的函數(shù)引用地址的澎怒,因此褒搔,它的執(zhí)行環(huán)境則是wObj指向的對象,因此輸出對象的w喷面,為2星瘾;
第三個輸出,函數(shù)執(zhí)行時惧辈,是通過全局變量wObjFunc找到函數(shù)引用地址的琳状,(因為let wObjFunc = wObj.wFunction;這直接把函數(shù)的引用地址直接賦給了全局變量wObjFunc,所以wObjFunc直接指向函數(shù)本身)它的執(zhí)行環(huán)境則是全局盒齿,因此輸出全局w念逞,為1;