好程式設計師Web前端培訓分享如何講清楚this指向?
好程式設計師Web 前端培訓分享 如何講清楚this 指向?不得不說,要搞清楚 this 是需要一個前提的。
你首先得知道函式、物件、作用域等基本概念。
知道 call 、 apply 、 bind 方法那再好不過了
當然學好語文是很重要的
需要知道第一人稱和第二人稱和第三人稱的區別
先來看一個新聞:
“我體內的惡魔已被鎖住了這麼多年,現在這種鎖鏈已經鬆了。”
“我很害怕,很孤獨,很疑惑,我將要嚮導致我的痛苦的根源——社會作出反擊,我想盡我所能地去傷害這個社會,然後死去。”
這段令人不寒而慄的文字,是美國北達科他州系列殺人案嫌犯約瑟夫·鄧肯於2005年5月11日寫下的。當人們在近兩個月後看到這段文字時,他已經將一個 5口之家的3人殘忍地殺害,並綁架了另外2名分別為8歲和9歲的孩子。
假設,你是一個jc
,抓到了一個xf
然後你在他的家裡搜出這本日記,此時你作何感想?
你肯定會想,如果這是嫌疑人自己寫的,這不就等於認罪了嘛?
當然,犯罪嫌疑人也可以狡辯說,這日記根本不是我寫的,只是我從網上摘抄的段子
我們試著把日記稍作改動,看看會有什麼效果變化。
他 體內的惡魔已被鎖住了這麼多年,現在這種鎖鏈已經鬆了。 他 很害怕,很孤獨,很疑惑, 他 將要嚮導致 他 的痛苦的根源——社會作出反擊, 他 想盡 他 所能地去傷害這個社會,然後死去。
注意到了嗎?
把第一人稱改成了第三人稱
這看上去根本不像日記,更像是一個小說故事。
為什麼一個字的改動會有這麼大差別呢?
帶著對這個問題的思考, 我們來開始今天this指向的學習 。
this的英文含義
先看英文解釋 this: 這樣、這個
接下來看一段程式碼
var obj = {
show : function(){
console.log( this);
}}obj.show();
結果很容易預測,列印 obj 物件本身
在JS中,this屬於一個關鍵字,也就是可以理解為,它是一個系統自帶命令
通常,我們把它的含義解釋為: 當前物件
那麼問題來了: 當前物件到底是指誰呢?
在上面的程式碼案例中,this代表的就是obj這個物件
接下來我們再看一段程式碼
function show(){
console.log( this);}show();
結果列印window物件
如果你對這個列印結果感到奇怪,那麼可能你忽略了一個常識問題
window物件是可以省略不寫的!
所以,上面的程式碼,實際上等價於:
function show(){
console.log( this);}window.show();
我再舉一個常見的例子,關於事件繫結
btn.onclick = function(){
console.log( this);}btn.onclick(); //手動呼叫函式//除手動呼叫外,滑鼠單擊按鈕也可以觸發函式執行
最終,無論是手動呼叫,還是單擊按鈕呼叫
列印結果都是btn物件
我們似乎總結出了一個this指向的規律
this總是指向,呼叫該函式的物件
如果你的程式碼結構是這樣的
物件.函式();
那麼,函式里的this,必然指向這個物件本身!
假設這個結論是成立的, 我們不妨來驗證一下我們的猜想!!
function show(){
console.log( this);}window.show(); //列印window物件 var obj1 = {};obj1.show1 = show;obj1.show1(); //列印obj1物件 var obj2 = {};obj2.show2 = obj1.show1;obj2.show2(); //列印obj2物件
從上面程式碼的例子中,可以看出來
window 物件和 obj1 物件和 obj2 物件,共享了一個函式 show
window.show == obj1.show1; //truewindow.show == obj2.show2; //true
三個物件,用了同一個函式
但列印出的this是各不相同的
window.show(); 列印出window物件
obj1.show1(); 列印出obj1物件
obj2.show2(); 列印出obj2物件
這似乎再一次印證了,我們剛才的猜想:
函式由哪個物件呼叫,this就指向哪個物件
科學是嚴謹的,得出結論之前,我們還是要反覆驗證
再看一個例子:
btn.onclick = function(){
setTimeout( function(){
console.log( this);
},0)}btn.onclick();
實際上,我只是在原來程式碼的基礎上,增加了一個延遲器,並且時間設為0
那麼列印出的this會不會有變化呢??
你可以先思考一番
通常按照直覺,我們會認為,延遲器只是延緩了執行時間,列印結果依然還是btn物件,沒有變化
但經過測試發現,實際的列印結果,是 window 物件
是我們剛才的猜想錯了嗎?
要解釋這個現象,我們得重新來觀察這段程式碼
btn.onclick = function(){ //<----這個函式,用A來表示 setTimeout( function(){ //<----這個函式,用B來表示 console.log( this);
},0)}btn.onclick();
注意程式碼當中出現了兩個函式,我們分別起名字叫做 函式A 和 函式B
按照我們剛才的猜想: 函式由哪個物件呼叫,this就指向哪個物件
所以,this指向會依賴它所在的函式
而這個函式,到底是 函式 A 還是函式 B 呢?
其實你不難從程式碼中看的出來, this很明顯是在函式 B 中的
所以, 結果沒有列印出 btn , 現在我們也不感到奇怪了
因為, this 已經不再函式 A 的內部了,而是函式 B 的內部
你可能還要問,為什麼函式 B 裡的 this指向window呢?
這裡其實算是一個特例,傳入定時器的函式,由哪個物件呼叫,我們不得而知
這種情況, this 就指向 window
你暫時記住這個規律就好了,等你學完了作用域鏈,你就會明白其中的本質
回到我們開頭的新聞
假設日記就是嫌疑人寫的。 但日記裡全是第三人稱。那麼 『 他 』到底是誰就很難說了
反過來如果日記裡用的都是第一人稱寫的。 那麼 『 我 』肯定指的是嫌疑人自己
JS函式當中的 this 關鍵字, 就相當於我們說話中的第一人稱代詞我
例如這樣一個例子:
A對B說:“我要殺了你!”
這裡的『我』指代 A , 『你』指代 B
B對A說:”我要弄死你!”
這裡的『我』指代 B , 『你』指代 A
所以你看,同樣的一個字,它可以指代任何人,關鍵看從誰的嘴裡說出來
function fn(){
//this, 就相當於中文裡的我 //不要上來就問this會指向誰 //我們必須搞清楚上下文環境,fn是誰呼叫的?(相當於這句話從誰的嘴裡說出來) //如果我們不能弄清楚這個問題,討論this指向就沒有意義 console.log( this);}
到目前為止,我們差不多可以得出結論了
下面用幾個練習最終驗證一下
var obj = {
show : function(){
console.log( this);
}}
上面的程式碼,最終列印
obj
物件
無論經過多少曲折,我們最終只看一個結論,那就是:
this所在的函式,由哪個物件呼叫?
我把程式碼進一步改造
function fn(){
console.log( this);}
var obj = {
show : fn}
btn.onclick = function(){
window.setTimeout( function(){
obj.show();
}, 100);}
上面的程式碼,最終列印還是 obj 物件
當然了,也總會有一些例外情況, 比如下面這個:
function m1(){
function m2(){
console.log( this);
}
m2();}m1();
我們不禁要問,函式m2是由哪個物件呼叫的?
我們想盡了各種可能,最終發現都是錯的。
我們始終不知道這個m2由哪個物件呼叫,好像它就那樣執行了
而實際的列印結果呢?
不出意外,還是 window 物件
最後的結論
1. 所有的this關鍵字,在函式執行時,才能確定它的指向
2. this所在的函式由哪個物件呼叫,this就會指向誰
3. 當函式執行時,沒有明確的呼叫物件時,則this指向window
由this衍生出的問題
剛才遺留了一個問題沒有解決
btn.onclick = function(){
setTimeout( function(){
console.log( this);
},0)}btn.onclick();
我們期待 this 指向 btn ,而 this 現在卻指向了 window
這個問題該怎麼修復呢? 有很多辦法
如果你不知道 call、apply、bind ,那麼恐怕你只能看得懂方法 A
//方法Abtn.onclick = function(){
var self = this; //使用變數儲存this,self變數的值是不會隨著環境改變的 setTimeout( function(){
console.log(self);
},0)}btn.onclick();
//方法Bbtn.onclick = function(){
var self = this; //使用變數儲存this
function fn(){ //將程式碼寫在一個函式fn中 console.log( this);
}
setTimeout( function(){
fn.call(self); //強行指定this為self物件 },0)}btn.onclick(); /* call方法的作用,是呼叫函式,同時指定this可以代表誰 例如 fn.call(obj) 意思就是 呼叫函式fn,並且this指向obj物件*/
//方法Cbtn.onclick = function(){
var self = this; //使用變數儲存this
function fn(){ //將程式碼寫在一個函式fn中 console.log( this);
}
setTimeout( function(){
fn.apply(self); //使用apply方法呼叫函式,強行指定this為self物件 },0)}btn.onclick(); /* apply方法的作用,是呼叫函式,同時指定this可以代表誰 例如 fn.apply(obj) 意思就是 呼叫函式fn,並且this指向obj物件*/
//方法Dbtn.onclick = function(){
setTimeout( function(){
console.log( this);
}.bind( this), 0 )
//使用bind方法,將定時器函式的this強行繫結為事件函式的this}btn.onclick(); /* bind方法的作用,是繫結函式的this,同時返回繫結後的新函式 例如 var fb = fn.bind(obj); window.fb(); 無論誰呼叫fb函式, 函式的this都會指向obj*/
接下來的內容,請學完ES6的箭頭函式再來看吧
1. 如何判斷箭頭函式的this?
因為箭頭函式不具備自己的this,所以非常簡單,假裝它不存在,就像這樣:
這下this的指向非常清晰了吧
2. 箭頭函式可以用call來改變this指向嗎?
不能!! 試圖改變箭頭函式的this是徒勞的。
最後一個特例: 建構函式
1. 什麼是建構函式?
假設有一個函式Fn, 我們有兩種方式來呼叫它
- 普通的呼叫 Fn()
- 配合new 關鍵字來呼叫 new Fn()
第二種呼叫方式, 函式就變成了建構函式
---------------------------------------
注意,在建構函式中, 上面我們所講的結論,是不成立的!!
----------------------------------------
2. 那建構函式里的this是誰呢?
請期待下一篇文章《建構函式與class》
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69913864/viewspace-2690834/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 好程式設計師web前端培訓分享如何講清楚Promise?程式設計師Web前端Promise
- 好程式設計師web前端培訓分享如何講清楚async和await?程式設計師Web前端AI
- 好程式設計師web前端培訓分享JavaScript框架J程式設計師Web前端JavaScript框架
- 好程式設計師web前端培訓分享Vue面試題程式設計師Web前端Vue面試題
- 好程式設計師web前端培訓分享學習JavaScript程式設計師Web前端JavaScript
- 好程式設計師web前端培訓分享怎樣學好css?程式設計師Web前端CSS
- 好程式設計師web前端培訓分享JavaScript學習指南程式設計師Web前端JavaScript
- 好程式設計師Web前端培訓分享jQuery面試題梳理程式設計師Web前端jQuery面試題
- 好程式設計師web前端培訓分享HTML DOM節點程式設計師Web前端HTML
- 好程式設計師web前端培訓分享HTML DOM簡介程式設計師Web前端HTML
- 好程式設計師web前端培訓分享CSS定位的教程程式設計師Web前端CSS
- 好程式設計師web前端培訓分享Vue面試題1.程式設計師Web前端Vue面試題
- 好程式設計師web前端培訓分享九個JavaScript小技巧程式設計師Web前端JavaScript
- 好程式設計師web前端培訓分享JavaScript基礎語法程式設計師Web前端JavaScript
- 好程式設計師web前端培訓分享JavaScript相關知識程式設計師Web前端JavaScript
- 好程式設計師web前端培訓分享node學習筆記程式設計師Web前端筆記
- 好程式設計師web前端培訓分享FormData 簡單介紹程式設計師Web前端ORM
- 好程式設計師web前端培訓分享HTML/CSS部分面試題程式設計師Web前端HTMLCSS面試題
- 好程式設計師web前端培訓分享Javascript中原型屬性程式設計師Web前端JavaScript原型
- 好程式設計師web前端培訓分享kbone高階-事件系統程式設計師Web前端事件
- 好程式設計師web前端培訓分享HTMLCSS學習筆記BFC程式設計師Web前端HTMLCSS筆記
- 好程式設計師web前端培訓分享JavaScript學習筆記Promise程式設計師Web前端JavaScript筆記Promise
- 好程式設計師web前端培訓分享JS面試題總結一程式設計師Web前端JS面試題
- 好程式設計師web前端培訓分享JavaScript學習筆記SASS程式設計師Web前端JavaScript筆記
- 好程式設計師web前端培訓分享JavaScript學習筆記cookie程式設計師Web前端JavaScript筆記Cookie
- 好程式設計師web前端培訓分享React學習筆記(一)程式設計師Web前端React筆記
- 好程式設計師web前端培訓分享React學習筆記(二)程式設計師Web前端React筆記
- 好程式設計師web前端培訓分享React學習筆記(三)程式設計師Web前端React筆記
- 好程式設計師web前端培訓分享小白學web常見的問題程式設計師Web前端
- 好程式設計師web前端培訓分享JavaScript學習筆記之設計模式程式設計師Web前端JavaScript筆記設計模式
- 好程式設計師web前端培訓分享HTMLCSS之寬高自適應程式設計師Web前端HTMLCSS
- 好程式設計師web前端培訓分享HTMLCSS學習之CSS基礎程式設計師Web前端HTMLCSS
- 好程式設計師web前端培訓分享HTMLCSS之HTML表單標籤程式設計師Web前端HTMLCSS
- 好程式設計師web前端培訓分享CSS基礎知識學習程式設計師Web前端CSS
- 好程式設計師web前端培訓分享如何用js檢測瀏覽器型別程式設計師Web前端JS瀏覽器型別
- 好程式設計師HTML5前端培訓分享如何學好HTML5程式設計師HTML前端
- 好程式設計師web前端培訓分享JavaScript學習筆記分支結構程式設計師Web前端JavaScript筆記
- 好程式設計師web前端培訓分享JavaScript學習筆陣列的排序程式設計師Web前端JavaScript陣列排序