天天看點

JavaScript深入之call和apply的模拟實作

一句話介紹 call:

call() 方法在使用一個指定的 this 值和若幹個指定的參數值的前提下調用某個函數或方法。

舉個例子:

注意兩點:

call 改變了 this 的指向,指向到 foo

bar 函數執行了

那麼我們該怎麼模拟實作這兩個效果呢?

試想當調用 call 的時候,把 foo 對象改造成如下:

這個時候 this 就指向了 foo,是不是很簡單呢?

但是這樣卻給 foo 對象本身添加了一個屬性,這可不行呐!

不過也不用擔心,我們用 delete 再删除它不就好了~

是以我們模拟的步驟可以分為:

将函數設為對象的屬性

執行該函數

删除該函數

以上個例子為例,就是:

fn 是對象的屬性名,反正最後也要删除它,是以起成什麼都無所謂。

根據這個思路,我們可以嘗試着去寫第一版的 call2 函數:

正好可以列印 1 哎!是不是很開心!(~ ̄▽ ̄)~

最一開始也講了,call 函數還能給定參數執行函數。舉個例子:

注意:傳入的參數并不确定,這可咋辦?

不急,我們可以從 Arguments 對象中取值,取出第二個到最後一個參數,然後放到一個數組裡。

比如這樣:

不定長的參數問題解決了,我們接着要把這個參數數組放到要執行的函數的參數裡面去。

也許有人想到用 ES6 的方法,不過 call 是 ES3 的方法,我們為了模拟實作一個 ES3 的方法,要用到ES6的方法,好像……,嗯,也可以啦。但是我們這次用 eval 方法拼成一個函數,類似于這樣:

這裡 args 會自動調用 Array.toString() 這個方法。

是以我們的第二版克服了兩個大問題,代碼如下:

(๑•̀ㅂ•́)و

模拟代碼已經完成 80%,還有兩個小點要注意:

1.this 參數可以傳 null,當為 null 的時候,視為指向 window

雖然這個例子本身不使用 call,結果依然一樣。

2.函數是可以有傳回值的!

不過都很好解決,讓我們直接看第三版也就是最後一版的代碼:

到此,我們完成了 call 的模拟實作,給自己一個贊 b( ̄▽ ̄)d

apply 的實作跟 call 類似,在這裡直接給代碼,代碼來自于知乎 @鄭航的實作:

繼續閱讀