#deep in JavaScript#--JavaScript中的this

隨著最近這幾年web前端的飛速發(fā)展,越來越多的人投入到前端開發(fā)的行列。前端的特點是入門簡單、精通極難。很多人在剛接觸前端時很容易產(chǎn)生一些錯誤的認(rèn)知。大批的前端工程師中,很多開發(fā)者覺得會用jQuery的API,搜集各種jq插件,能夠用這些東西構(gòu)建出體驗還不錯的小東西就覺足矣。導(dǎo)致目前前端工程師兩極分化嚴(yán)重,流弊的能流弊到讓人分分鐘獻(xiàn)上膝蓋、五體投地,技術(shù)比較low的讓人大跌眼鏡。其實,不論學(xué)習(xí)任何技術(shù),對基礎(chǔ)和原理的理解永遠(yuǎn)是開發(fā)者的不斷成長和進(jìn)步的本源,也是衡量一個人能力的關(guān)鍵。因此筆者打算將工作生活中研究積累的一些東西和大家分享出來,整理到#deep in JavaScript#,希望和大家共同學(xué)習(xí)研究核心的、基礎(chǔ)的東西。

問題

該學(xué)jQuery還是該學(xué)JavaScript?事實上,我們弄清楚了它們之間的關(guān)系就覺得這個問題很可笑,但這個問題經(jīng)常會被一些初入前端開發(fā)的開發(fā)者所提及。jQuery是對原生JavaScript的封裝,提供了一些列方便的API,并且優(yōu)化了性能,屏蔽了底層的兼容性等,確實是個不錯的東西。說到這里,JavaScript的重要性十分明了。因此我們應(yīng)該剖析事務(wù)的本質(zhì),深入挖掘JavaScript中的一些問題。

話題

今天我們要討論的是JavaScript中的this,如果不專門去學(xué)習(xí)研究,很難弄清楚其本源。誠然,因為我是從Java開發(fā)轉(zhuǎn)過來的,在剛接觸js沒多久,覺得js的某些情況下的表現(xiàn)和Java中的this比較類似,就自然而然歸為同一類東西了。在后續(xù)的學(xué)習(xí)中,看別人的博客和總結(jié)總能發(fā)現(xiàn)自己之前的理解有失偏頗,就像專門話精力去深入研究、總結(jié)。直到最近看的一本《你不知道的JavaScript(上卷)》中對JavaScript中的this的講解,才把我之前對this的理解全都打通,讓我豁然開朗。

究竟什么是this,this指向?

其實很多編程語言里面都有this,大部分的面向?qū)ο蟮拈_發(fā)語言中,this都是指當(dāng)前當(dāng)前對象。由于JavaScript是一個非面向?qū)ο蟮娜躅愋驼Z言,也不存在類的說法。在ES5中,function是一等公民。

在上述的背景下,很多人會聯(lián)想到:this指向函數(shù)本身,指對函數(shù)本身的引用;考慮如下代碼:

function sayHello () {
    this.content = 'hello';
}
console.log(content);    // ReferenceError: content is not defined
sayHello();
console.log(content);    // hello

代碼很簡單,在未調(diào)用函數(shù)時,全局作用域中沒有content的定義,所以報引用錯誤;調(diào)用函數(shù)時,這里將content定義為this的一個屬性,結(jié)合最后的輸出來看,這個content被定義為全局對象(瀏覽器中是window,Node中是global)的屬性??梢姡诜椒ǘx時,this默認(rèn)指向了全局對象,這種情況也是非常常見的。

既然不指向函數(shù),看似是指向當(dāng)某個對象?
前面的代碼,我們更改如下:

function sayHello () {
    console.log( window === this );
}
sayHello();    // true

嚴(yán)格相等的比較得出的結(jié)果是function內(nèi)部(函數(shù)調(diào)用)的this指向了全局對象window(宿主對象為瀏覽器),為什么會這樣呢?我們知道,直接作用域下的定義事實上都定義在了全局對象下,例如:

var a = 23;
console.log( window.a === a );    // true
function sayHello () {
    ......
}
console.log( window.sayHello === sayHello );    // true

因此sayHello()可以看作是window.sayHello()(事實上就是這樣),因而sayHello()內(nèi)部的this就指向了window,看來this真的是指向某個對象。

指向與函數(shù)調(diào)用

上面的代碼,我們思考下,因為調(diào)用者是window對象,因此sayHello內(nèi)部的this指向window,如果是其他的對象調(diào)用呢?思考如下代碼:

function sayHello () {
    console.log( this === window );
    console.log( this === obj);
}
var obj = {
    sayHello: sayHello
};
// 筆誤:更正為obj.sayHello(),對各位造成的困惑深表歉意,以后一定 嚴(yán)格校稿 2017/1/23
// sayHello();    // false  true

obj.sayHello();    // false true

由于調(diào)用對象更改為obj了,因此this指向發(fā)生了更改,指向了obj。綜合上面所有的討論,我們可以得出結(jié)論:this就是一個指向當(dāng)前對象的引用,具體指向在運行時得以確認(rèn)。

引用指向的變更

在JavaScript中,this指向通常在三種情況下發(fā)生變更:

  1. 創(chuàng)建對象
  2. 使用call或apply強(qiáng)制更改
  3. 對象引用
    第一種很好理解,根據(jù)ECMA5+的定義,在創(chuàng)建new Function類別的對象時,會將對象內(nèi)部this指向當(dāng)前對象,因此有如下代碼:
// 用以創(chuàng)建對象的function name首字母大寫是最佳實踐,這里只是作對比用
function sayHello () {
    console.log( this === window );
}
new sayHello();    // false
```
這是this指向發(fā)生了改變,指向了new sayHello()語句所創(chuàng)建的新對象;
第二種是調(diào)用Function對象內(nèi)建的call或apply方法(方法作用完全相同,只是第二個參數(shù)傳參不同,apply方法以數(shù)組形式傳參),這種方式會強(qiáng)制將當(dāng)前this指向call或apply調(diào)用傳參的第一個參數(shù):
```JavaScript
var obj = {
    content: 20;
};
var content = 10;
function sayHello () {
    console.log( this.content );
}
sayHello.call(obj);    // 20
```
第三種即下面例子提到的,體現(xiàn)了this由運行時調(diào)用位置的特點:
```JavaScript
function sayHello () {
    console.log( this === window );
    console.log( this === obj);
}
var obj = {
    sayHello: sayHello
};
sayHello();    // false  true
```

# 特殊情況
考慮到新版的ECMAscript6標(biāo)準(zhǔn)已經(jīng)發(fā)布,其應(yīng)用范圍正在飛速擴(kuò)大。雖然瀏覽器的支持度不是太好,隨著babel的橫空出世,眾多的開發(fā)人員在日常開發(fā)中都已經(jīng)在享受最新版JavaScript帶來的樂趣。如果你是一名前端開發(fā)人員,我強(qiáng)烈建議你在日常開發(fā)中將babel加入你的工作流技術(shù)棧。
新版的JavaScript引入了箭頭函數(shù)() => {};使創(chuàng)建匿名函數(shù)更加簡潔。尤其要注意一點的是,this在這里的指向在其書寫定義的時候就已經(jīng)確定了:
```JavaScript
var sayHello = () => {
    console.log( this === window );
    console.log( this === obj );
};
var obj = {
    sayHello: sayHello
};
obj.sayHello();    // true false
```

# 總結(jié)
> 技術(shù)日新月異,不變的是那些經(jīng)常被腦殘瞧不起的最簡單、最基本的東西。
> -- Kai Zou

# 說明
本人所有文章不間斷更新,除非哪天我不做前端了(基本不可能^_^)。另外本人能力有限,疏漏支出在所難免。如果你對其中某處有不同的看法,歡迎留言討論。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 沒搞錯吧!js寫了那么多年,this還是會搞錯!沒搞錯,javascript就是回搞錯! ………… 在寫java的...
    zhoulujun閱讀 1,499評論 0 11
  • 導(dǎo)語 不得不說,作為一名初級的前端開發(fā)者,this關(guān)鍵字這個問題對于我來說一直是一個痛點,什么是this?什么是函...
    Nicole_tiny閱讀 627評論 0 4
  • 周末重病患者回家了,晚上吃完藥直接昏睡(其實是最近的常態(tài)) 整理了一下當(dāng)日小事~
    wutacooper閱讀 192評論 0 0
  • 今天,老師在QQ群里發(fā)了一個熊孩子的故事一個中國熊孩子在坐飛機(jī)的時候把日本小哥弄得很煩惱,最后下了飛機(jī)他們被國家安...
    寂寞的時光者閱讀 319評論 0 0
  • 前段時間在知乎上有一個特別火的問題“為什么現(xiàn)在很多年輕人愿意到北上廣深打拼,即使過得異常艱苦,遠(yuǎn)離親人,仍然義無反...
    悠哉的惆悵閱讀 140評論 0 0

友情鏈接更多精彩內(nèi)容