使用JS簡單實現(xiàn)apply、call和bind方法的實例代碼
1.方法介紹
apply、call和bind都是系統(tǒng)提供給我們的內(nèi)置方法,每個函數(shù)都可以使用這三種方法,是因為apply、call和bind都實現(xiàn)在了Function的原型上(Function.prototype),而他們的作用都是給我們函數(shù)調(diào)用時顯式綁定上this。下面先介紹一下它們的基本用法:
apply方法:調(diào)用一個具有給定this值的函數(shù),以及以一個數(shù)組(或類數(shù)組對象)的形式提供的參數(shù)。
使用語法:func.apply(thisArg, [argsArray])
thisArg:在func函數(shù)調(diào)用時綁定的this值;[argsArray]:一個數(shù)組或者類數(shù)組對象,其中的數(shù)組元素將作為單獨的參數(shù)傳給func函數(shù);
使用效果:
function foo(x, y ,z) { console.log(this, x, y, z) } const obj = { name: 'curry', age: 30 } /** * 1.將obj對象綁定給foo函數(shù)的this * 2.數(shù)組中的1 2 3分別傳遞給foo函數(shù)對應(yīng)的三個參數(shù) */ foo.apply(obj, [1, 2, 3])
call方法:使用一個指定的 this值和單獨給出的一個或多個參數(shù)來調(diào)用一個函數(shù)。
使用語法:func.call(thisArg, arg1, arg2, ...)
thisArg:在func函數(shù)調(diào)用時綁定的this值;arg1, arg2, ...:指定的參數(shù)列表,將作為參數(shù)傳遞給func函數(shù);
使用效果:
function foo(x, y ,z) { console.log(this, x, y, z) } const obj = { name: 'curry', age: 30 } /** * 1.將obj對象綁定給foo函數(shù)的this * 2.call剩余參數(shù)中的a b c分別傳遞給foo函數(shù)對應(yīng)的三個參數(shù) */ foo.call(obj, 'a', 'b', 'c')
bind方法:創(chuàng)建一個新的函數(shù),在bind()被調(diào)用時,這個新函數(shù)的this被指定為bind()的第一個參數(shù),而其余參數(shù)將作為新函數(shù)的參數(shù),供調(diào)用時使用。
使用語法:func.bind(thisArg[, arg1[, arg2[, ...]]])
thisArg:調(diào)用func函數(shù)時作為this參數(shù)傳遞給目標函數(shù)的值;arg1, arg2, ...:當(dāng)目標函數(shù)被調(diào)用時,被預(yù)置入func函數(shù)的參數(shù)列表中的參數(shù);
使用效果:
function foo(...args) { console.log(this, ...args) } const obj = { name: 'curry', age: 30 } /** * 1.將obj對象綁定給foo函數(shù)的this * 2.bind剩余參數(shù)中的1 2 3分別傳遞給foo函數(shù)中參數(shù) * 3.也可在newFoo調(diào)用時傳入?yún)?shù),這時bind傳遞的參數(shù)會與newFoo調(diào)用時傳遞的參數(shù)進行合并 */ const newFoo = foo.bind(obj, 1, 2, 3) newFoo() newFoo('a', 'b', 'c')
總結(jié):
apply和call主要用于在函數(shù)調(diào)用時給函數(shù)的this綁定對應(yīng)的值,兩者作用類似,主要區(qū)別就是除了第一個參數(shù),apply方法接受的是一個參數(shù)數(shù)組,而call方法接受的是參數(shù)列表。
bind也是給函數(shù)指定this所綁定的值,不同于apply和call的是,它會返回一個新的函數(shù),新函數(shù)中的this指向就是我們所指定的值,且分別傳入的參數(shù)會進行合并。
2.apply、call和bind方法的實現(xiàn)
為了所有定義的函數(shù)能夠使用我們自定義的apply、call和bind方法,所以需要將自己實現(xiàn)的方法掛在Function的原型上,這樣所有的函數(shù)就可以通過原型鏈找到自定義的這三個方法了。
2.1.apply的實現(xiàn)
Function.prototype.myApply = function(thisArg, argArray) { // 1.獲取當(dāng)前需要被執(zhí)行的函數(shù) // 因為myApply是需要被當(dāng)前函數(shù)進行調(diào)用的,根據(jù)this的隱式綁定,此處的this就是指向當(dāng)前需要被執(zhí)行的函數(shù) const fn = this // 2.對傳入的thisArg進行邊界判斷 if (thisArg === null || thisArg === undefined) { // 當(dāng)傳入的是null或者undefined是,被執(zhí)行函數(shù)的this直接指向全局window thisArg = window } else { // 將傳入的thisArg對象化,方便后面在thisArg添加屬性 thisArg = Object(thisArg) } // 也可簡單寫成三元運算符: // thisArg = (thisArg === null || thisArg === undefined) ? window : Object(thisArg) // 3.將獲取的fn添加到thisArg對象上 // 這里使用Symbol的原因是避免外部傳入的thisArg中的屬性與添加fn有沖突 const fnSymbol = Symbol() Object.defineProperty(thisArg, fnSymbol, { enumerable: false, configurable: true, writable: false, value: fn }) // 也可簡單寫成 // thisArg[fnSymbol] = fn // 4.對argArray進行判斷 // 看是否有傳入值,沒有值傳入就默認 [] argArray = argArray || [] // 5.調(diào)用獲取的fn函數(shù),并將對應(yīng)傳入的數(shù)組展開傳遞過去 const result = thisArg[fnSymbol](...argArray) // 調(diào)用完后刪除添加的屬性 delete thisArg[fnSymbol] // 6.將結(jié)果返回 return result }
測試:雖然打印出來的對象中還存在Symbol屬性,實際上已經(jīng)通過delete刪除了,這里是對象引用的問題。
function foo(x, y, z) { console.log(this, x, y, z) } foo.myApply({name: 'curry'}, [1, 2, 3])
2.2.call的實現(xiàn)
call方法的實現(xiàn)和apply方法的實現(xiàn)差不多,主要在于后面參數(shù)的處理。
Function.prototype.myCall = function(thisArg, ...args) { // 1.獲取當(dāng)前需要被執(zhí)行的函數(shù) const fn = this // 2.對傳入的thisArg進行邊界判斷 thisArg = (thisArg === null || thisArg === undefined) ? window : Object(thisArg) // 3.將獲取的fn添加到thisArg對象上 const fnSymbol = Symbol() thisArg[fnSymbol] = fn // 4.調(diào)用獲取的fn函數(shù),并將對應(yīng)傳入的args傳遞過去 const result = thisArg[fnSymbol](...args) // 調(diào)用完后刪除添加的屬性 delete thisArg[fnSymbol] // 5.將結(jié)果返回 return result }
測試:
function foo(x, y, z) { console.log(this, x, y, z) } foo.myCall({name: 'curry'}, 1, 2, 3)
2.3.bind的實現(xiàn)
bind方法的實現(xiàn)稍微復(fù)雜一點,需要考慮到參數(shù)合并的問題。
Function.prototype.myBind = function(thisArg, ...argsArray) { // 1.獲取當(dāng)前的目標函數(shù),也就是當(dāng)前使用myBind方法的函數(shù) const fn = this // 2.對傳入的thisArg進行邊界判斷 thisArg = (thisArg === null || thisArg === undefined) ? window : Object(thisArg) // 3.將獲取的fn添加到thisArg對象上 const fnSymbol = Symbol() thisArg[fnSymbol] = fn // 4.定義一個新的函數(shù) function newFn(...args) { // 4.1.合并myBind和newFn傳入的參數(shù) const allArgs = [...argsArray, ...args] // 4.2.調(diào)用真正需要被調(diào)用的函數(shù),并將合并后的參數(shù)傳遞過去 const result = thisArg[fnSymbol](...allArgs) // 4.3.調(diào)用完后刪除添加的屬性 delete thisArg[fnSymbol] // 4.4.將結(jié)果返回 return result } // 6.將新函數(shù)返回 return newFn }
測試:
function foo(x, y, z) { console.log(this, x, y, z) } const newFoo = foo.myBind({ name: 'curry' }, 1, 2) newFoo(3)
總結(jié)
到此這篇關(guān)于使用JS簡單實現(xiàn)apply、call和bind方法的文章就介紹到這了,更多相關(guān)JS實現(xiàn)apply、call和bind方法內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
詳解如何使用JavaScript實現(xiàn)自定義的雙向數(shù)據(jù)綁定
雙向數(shù)據(jù)綁定是一種編程模式,用于在用戶界面和數(shù)據(jù)模型之間實現(xiàn)數(shù)據(jù)的同步更新,它允許用戶界面中的數(shù)據(jù)變化自動更新到數(shù)據(jù)模型中,在這篇文章中,我會使用基于觀察者模式和基于Proxy對象來實現(xiàn)JS的自定義雙向數(shù)據(jù)綁定2023-08-08關(guān)于base64編碼和解碼的js工具函數(shù)
這篇文章主要介紹了關(guān)于base64編碼和解碼的js工具函數(shù),具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-02-02一起來學(xué)習(xí)JavaScript的BOM操作
這篇文章主要為大家詳細介紹了JavaScript BOM操作,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助2022-03-03JavaScript+CSS實現(xiàn)的可折疊二級菜單實例
這篇文章主要介紹了JavaScript+CSS實現(xiàn)的可折疊二級菜單,以完整實例形式分析了JavaScript基于頁面元素節(jié)點及樣式的動態(tài)操作實現(xiàn)折疊菜單的相關(guān)技巧,需要的朋友可以參考下2016-02-02