JS中call apply bind函數(shù)手寫實(shí)現(xiàn)demo
正文
JavaScript 中的函數(shù)是一等公民,可以像普通變量一樣被傳遞和使用。這種靈活性使得函數(shù)可以被用于各種場景,比如對(duì)象方法的調(diào)用、構(gòu)造函數(shù)的創(chuàng)建和原型繼承等。在函數(shù)的使用過程中,call
、apply
、bind
是 JavaScript 中比較常用的一些方法,它們可以改變函數(shù)執(zhí)行的上下文,同時(shí)還能傳遞參數(shù)。
在本篇文章中,我們將會(huì)詳細(xì)介紹 call
、apply
、bind
這三個(gè)方法,并且手動(dòng)模擬實(shí)現(xiàn)它們。
call 方法
call
方法用于調(diào)用一個(gè)函數(shù),并且可以設(shè)置函數(shù)內(nèi)部的 this
值。它可以讓你將一個(gè)函數(shù)的 this
對(duì)象指向任意一個(gè)對(duì)象,并且傳入任意個(gè)數(shù)的參數(shù)。
下面是 call
方法的基本語法:
function.call(thisArg, arg1, arg2, ...)
其中:
function
:要調(diào)用的函數(shù)。thisArg
:設(shè)置function
函數(shù)中的this
對(duì)象的值。arg1
、arg2
、...
:傳遞給function
函數(shù)的參數(shù),可以有多個(gè)。
下面是一個(gè)簡單的示例:
const person = { name: 'Zhang San', sayHi() { console.log(`Hi, my name is ${this.name}.`); }, }; person.sayHi(); // 輸出 "Hi, my name is Zhang San." const otherPerson = { name: 'Zhang San', }; person.sayHi.call(otherPerson); // 輸出 "Hi, my name is Zhang San."
在上面的例子中,我們創(chuàng)建了一個(gè) person
對(duì)象,它有一個(gè) sayHi
方法,用于輸出自我介紹。我們使用 call
方法將 person
對(duì)象的 sayHi
方法綁定到 otherPerson
對(duì)象上,并且輸出了 otherPerson
對(duì)象的名字。
接下來,我們將手動(dòng)模擬實(shí)現(xiàn) call
方法,實(shí)現(xiàn)一個(gè)名為 myCall
的函數(shù)。
Function.prototype.myCall = function(context, ...args) { context = context || window; context.fn = this; const result = context.fn(...args); delete context.fn; return result; };
上面的代碼中,我們給 Function.prototype
添加了一個(gè)新的方法 myCall
。該方法接收兩個(gè)參數(shù),第一個(gè)參數(shù) context
表示要綁定的 this
值,第二個(gè)參數(shù) args
表示要傳遞給函數(shù)的參數(shù)列表。如果第一個(gè)參數(shù) context
為空,則默認(rèn)綁定到全局對(duì)象 window
上。
接著,我們?cè)诮壎ǖ膶?duì)象 context
上添加了一個(gè) fn
屬性,并且將當(dāng)前函數(shù)綁定到該屬性上,接著調(diào)用該函數(shù),并將結(jié)果保存到 result
變量中。
最后,我們刪除 context
對(duì)象上的 fn
屬性,并將結(jié)果返回。這樣,我們就成功地手動(dòng)模擬實(shí)現(xiàn) call
方法。
apply 方法
apply
函數(shù)的語法為:function.apply(thisArg, [argsArray])
,其中 thisArg
表示函數(shù)執(zhí)行時(shí)的上下文對(duì)象,也就是函數(shù)中的 this
關(guān)鍵字所指向的對(duì)象,argsArray
是一個(gè)數(shù)組,表示函數(shù)執(zhí)行時(shí)傳遞的參數(shù)列表。
實(shí)現(xiàn)步驟
聲明一個(gè)函數(shù),以便在之后使用 apply
函數(shù)。
function sum(a, b) { return a + b; }
然后我們現(xiàn)在需要為函數(shù) sum
添加 apply
方法,該方法接受兩個(gè)參數(shù):上下文對(duì)象 thisArg
和參數(shù)數(shù)組 argsArray
。
Function.prototype.apply = function(thisArg, argsArray) { // 代碼實(shí)現(xiàn) };
在 apply
函數(shù)中,第一個(gè)參數(shù) thisArg
表示要調(diào)用函數(shù)的上下文對(duì)象。如果沒有傳遞 thisArg
,那么默認(rèn)為全局對(duì)象 window
。
Function.prototype.apply = function(thisArg, argsArray) { thisArg = thisArg || window; };
我們需要在函數(shù)執(zhí)行時(shí)將函數(shù)中的 this
關(guān)鍵字指向上下文對(duì)象 thisArg
,從而改變函數(shù)的上下文對(duì)象。
Function.prototype.apply = function(thisArg, argsArray) { thisArg = thisArg || window; let fn = Symbol('fn'); thisArg[fn] = this; let result = thisArg[fn](...argsArray); delete thisArg[fn]; return result; };
在上述代碼中,我們使用了一個(gè)新的 Symbol
類型的變量 fn
,用于存儲(chǔ)函數(shù)對(duì)象。然后我們將函數(shù)對(duì)象存儲(chǔ)在上下文對(duì)象 thisArg
中,并立即執(zhí)行該函數(shù),從而改變函數(shù)的上下文對(duì)象。最后,我們刪除存儲(chǔ)在上下文對(duì)象中的函數(shù)對(duì)象,并返回函數(shù)執(zhí)行的結(jié)果。
下面是完整的 apply
函數(shù)的代碼實(shí)現(xiàn):
function sum(a, b) { return a + b; } Function.prototype.apply = function(thisArg, argsArray) { thisArg = thisArg || window; let fn = Symbol('fn'); thisArg[fn] = this; let result = thisArg[fn](...argsArray); delete thisArg[fn]; return result; }; console.log(sum.apply(null, [1, 2])); // 輸出:3
bind 方法
bind
函數(shù)也是對(duì)函數(shù)的this指向進(jìn)行修改的函數(shù),不同于 call
和 apply
函數(shù)的立即執(zhí)行,bind
函數(shù)返回一個(gè)新的函數(shù),這個(gè)新的函數(shù)可以在后續(xù)調(diào)用時(shí)再傳入?yún)?shù)并執(zhí)行。bind
函數(shù)的實(shí)現(xiàn)可以通過在返回的新函數(shù)中使用閉包來保存?zhèn)魅氲?this
值,并返回一個(gè)新函數(shù)。
bind
函數(shù)的語法如下:
function.bind(thisArg[, arg1[, arg2[, ...]]])
其中,thisArg
為需要綁定的 this
值,arg1
, arg2
等為新函數(shù)的參數(shù)。bind
函數(shù)返回一個(gè)新函數(shù),這個(gè)新函數(shù)的 this
值被綁定為傳入的 thisArg
值,同時(shí)可以傳入額外的參數(shù)作為新函數(shù)的參數(shù)。當(dāng)調(diào)用返回的新函數(shù)時(shí),會(huì)以傳入的參數(shù)和之前綁定的 this
值作為參數(shù)調(diào)用原函數(shù)。
下面是一個(gè)手動(dòng)實(shí)現(xiàn)的 bind
函數(shù):
Function.prototype.bind2 = function(thisArg) { var self = this; var args = Array.prototype.slice.call(arguments, 1); return function() { var bindArgs = Array.prototype.slice.call(arguments); return self.apply(thisArg, args.concat(bindArgs)); }; }
在實(shí)現(xiàn)中,先保存 this
的指向,然后將傳入的參數(shù)放到 args
數(shù)組中。接下來返回一個(gè)新的函數(shù),這個(gè)新的函數(shù)會(huì)保存 bind2
函數(shù)中的 this
值和 args
數(shù)組中的參數(shù)。在新函數(shù)被調(diào)用時(shí),會(huì)將之前保存的 this
值和 args
數(shù)組中的參數(shù)與新傳入的參數(shù)合并為一個(gè)數(shù)組,并調(diào)用原函數(shù)的 apply
方法傳入這個(gè)數(shù)組作為參數(shù),以達(dá)到修改 this
值和傳入?yún)?shù)的目的。
總結(jié)
本文我們介紹了 call
、apply
和 bind
這三個(gè)函數(shù)的作用及其實(shí)現(xiàn)原理,并手動(dòng)模擬實(shí)現(xiàn)了這三個(gè)函數(shù)。實(shí)現(xiàn)過程中,我們學(xué)習(xí)了函數(shù)的 this
指向、函數(shù)的 apply
和 call
方法、以及函數(shù)的柯里化等知識(shí)點(diǎn)。
掌握這些知識(shí)點(diǎn)有助于我們更好地理解 JavaScript 中的函數(shù)機(jī)制,并能夠編寫更加靈活、高效的代碼。
以上就是JS中call apply bind函數(shù)手寫實(shí)現(xiàn)demo的詳細(xì)內(nèi)容,更多關(guān)于JS call apply bind函數(shù)的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
javascript下arguments,caller,callee,call,apply示例及理解
在看到大家如此關(guān)注JS里頭的這幾個(gè)對(duì)象,我試著把原文再修改一下,力求能再詳細(xì)的闡明個(gè)中意義2009-12-12Javascript的表單驗(yàn)證-初識(shí)正則表達(dá)式
JavaScript 可用來在數(shù)據(jù)被送往服務(wù)器前對(duì) HTML 表單中的這些輸入數(shù)據(jù)進(jìn)行驗(yàn)證。接下來通過本文給大家介紹Javascript的表單驗(yàn)證-初識(shí)正則表達(dá)式,對(duì)js表單驗(yàn)證正則表達(dá)式相關(guān)知識(shí)感興趣的朋友一起學(xué)習(xí)吧2016-03-03JavaScript DOM 學(xué)習(xí)總結(jié)(五)
當(dāng)頁面加載時(shí),瀏覽器會(huì)創(chuàng)建頁面的文檔對(duì)象模型(Document Object Model)。文檔對(duì)象模型定義訪問和處理HTML文檔的標(biāo)準(zhǔn)方法,本篇文章給大家介紹javascript dom 學(xué)習(xí)總結(jié)(五),感興趣的朋友一起學(xué)習(xí)吧2015-11-11js實(shí)現(xiàn)讓某個(gè)動(dòng)作延遲幾秒執(zhí)行
這篇文章主要介紹了使用js實(shí)現(xiàn)讓某個(gè)動(dòng)作延遲幾秒執(zhí)行的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-06-06詳解Web使用webpack構(gòu)建前端項(xiàng)目
本篇文章主要介紹了詳解Web使用webpack構(gòu)建前端項(xiàng)目,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-09-09js監(jiān)控IE火狐瀏覽器關(guān)閉、刷新、回退、前進(jìn)事件
本節(jié)主要介紹了js監(jiān)控IE火狐瀏覽器關(guān)閉、刷新、回退、前進(jìn)事件的方法2014-07-07瀏覽器JavaScript調(diào)試功能無法使用解決方案
這篇文章主要介紹了瀏覽器JavaScript調(diào)試功能無法使用解決方案,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-09-09