tft每日頭條

 > 生活

 > this 參數

this 參數

生活 更新时间:2024-11-21 00:27:52

不得不說,要搞清楚this是需要一個前提的。

你首先得知道函數、對象、作用域等基本概念。

知道 call、apply、bind方法那再好不過了

當然學好語文是很重要的

需要知道第一人稱和第二人稱和第三人稱的區别

this 參數(如何講清楚this指向)1

先來看一個新聞:

“我體内的惡魔已被鎖住了這麼多年,現在這種鎖鍊已經松了。”“我很害怕,很孤獨,很疑惑,我将要向導緻我的痛苦的根源——社會作出反擊,我想盡我所能地去傷害這個社會,然後死去。”

這段令人不寒而栗的文字,是美國北達科他州系列殺人案嫌犯約瑟夫·鄧肯于2005年5月11日寫下的。當人們在近兩個月後看到這段文字時,他已經将一個 5口之家的3人殘忍地殺害,并綁架了另外2名分别為8歲和9歲的孩子。

假設,你是一個警察,抓到了一個嫌疑犯然後你在他的家裡搜出這本日記,此時你作何感想?

你肯定會想,如果這是嫌疑人自己寫的,這不就等于認罪了嘛?

當然,犯罪嫌疑人也可以狡辯說,這日記根本不是我寫的,隻是我從網上摘抄的段子

我們試着把日記稍作改動,看看會有什麼效果變化。

體内的惡魔已被鎖住了這麼多年,現在這種鎖鍊已經松了。很害怕,很孤獨,很疑惑,将要向導緻的痛苦的根源——社會作出反擊,想盡所能地去傷害這個社會,然後死去。

注意到了嗎?

把第一人稱改成了第三人稱

這看上去根本不像日記,更像是一個小說故事。

為什麼一個字的改動會有這麼大差别呢?

帶着對這個問題的思考, 我們來開始今天this指向的學習。

this 參數(如何講清楚this指向)2

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; //true window.show == obj2.show2; //true

三個對象,用了同一個函數

但打印出的this是各不相同的

window.show(); 打印出window對象

obj1.show1(); 打印出obj1對象

obj2.show2(); 打印出obj2對象

這似乎再一次印證了,我們剛才的猜想:

函數由哪個對象調用,this就指向哪個對象

this 參數(如何講清楚this指向)3

科學是嚴謹的,得出結論之前,我們還是要反複驗證

再看一個例子:

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

//方法A btn.onclick = function(){ var self = this; //使用變量保存this,self變量的值是不會随着環境改變的 setTimeout(function(){ console.log(self); },0) } btn.onclick();

//方法B btn.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對象 */

//方法C btn.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對象 */

//方法D btn.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 參數(如何講清楚this指向)4

這下this的指向非常清晰了吧

2. 箭頭函數可以用call來改變this指向嗎?

不能!! 試圖改變箭頭函數的this是徒勞的。

this 參數(如何講清楚this指向)5


最後一個特例:構造函數

1. 什麼是構造函數?

假設有一個函數Fn, 我們有兩種方式來調用它

  • 普通的調用 Fn()
  • 配合new關鍵字來調用 new Fn()

第二種調用方式, 函數就變成了構造函數

---------------------------------------

注意,在構造函數中, 上面我們所講的結論,是不成立的!!

----------------------------------------

2. 那構造函數裡的this是誰呢?

請期待下一篇文章《構造函數與class》

,

更多精彩资讯请关注tft每日頭條,我们将持续为您更新最新资讯!

查看全部

相关生活资讯推荐

热门生活资讯推荐

网友关注

Copyright 2023-2024 - www.tftnews.com All Rights Reserved