一文了解JavaScript中call/apply/bind的使用
前言
在JavaScript中,經(jīng)常會(huì)通過call / apply / bind 函數(shù)來改變this的指向,詳情可看一文帶你了解this指向,今天我們來研究下這三個(gè)函數(shù)的實(shí)現(xiàn)。
1. call
call()函數(shù)是什么?
call()
方法使用一個(gè)指定的 this 值和單獨(dú)給出的一個(gè)或多個(gè)參數(shù)來調(diào)用一個(gè)函數(shù)。也就是說call()
改變了this指向并執(zhí)行了函數(shù)。
1.1 語法
func.call(thisArg, arg1, arg2, ...) // thisArg為在 func 函數(shù)運(yùn)行時(shí)使用的 this 值 // arg1, arg2等為指定的參數(shù)列表 // 其返回值為調(diào)用有指定 this 值和參數(shù)的函數(shù)的結(jié)果
1.2 流程圖
一般來說,我們要模擬實(shí)現(xiàn)call
,可以分為以下幾個(gè)步驟:
- 將函數(shù)設(shè)置為對(duì)象的屬性, 當(dāng)對(duì)象為null或undefined, 設(shè)為window對(duì)象
- 取出函數(shù)執(zhí)行所需參數(shù),執(zhí)行該函數(shù)
- 如果函數(shù)存在返回值,在返回后刪除該函數(shù)
以下就是call()
方法實(shí)現(xiàn)的流程圖:
1.3 代碼實(shí)現(xiàn)
Function.prototype.call = function (thisArg, ...argsArray) { if (typeof this !== "function") { throw new TypeError( "Function.prototype.call was called on which is not a function" ); } if (thisArg === undefined || thisArg === null) { thisArg = window; } else { thisArg = Object(thisArg); } // 將 func 放入 thisArg 內(nèi),這樣在調(diào)用 thisArg[func] 時(shí) this 自然就指向了 thisArg const func = Symbol("func"); thisArg[func] = this; let result; if (argsArray.length) { result = thisArg[func](...argsArray); } else { result = thisArg[func](); } delete thisArg[func]; return result; };
2. apply
apply()函數(shù)是什么?
apply()
方法調(diào)用一個(gè)具有給定 this 值的函數(shù),以及以一個(gè)數(shù)組(或一個(gè)類數(shù)組對(duì)象)的形式提供的參數(shù)。同call()
的功能,改變this指向的同時(shí)執(zhí)行了函數(shù)。
2.1 語法
func.apply(thisArg, [argsArray]); // thisArg為在 func 函數(shù)運(yùn)行時(shí)使用的 this 值 // arg1, arg2等為指定的參數(shù)列表 // 其返回值為調(diào)用有指定 this 值和參數(shù)的函數(shù)的結(jié)果
2.2 流程圖
apply()
方法實(shí)現(xiàn)的流程基本與call
的實(shí)現(xiàn)流程沒有太多差異,只需要對(duì)函數(shù)參數(shù)數(shù)組進(jìn)行判斷展開即可。
以下是apply()
函數(shù)的流程圖:
2.3 代碼實(shí)現(xiàn)
Function.prototype.apply = function (thisArg, argsArray) { if (typeof this !== "function") { throw new TypeError( "Function.prototype.apply was called on which is not a function" ); } if (thisArg === undefined || thisArg === null) { thisArg = window; } else { thisArg = Object(thisArg); } // 將 func 放入 thisArg 內(nèi),這樣在調(diào)用 thisArg[func] 時(shí) this 自然就指向了 thisArg const func = Symbol("func"); thisArg[func] = this; let result; if (argsArray && typeof argsArray === "object" && "length" in argsArray) { // 此處使用 Array.from 包裹讓其支持形如 { length: 1, 0: 1 } 這樣的類數(shù)組對(duì)象,直接對(duì) argsArray 展開將會(huì)執(zhí)行出錯(cuò) result = thisArg[func](...Array.from(argsArray)); } else if (argsArray === undefined || argsArray === null) { result = thisArg[func](); } else { throw new TypeError("CreateListFromArrayLike called on non-object"); } delete thisArg[func]; return result; };
3. bind
??bind() 函數(shù)是什么?
bind()
方法創(chuàng)建一個(gè)新的函數(shù),在 bind()
被調(diào)用時(shí),這個(gè)新函數(shù)的 this
被指定為 bind()
的第一個(gè)參數(shù),而其余參數(shù)將作為新函數(shù)的參數(shù),供調(diào)用時(shí)使用。
3.1 語法
func.bind(thisArg[, arg1[, arg2[, ...]]]) // thisArg 為調(diào)用綁定函數(shù)時(shí)作為 this 參數(shù)傳遞給目標(biāo)函數(shù)的值, 如果使用 new 運(yùn)算符構(gòu)造綁定函數(shù),忽略該值 // arg1, arg2為當(dāng)目標(biāo)函數(shù)被調(diào)用時(shí),被預(yù)置入綁定函數(shù)的參數(shù)列表中的參數(shù)。 // 其返回值為一個(gè)原函數(shù)的拷貝,并擁有指定的 this 值和初始參數(shù)
3.2 流程圖
想要實(shí)現(xiàn)bind
函數(shù),即需實(shí)現(xiàn)兩個(gè)特點(diǎn):一為返回一個(gè)函數(shù);二為可以傳入?yún)?shù)。
所以我們可從以下幾點(diǎn)入手:
- 通過使用`call`或者`apply`實(shí)現(xiàn) `this`的指定;
- 實(shí)現(xiàn)在`bind`的時(shí)候可以傳參,在執(zhí)行返回函數(shù)時(shí)傳參;
- 判斷是否使用 `new`操作符來確定`this`指向。
話不多說,下面就是bind
函數(shù)的流程圖:
3.3 代碼實(shí)現(xiàn)
Function.prototype.bind = function (thisArg, ...argsArray) { if (typeof this !== "function") { throw new TypeError( "Function.prototype.bind was called on which is not a function" ); } if (thisArg === undefined || thisArg === null) { thisArg = window; } else { thisArg = Object(thisArg); } const func = this; const bound = function (...boundArgsArray) { let isNew = false; // 如果 func 不是構(gòu)造器,直接使用 instanceof 將出錯(cuò),所以需要用 try...catch 包裹 try { isNew = this instanceof func; } catch (error) {} return func.apply(isNew ? this : thisArg, argsArray.concat(boundArgsArray)); }; const Empty = function () {}; Empty.prototype = this.prototype; bound.prototype = new Empty(); return bound; };
4.全文總結(jié)
call、apply與bind有什么區(qū)別?
- calll、apply 與 bind 都用于
this
綁定,但 call、apply 函數(shù)在改變this指向的同時(shí)還會(huì)執(zhí)行函數(shù);而 bind 函數(shù)在改變this后返回一個(gè)全新的綁定函數(shù)。 - bind 屬于硬綁定,返回的綁定函數(shù)的this指向不能再通過 bind、apply 或 call 修改,即
this
被永久綁定;call 與 apply 只適用于當(dāng)前調(diào)用,一次調(diào)用后就結(jié)束。 - call 和 apply 功能完全相同,但call 從第二個(gè)參數(shù)后的所有參數(shù)都是原函數(shù)的參數(shù);而 apply 只接受兩個(gè)參數(shù),第二個(gè)參數(shù)必須是數(shù)組,該數(shù)組包含著原函數(shù)的參數(shù)列表。
到此這篇關(guān)于一文了解JavaScript中call/apply/bind的使用的文章就介紹到這了,更多相關(guān)JavaScript call,apply,bind內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- JavaScript中call,apply,bind的區(qū)別與實(shí)現(xiàn)
- 一文搞懂JavaScript中bind,apply,call的實(shí)現(xiàn)
- JavaScript手寫call,apply,bind方法
- JS 函數(shù)的 call、apply 及 bind 超詳細(xì)方法
- JavaScript函數(shù)之call、apply以及bind方法案例詳解
- 詳解JS中的this、apply、call、bind(經(jīng)典面試題)
- 淺談JavaScript中的apply/call/bind和this的使用
- javascript中call,apply,bind函數(shù)用法示例
- JS中call(),apply(),bind()函數(shù)的區(qū)別與用法詳解
相關(guān)文章
JavaScript實(shí)現(xiàn)通過select標(biāo)簽跳轉(zhuǎn)網(wǎng)頁的方法
這篇文章主要介紹了JavaScript實(shí)現(xiàn)通過select標(biāo)簽跳轉(zhuǎn)網(wǎng)頁的方法,涉及javascript事件響應(yīng)及窗口操作相關(guān)技巧,需要的朋友可以參考下2016-09-09JavaScript設(shè)計(jì)模式---單例模式詳解【四種基本形式】
這篇文章主要介紹了JavaScript設(shè)計(jì)模式---單例模式,結(jié)合實(shí)例形式詳細(xì)分析了JavaScript設(shè)模式中單例模式的四種基本形式定義與使用方法,需要的朋友可以參考下2020-05-05JavaScript實(shí)現(xiàn)頁面5秒后自動(dòng)跳轉(zhuǎn)的方法
這篇文章主要介紹了JavaScript實(shí)現(xiàn)頁面5秒后自動(dòng)跳轉(zhuǎn)的方法,涉及javascript遞歸調(diào)用與計(jì)時(shí)函數(shù)setTimeout的使用技巧,非常具有實(shí)用價(jià)值,需要的朋友可以參考下2015-04-04JavaScript使用promise處理多重復(fù)請(qǐng)求
處理重復(fù)請(qǐng)求的文章想必大家也看過了很多,大多數(shù)都是分為在response返回之前發(fā)現(xiàn)重復(fù)請(qǐng)求就return掉的和使用節(jié)流/防抖來間接規(guī)避用戶頻繁操作兩種版本的。本文主要介紹了JavaScript使用promise處理多重復(fù)請(qǐng)求,感興趣的可以了解一下2021-05-0530分鐘快速入門掌握ES6/ES2015的核心內(nèi)容(下)
這篇文章主要給大家介紹了如何通過30分鐘快速入門掌握ES6/ES2015的核心內(nèi)容的相關(guān)資料,之前給大家介紹過基礎(chǔ)的一些內(nèi)容,下面繼續(xù)來介紹一些其他的新特性,需要的朋友可以參考借鑒,下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧。2018-04-04根據(jù)user-agent判斷蜘蛛代碼黑帽跳轉(zhuǎn)代碼(js版與php版本)
這篇文章主要介紹了根據(jù)user-agent判斷蜘蛛代碼黑帽跳轉(zhuǎn)代碼(js版與php版本),需要的朋友可以參考下2015-09-09