詳解JavaScript中的this硬綁定
一、this顯示綁定
this顯示綁定,顧名思義,它有別于this的隱式綁定,而隱式綁定必須要求一個(gè)對(duì)象內(nèi)部包含一個(gè)指向某個(gè)函數(shù)的屬性(或者某個(gè)對(duì)象或者上下文包含一個(gè)函數(shù)調(diào)用位置),并通過(guò)這個(gè)屬性間接調(diào)用這個(gè)函數(shù),從而把this簡(jiǎn)介/隱式綁定到這個(gè)對(duì)象上。但是this的隱式綁定存在一個(gè)綁定對(duì)象丟失問(wèn)題,如下面代碼所示:
function afun() { console.log(this.a); } var obj = { a: 1, afun: afun }; var a = "hello"; setTimeout(obj.afun, 100);//"hello"
出人意料的是,控制臺(tái)打印出來(lái)的結(jié)果是全局變量a的結(jié)果,而不是擁有指向函數(shù)屬性的對(duì)象的a的值,這就是隱式綁定的對(duì)象丟失,回調(diào)函數(shù)丟失綁定對(duì)象是非常常見(jiàn)的。
但是,顯示綁定仍然不能解決綁定對(duì)象丟失的問(wèn)題,但是顯示綁定的一個(gè)變種,即硬綁定可以解決綁定對(duì)象丟失。
在此之前,我們先來(lái)看看什么是顯示綁定。
我們可以通過(guò)使用函數(shù)的call()和apply()方法實(shí)現(xiàn)this顯示綁定,絕大多數(shù)內(nèi)置函數(shù)和自定義函數(shù)都可以調(diào)用這兩種方法。他們均接收兩個(gè)參數(shù)
參數(shù):
thisArg
: 要綁定到調(diào)用者this的對(duì)象。
arg1, arg2, ...
(call):指定的參數(shù)列表,即要傳給調(diào)用者的參數(shù)。比如a.call(obj, args)/a.apply(obj, args),args為參數(shù)傳給調(diào)用者函數(shù)a作為該函數(shù)的實(shí)參。
argsArray
(apply):一個(gè)數(shù)組或者類數(shù)組對(duì)象,如果該參數(shù)的值為 null 或 undefined,則表示不需要傳入任何參數(shù)。
返回值
:調(diào)用者函數(shù)若有返回值則返回該值,沒(méi)有返回值則返回undefined。
來(lái)看下面的代碼:
function bfun() { return this.a; } var obj1 = { a: "hello" }; console.log(bfun.apply(obj1), bfun.call(obj1));//"hello" "hello"
若傳入的第一個(gè)參數(shù)時(shí)一個(gè)原始值呢?來(lái)看下面的代碼:
function bfun() { return this; } console.log(bfun.apply(3));//[Number: 2]
沒(méi)錯(cuò),原始值被轉(zhuǎn)換成了它的對(duì)象形式,也就是new Number(),這被成為"裝箱"。
但是,我們前面提到過(guò),this顯示綁定雖然強(qiáng)大,但是仍然不能解決this綁定丟失問(wèn)題。下面我們來(lái)解釋硬綁定,即顯示綁定的一個(gè)變種,它能完美解決this綁定丟失問(wèn)題。
二、硬綁定
先來(lái)看看下面的代碼:
function cfun() { console.log(this.a)//"hello" return this.a; } var obj2 = { a: "hello" }; var fn = function() { return cfun.apply(obj2); }; console.log(fn());//"hello" setTimeout(fn, 100);//"hello"
可以看到,硬綁定確實(shí)解決了this綁定丟失,但值得注意的是,通過(guò)apply()綁定的this對(duì)象,無(wú)法二次更改綁定對(duì)象:
function f() { console.log( this.a ); } var obj = { a:2 }; var b = function() { f.call( obj ); }; b(); // 2 b.call( window ); // 2
硬綁定的一個(gè)典型應(yīng)用場(chǎng)景是創(chuàng)建一個(gè)包裹函數(shù),傳入所有的參數(shù)給調(diào)用者函數(shù)并返回接收到的所有值。
function dfun(v) { return (v[0] + this.a); } var obj3 = { a: 10 }; var fn1 = function() { return dfun.call(obj3, arguments); } var result = fn1(6); console.log(result);//16
對(duì)于arguments而言,call()和apply()的不同之處在于他們的參數(shù)類型不同:
function efun(v) { console.log(..v)//6 10 11 return (v); } var obj4 = { a: 10 }; var fn1 = function() { return efun.apply(obj3, arguments); } var result = fn1([6, 10, 11]); console.log(result);//[6, 10, 11]
也就是說(shuō)call()的參數(shù)類型是Object,它傳入的參數(shù)列表會(huì)被轉(zhuǎn)換為鍵為'0'(隨傳入?yún)?shù)數(shù)量遞增),值為傳入?yún)?shù)的對(duì)象;而apply()的參數(shù)類型則是數(shù)組或者類數(shù)組。
function dfun(v) { return (v); } var obj3 = { a: 10 }; var fn1 = function() { return dfun.call(obj3, arguments); } var result = fn1(6, 19, 1, 1); console.log(result);//[Arguments]{'0':6,'1':19,2':1,3':1} console.log(typeof result);//'object'
最強(qiáng)大的一種方法是將包裹函數(shù)創(chuàng)建為可以重復(fù)使用的輔助函數(shù),封裝可重復(fù)使用的硬綁定。
function ffun(v) { return this.a * v; } var obj5 = { a: 5, }; var fn2 = function(fn, obj) { return function() { return fn.apply(obj, arguments); } } var bind = fn2(ffun, obj5); console.log(bind(10));//50
由于硬綁定十分常用,但通過(guò)包裹函數(shù)創(chuàng)建可重復(fù)使用的硬綁定比較麻煩,所以ES5提供了一個(gè)實(shí)現(xiàn)相同功能的方法bind()。用法如下:
function hfun(v) { return this.a * v; } var obj6 = { a: 6 }; var bind = hfun.bind(obj6); console.log(bind(4));//24
可以看到,我們?cè)贌o(wú)需構(gòu)建一個(gè)包裹函數(shù)來(lái)手動(dòng)調(diào)用call或apply方法,只需要提供調(diào)用者和綁定到調(diào)用者this的對(duì)象即可。
我們可能發(fā)現(xiàn)了一個(gè)奇怪的現(xiàn)象,通過(guò)apply()和call()方法綁定的對(duì)象在傳參給調(diào)用者時(shí),需要設(shè)置一個(gè)參數(shù)占位,但bind()方法則不用,這是因?yàn)樗麄兊姆祷刂挡煌?,bind()方法會(huì)返回一個(gè)經(jīng)過(guò)硬編碼的新函數(shù),它會(huì)把傳入?yún)?shù)設(shè)置為this的上下文并調(diào)用原始函數(shù)??梢岳斫鈈ind使用方法為bind(obj)(args)
。而對(duì)于call()和apply()方法而言,一旦調(diào)用此方法,就會(huì)立刻返回調(diào)用者函數(shù)的返回值,所以此時(shí)就需要同時(shí)傳入?yún)?shù)給方法的參數(shù)占用符,然后被函數(shù)參數(shù)讀取。值得注意的是,bind方法的參數(shù)和call方法類似。
到此這篇關(guān)于詳解JavaScript中的this硬綁定 的文章就介紹到這了,更多相關(guān)JavaScript this硬綁定 內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Flexigrid在IE下不顯示數(shù)據(jù)的處理的解決方法
Flexigrid在IE下不顯示數(shù)據(jù)的情況,想必大家都有遇到過(guò)吧,下面有個(gè)不錯(cuò)的解決方法,感興趣的朋友可以參考下2013-10-10javascript dom操作之cloneNode文本節(jié)點(diǎn)克隆使用技巧
文本克隆函數(shù)cloneNode他有兩個(gè)參數(shù)——true or false2009-12-12uniapp如何實(shí)現(xiàn)tabBar之間傳參
這篇文章主要給大家介紹了關(guān)于uniapp如何實(shí)現(xiàn)tabBar之間傳參的相關(guān)資料,文中通過(guò)代碼示例介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2023-08-08BootStrap 智能表單實(shí)戰(zhàn)系列(二)BootStrap支持的類型簡(jiǎn)介
這篇文章主要介紹了BootStrap 智能表單實(shí)戰(zhàn)系列(二)BootStrap支持的類型簡(jiǎn)介 的相關(guān)資料,非常不錯(cuò)具有參考借鑒價(jià)值,感興趣的朋友一起學(xué)習(xí)吧2016-06-06基于Bootstrap table組件實(shí)現(xiàn)多層表頭的實(shí)例代碼
Bootstrap table還有一個(gè)很多強(qiáng)大的功能,下面就通過(guò)本文給大家分享基于Bootstrap table組件實(shí)現(xiàn)多層表頭的實(shí)例代碼,需要的朋友參考下吧2017-09-09JavaScript forEach的幾種用法小結(jié)
forEach()是JavaScript中一個(gè)常用的方法,用于遍歷數(shù)組或類數(shù)組對(duì)象中的每個(gè)元素,本文就來(lái)介紹一下JavaScript forEach的幾種用法小結(jié),具有一定的參考價(jià)值,感興趣的可以了解一下2023-11-11js實(shí)現(xiàn)按鈕控制圖片360度翻轉(zhuǎn)特效的方法
這篇文章主要介紹了js實(shí)現(xiàn)按鈕控制圖片360度翻轉(zhuǎn)特效的方法,涉及HTML5中canvas方法的使用技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-02-02