javascript中關(guān)于對call()、apply()和bind()的一點理解

最開始對于這三者的概念不是很理解,通過查閱資料總算有點理解了,所以在這里記錄一下,有什么不對的地方歡迎指出。

1 定義:call()和apply()其實就是改變函數(shù)的執(zhí)行上下文(this的值),可以劫持另外一個對象的方法,繼承另外一個對象的屬性。他們兩是Function對象的方法,所以每個函數(shù)都能調(diào)用他們。

例如:Function.apply(obj,args)可以說是在obj里面去執(zhí)行Function里面的內(nèi)容。也就是Function的執(zhí)行主體變成了obj,改變函數(shù)的執(zhí)行上下文(this的值)。


2 區(qū)別:call()和apply()的意思是一樣的,不同的是參數(shù)列表不一樣,call的第二部分參數(shù)要一個一個傳,apply要把這些參數(shù)放到數(shù)組中。這就是他們的區(qū)別。

Function.apply(obj,args),F(xiàn)unction.call(obj,[param1[,param2[,…[,paramN]]]])

obj:這個對象將代替Function類里this對象

params:這個是一個參數(shù)列表


apply的一點小擴展:

①實現(xiàn)數(shù)組最大最小的一項??

? ? ? ? ? 因為Math.max 參數(shù)里面不支持Math.max([param1,param2]) 也就是數(shù)組

? ? ? ? ? 所以可以使用Math.max.apply(null,array)或Math.min.apply(null,array)得到數(shù)組最大最小的一項

②可以實現(xiàn)兩個數(shù)組合并

? ? ? ? vararr1=new Array("1","2","3");

? ? ? ? vararr2=new Array("4","5","6");

? ? ? ? Array.prototype.push.apply(arr1,arr2);

③一個數(shù)組插入另一個數(shù)組的指定位置

? ? ? ?var arr1 = ['a', 'b', 'c'];

? ? ? ?var arr2?=?['1',?'2',?'3'];

? ? ? ?arr2.unshift(2,?0);

? ? ? ?Array.prototype.splice.apply(arr1,?arr2);

? ? ? ?console.log(arr1);


3、下面來講bind()函數(shù),bind()是es5中的方法,它也是用來實現(xiàn)上下文綁定,但與bind()和call與apply不同。bind是新創(chuàng)建一個函數(shù),然后把它的上下文綁定到bind()括號中的參數(shù)上,然后將它返回。所以,bind后函數(shù)不會執(zhí)行,而只是返回一個改變了上下文的函數(shù)副本,而call和apply是直接執(zhí)行函數(shù)。

下面代碼可以反映出這點,而且也顯示了bind的用法(后面的代碼皆取自張鑫旭大神的博客)

var button = document.getElementById("button"),? ? text = document.getElementById("text");button.onclick = function() {? ? alert(this.id);// 彈出text}.bind(text);

但由于ie6~ie8不支持該方法,所以若想在這幾個瀏覽器中使用,我們就要模擬該方法,這也是面試??嫉膯栴},模擬的代碼如下:

if (!function() {}.bind) {

Function.prototype.bind = function(context) {

var self = this

, args = Array.prototype.slice.call(arguments);

return function() {

return self.apply(context, args.slice(1));

}

};

}

就是這段代碼,糾正了我長久以來的一個誤區(qū)。下面來講一下這段代碼

首先,我們判斷是否存在bind方法,然后,若不存在,向Function對象的原型中添加自定義的bind方法。

這里面var self = this這段代碼讓我很困擾,按理說,prototype是一個對象,對象的this應(yīng)該指向?qū)ο蟊旧?,也就是prototype,但真的是這樣嗎。看看下面的代碼:

function a(){};

a.prototype.testThis = function(){console.log(a.prototype == this);};

var b = new a();

b.testThis();//false

顯然,this不指向prototype,而經(jīng)過測試,它也不指向a,而指向b。所以原型中的this值就明朗了。指向調(diào)用它的對象。

Array.prototype.slice.call(arguments);

接下來就是上面這段代碼,它會將一個類數(shù)組形式的變量轉(zhuǎn)化為真正的數(shù)組。為啥呢,其實書上并沒有說slice還有這樣的用法,也不知道是誰發(fā)明的。slice的用法可以順便上網(wǎng)查一下,就能查到。但要更正一點,網(wǎng)上的介紹說slice有兩個參數(shù),第一個參數(shù)不能省略。然而我不知道是我理解的問題還是咋地,上面這段代碼tmd不就是典型的沒傳參數(shù)嗎?。。rguments是傳給call的那個上下文,前面講過,不要弄混(由于arguments自己沒有slice方法,這里屬于借用Array原型的slice方法)。而且經(jīng)過測試,若果你不給slice傳參數(shù),那就等于傳了個0給它,結(jié)果就是返回一個和原來數(shù)組一模一樣的副本。

這之后的代碼就很好理解,返回一個函數(shù),該函數(shù)把傳給bind的第一個參數(shù)當做執(zhí)行上下文,由于args已經(jīng)是一個數(shù)組,排除第一項,將之后的部分作為第二部分參數(shù)傳給apply,前面講過apply的用法。

如此,我們自己的這個bind函數(shù)的行為就同es5中的bind一樣了。


總結(jié):call和apply都是改變上下文中的this并立即執(zhí)行這個函數(shù),bind方法可以讓對應(yīng)的函數(shù)想什么時候調(diào)就什么時候調(diào)用,并且可以將參數(shù)在執(zhí)行的時候添加,這是它們的區(qū)別,根據(jù)自己的實際情況來選擇使用。

最后編輯于
?著作權(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)容

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