一文了解JavaScript中call/apply/bind的使用
前言
在JavaScript中,經(jīng)常會通過call / apply / bind 函數(shù)來改變this的指向,詳情可看一文帶你了解this指向,今天我們來研究下這三個函數(shù)的實現(xiàn)。
1. call
call()函數(shù)是什么?
call() 方法使用一個指定的 this 值和單獨給出的一個或多個參數(shù)來調(diào)用一個函數(shù)。也就是說call() 改變了this指向并執(zhí)行了函數(shù)。
1.1 語法
func.call(thisArg, arg1, arg2, ...) // thisArg為在 func 函數(shù)運行時使用的 this 值 // arg1, arg2等為指定的參數(shù)列表 // 其返回值為調(diào)用有指定 this 值和參數(shù)的函數(shù)的結(jié)果
1.2 流程圖
一般來說,我們要模擬實現(xiàn)call,可以分為以下幾個步驟:
- 將函數(shù)設(shè)置為對象的屬性, 當(dāng)對象為null或undefined, 設(shè)為window對象
- 取出函數(shù)執(zhí)行所需參數(shù),執(zhí)行該函數(shù)
- 如果函數(shù)存在返回值,在返回后刪除該函數(shù)
以下就是call()方法實現(xiàn)的流程圖:

1.3 代碼實現(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] 時 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)用一個具有給定 this 值的函數(shù),以及以一個數(shù)組(或一個類數(shù)組對象)的形式提供的參數(shù)。同call()的功能,改變this指向的同時執(zhí)行了函數(shù)。
2.1 語法
func.apply(thisArg, [argsArray]); // thisArg為在 func 函數(shù)運行時使用的 this 值 // arg1, arg2等為指定的參數(shù)列表 // 其返回值為調(diào)用有指定 this 值和參數(shù)的函數(shù)的結(jié)果
2.2 流程圖
apply()方法實現(xiàn)的流程基本與call的實現(xiàn)流程沒有太多差異,只需要對函數(shù)參數(shù)數(shù)組進行判斷展開即可。
以下是apply()函數(shù)的流程圖:

2.3 代碼實現(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] 時 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ù)組對象,直接對 argsArray 展開將會執(zhí)行出錯
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)建一個新的函數(shù),在 bind() 被調(diào)用時,這個新函數(shù)的 this 被指定為 bind() 的第一個參數(shù),而其余參數(shù)將作為新函數(shù)的參數(shù),供調(diào)用時使用。
3.1 語法
func.bind(thisArg[, arg1[, arg2[, ...]]]) // thisArg 為調(diào)用綁定函數(shù)時作為 this 參數(shù)傳遞給目標(biāo)函數(shù)的值, 如果使用 new 運算符構(gòu)造綁定函數(shù),忽略該值 // arg1, arg2為當(dāng)目標(biāo)函數(shù)被調(diào)用時,被預(yù)置入綁定函數(shù)的參數(shù)列表中的參數(shù)。 // 其返回值為一個原函數(shù)的拷貝,并擁有指定的 this 值和初始參數(shù)
3.2 流程圖
想要實現(xiàn)bind函數(shù),即需實現(xiàn)兩個特點:一為返回一個函數(shù);二為可以傳入?yún)?shù)。
所以我們可從以下幾點入手:
- 通過使用`call`或者`apply`實現(xiàn) `this`的指定;
- 實現(xiàn)在`bind`的時候可以傳參,在執(zhí)行返回函數(shù)時傳參;
- 判斷是否使用 `new`操作符來確定`this`指向。
話不多說,下面就是bind函數(shù)的流程圖:

3.3 代碼實現(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 將出錯,所以需要用 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指向的同時還會執(zhí)行函數(shù);而 bind 函數(shù)在改變this后返回一個全新的綁定函數(shù)。 - bind 屬于硬綁定,返回的綁定函數(shù)的this指向不能再通過 bind、apply 或 call 修改,即
this被永久綁定;call 與 apply 只適用于當(dāng)前調(diào)用,一次調(diào)用后就結(jié)束。 - call 和 apply 功能完全相同,但call 從第二個參數(shù)后的所有參數(shù)都是原函數(shù)的參數(shù);而 apply 只接受兩個參數(shù),第二個參數(shù)必須是數(shù)組,該數(shù)組包含著原函數(shù)的參數(shù)列表。
到此這篇關(guān)于一文了解JavaScript中call/apply/bind的使用的文章就介紹到這了,更多相關(guān)JavaScript call,apply,bind內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- JavaScript中call,apply,bind的區(qū)別與實現(xiàn)
- 一文搞懂JavaScript中bind,apply,call的實現(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實現(xiàn)通過select標(biāo)簽跳轉(zhuǎn)網(wǎng)頁的方法
這篇文章主要介紹了JavaScript實現(xiàn)通過select標(biāo)簽跳轉(zhuǎn)網(wǎng)頁的方法,涉及javascript事件響應(yīng)及窗口操作相關(guān)技巧,需要的朋友可以參考下2016-09-09
JavaScript設(shè)計模式---單例模式詳解【四種基本形式】
這篇文章主要介紹了JavaScript設(shè)計模式---單例模式,結(jié)合實例形式詳細(xì)分析了JavaScript設(shè)模式中單例模式的四種基本形式定義與使用方法,需要的朋友可以參考下2020-05-05
JavaScript實現(xiàn)頁面5秒后自動跳轉(zhuǎn)的方法
這篇文章主要介紹了JavaScript實現(xiàn)頁面5秒后自動跳轉(zhuǎn)的方法,涉及javascript遞歸調(diào)用與計時函數(shù)setTimeout的使用技巧,非常具有實用價值,需要的朋友可以參考下2015-04-04
JavaScript使用promise處理多重復(fù)請求
處理重復(fù)請求的文章想必大家也看過了很多,大多數(shù)都是分為在response返回之前發(fā)現(xiàn)重復(fù)請求就return掉的和使用節(jié)流/防抖來間接規(guī)避用戶頻繁操作兩種版本的。本文主要介紹了JavaScript使用promise處理多重復(fù)請求,感興趣的可以了解一下2021-05-05
30分鐘快速入門掌握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

