JavaScript當中的this究竟是個啥?
對於JS的初學者而言,JS當中的this指向很難讓人摸準其脈絡,經常會給你一種模糊美、朦朧美的感腳!因為this並不是固定不變的,它會根據自身所執行的環境的不同而不同。而且在開發的過程中,經常因為對this的不瞭解出現這樣或那樣的錯誤!所以搞定this的指向是非常非常有必要的!
與其它語言當中的this不同的是,我們JS當中的this總是指向一個物件。而具體是指向哪一個物件,則要看其執行時是基於哪一個函式的執行環境所動態繫結的。
注意:this的指向並不是函式被宣告時的環境。
具體到實際開發中,this的指向大致可以分為以下幾種:
1、作為普通函式呼叫
當你的函式不是作為物件的屬性來呼叫時,即是我們經常說的普通函式呼叫。此時的this為全域性物件,而JS當中的全域性物件指的是window。
作為普通物件呼叫:
//定義一個全域性變數agevar age=18;//宣告一個全域性函式getAgefunction getAge(){ return this.age; }//因為是全域性環境內呼叫的getAget函式所以指向的物件為windowconsole.log(getAge());//18//你也可以這樣寫console.log(window.getAge());//18
以上程式碼中,getAge方法在全域性window下呼叫,所以getAge方法內的this指向的是window。為了更好的驗證這一點,我們們再來對以上程式碼修改如下:
//宣告一個全域性函式getAgefunction getAge(){ //由於該函式在全域性環境(window)下呼叫,所以this為window this.age=81;//為this指向的window物件新增屬性age} getAge();//全域性呼叫函式getAge()console.log(age);//81//也可以這樣輸出console.log(window.age);//81
以上程式碼中宣告瞭一個全域性函式getAge。由於該函式在全域性環境(window)下呼叫,所以this為window。然後透過this.age為window物件增加一個age屬性。所以在呼叫完該函式後進行console.log(window.age)輸出的結果為81。
2、函式作為物件的屬性來呼叫:
如果函式作為物件的屬性來呼叫,函式內的this為呼叫函式的物件。
var obj={ //obj屬性age age:12, //obj方法getAge getAge:function(){ return this.age; } }//全域性屬性agevar age=13;//全域性方法getAgefunction getAge(){ return this.age; }//在obj物件下呼叫getAge(),this代表的是objconsole.log(obj.getAge());//12
在全域性環境下,this代表的是window。所以調取的方法為全域性方法getAge。又因為getAge是在window下呼叫的,所以內部this指向的是window物件。最終輸出結果為13
var obj={ //obj屬性age age:12, //obj方法getAge getAge:function(){ return this.age; } }//全域性屬性agevar age=13;//全域性方法getAgefunction getAge(){ return this.age; }//在全域性環境下,this代表window,所以下面可以理解為window物件下呼叫全域性getAgeconsole.log(this.getAge());//13
接下來看種丟失掉this的情況,換言之,this的指向發生改變。我們先來看下面的程式碼
var obj={ //obj屬性age age:12, //obj方法getAge getAge:function(){ return this.age; } }//全域性屬性agevar age=13;//全域性方法getAgefunction getAge(){ return this.age; }//在obj物件下呼叫getAge(),this代表的是objconsole.log(obj.getAge());//12//將obj下的函式getAge賦值給fn。var fn=obj.getAge;//在全域性環境(window) 下呼叫fn,this代表的是windowconsole.log(fn());//13
當呼叫obj.getAge時,getAge方法是作為obj物件的屬性來呼叫的。輸出結果為12。當將obj.getAge賦值給一個變數fn時,因為fn的呼叫是在全域性環境下呼叫的,所以this指向的是window,輸出結果為13。
將程式碼彙總如下,認真看看:
var obj={ //obj屬性age age:12, //obj方法getAge getAge:function(){ return this.age; } }//全域性屬性agevar age=13;//全域性方法getAgefunction getAge(){ return this.age; }//在obj物件下呼叫getAge(),this代表的是objconsole.log(obj.getAge());//12//在全域性環境下,this代表window,所以下面可以理解為window物件下呼叫全域性getAgeconsole.log(this.getAge());//13//將obj下的函式getAge賦值給fn。var fn=obj.getAge;//在全域性環境(window) 下呼叫fn,this代表的是windowconsole.log(fn());//13
3、DOM物件的事件函式
DOM物件的事件函式內的this指向的是該DOM物件,看以下程式碼:
點我吧!
在事件函式內新增一個子函式_fn,該子函式內的this指向的是window:
點我吧!
但往往我們需要的是讓它指向觸發事件的DOM物件,此時有一種解決方法可以作為參考:
點我吧!
4、建構函式
在JS當中並沒有類的概念,但是我們可以透過建構函式來建立物件,而且JS也提供了new運算子,使建構函式看起來更像是一個類!
建構函式與普通函式的異同:建構函式與普通函式的個表是一樣的,它們的區別在於調取的方式。當用new運算子呼叫函式時,該函式為建構函式,否則為普通函式。
function Box(){ this.age=14; }var obj=new Box();console.log(obj.age);//14
透過new來呼叫建構函式時的執行流程如下:
new 建構函式(),隱式執行了new Object();
將建構函式的作用域給新物件(即new Object()建立出的物件),函式體內的this就代表這個新物件。
執行建構函式的語句。
隱式直接返回新物件。
需要注意的是建構函式如果直接返回一個物件,那麼執行返回的物件就不是我們所期待的this:
function Box(){ this.age=14; return { age:16 } }var obj=new Box();console.log(obj.age);//16
5、透過call與apply改變this的指向
透過call與apply可以動態的改變函式內的this
//宣告一個全域性變數colorvar color="red";//宣告一個全域性物件obj,為 obj新增一個屬性color值為yellowvar obj= { color: "yellow"}//新增一個建構函式function Fn(){ this.color="blue"; }//普通函式function getColor(){ console.log(this.color); } getColor();//redgetColor.call(window);//redgetColor.call(this);//redgetColor.call(obj);//yellowgetColor.call(new Fn());//blue
以上程式碼透過call來改變函式體內this的指向,以上程式碼用apply也是可以實現相同的功能。只需要將call改變apply即可:
var color="red";var obj= { color: "yellow"}function Fn(){ this.color="blue"; }function getColor(){ console.log(this.color); } getColor();//redgetColor.apply(window);//redgetColor.apply(this);//redgetColor.apply(obj);//yellowgetColor.apply(new Fn());//blue
call與apply的用法是一樣,區別僅在於傳入的引數形式不同。
var num=5;function fn(num1,num2){ console.log(num1+num2+this.num); }var obj={ num:8} fn.call(this,1,2);//8fn.call(obj,1,2);//11//apply 傳遞的引數需要用中括號進行包裹fn.apply(this,[3,4]);//12fn.apply(obj,[3,4]);//12
6、透過bind指定函式內部的this
var age=81;var obj={ age:18}//指定fn函式體內的this指向windowvar fn=function(){ console.log(this.age); }.bind(this);//指定fn2函式體內的this指向objvar fn2=function(){ console.log(this.age); }.bind(obj); fn();//81fn2();//18
好了,今天就先到這裡吧!
作者:張培躍
連結:
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/2331/viewspace-2813627/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Python 3.5 協程究竟是個啥Python
- 大廠偏愛的Agent技術究竟是個啥
- Java中的反射到底是個啥?Java反射
- 我們常討論的遊戲吸量和次日留存究竟是啥?遊戲
- Web開發者應當知道的5個JavaScript工具WebJavaScript
- 到底啥是JavaScript MockJavaScriptMock
- 每個Javascript開發者都應當知道的那些事JavaScript
- Linux驅動中的EPROBE_DEFER是個啥Linux
- 一分鐘乾貨告訴你區塊鏈究竟是啥?區塊鏈
- javascript獲取當前li元素在集合中的位置JavaScript
- 換個思路理解Javascript中的thisJavaScript
- Golang 中如何獲取當前路徑,它們之間有啥差異Golang
- javascript 分割字元後壓入陣列當中JavaScript字元陣列
- JavaScript中獲取當前專案的絕對路徑JavaScript
- 計算機中的流水線技術到底是個啥?計算機
- JavaScript獲取當前li元素是第幾個JavaScript
- Spring是個啥?Spring
- JavaScript 中 JSON 的 5 個小技巧?JavaScriptJSON
- JavaScript陣列中的22個常用方法JavaScript陣列
- javascript如何獲取當前選中的option項的文字和value值JavaScript
- JavaScript 6 裡都有啥新鮮東西?JavaScript
- 工作當中碰到的一個UTL_FILE的問題
- 深度學習當中的三個概念:Epoch, Batch, Iteration深度學習BAT
- 在安全管理的Hard模式中,當一個好“玩家”模式
- PHP最近的6個版本到底多了啥?PHP
- tslib 這個包做啥用的
- Python中的類、模組和包究竟是什麼?Python
- Webhook到底是個啥?WebHook
- 為啥iPhone和安卓手機都會當機卡頓?iPhone安卓
- JavaScript 中 try...catch 的 10 個使用技巧JavaScript
- javascript替換字串中的某個漢字JavaScript字串
- Java當中的JVMJavaJVM
- 生命是個軟體,我是個啥?
- 網站設計中應當避免的8個錯誤網站
- javascript獲取當前的時間戳JavaScript時間戳
- 訊息佇列究竟是個什麼鬼?佇列
- Node.js 中的緩衝區(Buffer)究竟是什麼?Node.js
- JavaScript 獲取當前月份JavaScript