徹底搞懂JS中call、apply、bind的區(qū)別與應(yīng)用
前言
在 JavaScript 中,this 的指向是動(dòng)態(tài)的,這雖然靈活,但也常讓我們頭疼。而 call、apply 和 bind 就是我們手中的“魔法棒”,專門用來手動(dòng)控制 this 的指向。它們有什么區(qū)別?分別在什么場景下使用?本文帶你一探究竟。
一、 三大方法詳解
這三個(gè)方法都掛載在 Function.prototype 上,這意味著所有的函數(shù)都可以調(diào)用它們。
1. call()
作用:修改函數(shù)的
this指向,并立即執(zhí)行該函數(shù)。參數(shù):
thisArg:this需要綁定的對象。arg1, arg2, ...:參數(shù)列表,直接按順序傳入。
默認(rèn)行為:如果不傳
thisArg或傳null/undefined,在非嚴(yán)格模式下指向window。
fn.call(obj, agr1,agr2,arg3,arg4,.....)
2. apply()
作用:修改函數(shù)的
this指向,并立即執(zhí)行該函數(shù)。參數(shù):
thisArg:this需要綁定的對象。argsArray:數(shù)組(或類數(shù)組) ,數(shù)組內(nèi)的元素會被展開傳入函數(shù)。
fn.apply(obj, [agr1,agr2,arg3,arg4,.....])
3. bind()
- 作用:修改函數(shù)的
this指向,但不會立即執(zhí)行。 - 返回值:返回一個(gè)新的函數(shù)(稱為綁定函數(shù))。
- 硬綁定:
bind返回的新函數(shù),其this指向一旦被綁定,后續(xù)再使用call或apply都無法再次修改。 - 參數(shù):與
call相同,接受參數(shù)列表。支持柯里化(預(yù)設(shè)部分參數(shù))。
bind(thisArg, arg1, arg2, arg3, ...)
二、 核心區(qū)別對比(一張表看懂)
| 方法 | 執(zhí)行時(shí)機(jī) | 參數(shù)格式 | 返回值 | 核心場景 |
|---|---|---|---|---|
| call | 立即執(zhí)行 | 參數(shù)列表 (arg1, arg2) | 函數(shù)執(zhí)行結(jié)果 | 對象繼承、借用方法 |
| apply | 立即執(zhí)行 | 數(shù)組 ([arg1, arg2]) | 函數(shù)執(zhí)行結(jié)果 | 數(shù)學(xué)計(jì)算、數(shù)組合并 |
| bind | 稍后執(zhí)行 | 參數(shù)列表 (arg1, arg2) | 新函數(shù) | 事件綁定、回調(diào)函數(shù) |
三、 代碼實(shí)戰(zhàn)與糾錯(cuò)
讓我們通過一個(gè)經(jīng)典的例子來看它們的具體表現(xiàn)。
const obj = {
name: 'Original',
fn: function(a, b) {
console.log(this.name, a, b);
}
}
const db = { name: 'DataBase' };
// 1. 原始調(diào)用
obj.fn(1, 2);
// 輸出: "Original" 1 2
// 2. call 調(diào)用:傳參列表
obj.fn.call(db, 3, 4);
// 輸出: "DataBase" 3 4
// 3. apply 調(diào)用:傳參數(shù)組
obj.fn.apply(db, [5, 6]);
// 輸出: "DataBase" 5 6
// 4. bind 調(diào)用:返回新函數(shù),手動(dòng)執(zhí)行
const boundFn = obj.fn.bind(db, 7, 8);
boundFn();
// 輸出: "DataBase" 7 8
// 5. bind 的連續(xù)修改無效性(面試坑點(diǎn))
const doubleBind = obj.fn.bind(db).bind({ name: 'Error' });
doubleBind();
// 輸出: "DataBase" undefined undefined (第二次 bind 無效)四、 常見應(yīng)用場景(面試加分項(xiàng))
僅僅知道語法是不夠的,面試官更看重你知道怎么用。
1. 數(shù)組求最大值 (apply)
利用 apply 接受數(shù)組參數(shù)的特性,結(jié)合 Math.max。
const nums = [5, 10, 20, 1]; const max = Math.max.apply(null, nums); // 20 // ES6 寫法: Math.max(...nums)
2. 類數(shù)組轉(zhuǎn)數(shù)組 (call)
利用 call 借用數(shù)組的 slice 方法。
function func() {
const args = Array.prototype.slice.call(arguments);
console.log(args); // 變成了真數(shù)組
}3. React/Vue 中的事件綁定 (bind)
防止回調(diào)函數(shù)在執(zhí)行時(shí) this 丟失(指向 undefined 或 window)。
this.handleClick = this.handleClick.bind(this);
五、 面試模擬題
Q1:call和apply的唯一區(qū)別是什么?
參考回答:
它們的唯一區(qū)別在于傳參方式。call 需要把參數(shù)按順序一個(gè)個(gè)傳進(jìn)去(參數(shù)列表),而 apply 需要把參數(shù)放在一個(gè)數(shù)組(或類數(shù)組)里傳進(jìn)去。助記口訣:"a" for array (apply), "c" for comma (call)。
Q2:為什么bind返回的函數(shù),再次使用call無法修改this?
參考回答:
這涉及 bind 的內(nèi)部實(shí)現(xiàn)。bind 返回的函數(shù)內(nèi)部已經(jīng)通過閉包鎖定了 this(通常稱為硬綁定)。也就是類似 return function() { return originalFn.apply(that, arguments) } 的結(jié)構(gòu)。無論外部怎么 call,內(nèi)部的 apply 永遠(yuǎn)使用的是第一次綁定的 that。
Q3:手寫一個(gè)簡單的bind?
Function.prototype.myBind = function (context, ...args) {
// 1. 保存當(dāng)前的函數(shù)(this 指向原函數(shù))
const fn = this;
// 2. 返回一個(gè)新的函數(shù)
return function (...innerArgs) {
// 3. 將預(yù)設(shè)參數(shù)和新參數(shù)合并,并用 apply 執(zhí)行原函數(shù)
return fn.apply(context, args.concat(innerArgs));
};
};
const obj = {
name: "Original",
fn: function (a, b) {
console.log(this.name, a, b);
},
};
const boundFn = obj.fn.myBind({ name: 'DataBase' }, 7, 8);
boundFn();總結(jié)
到此這篇關(guān)于JS中call、apply、bind區(qū)別與應(yīng)用的文章就介紹到這了,更多相關(guān)JS中call、apply、bind內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- JS中改變this指向的方法(call和apply、bind)
- js apply/call/caller/callee/bind使用方法與區(qū)別分析
- 詳解JS中的this、apply、call、bind(經(jīng)典面試題)
- 淺談javascript中call()、apply()、bind()的用法
- 深入理解JavaScript中的call、apply、bind方法的區(qū)別
- 跟我學(xué)習(xí)javascript的call(),apply(),bind()與回調(diào)
- Javascript中call,apply,bind方法的詳解與總結(jié)
- javascript中call,apply,bind的用法對比分析
- javascript中apply、call和bind的使用區(qū)別
- 淺談javascript的call()、apply()、bind()的用法
相關(guān)文章
JavaScript日期時(shí)間與時(shí)間戳的轉(zhuǎn)換函數(shù)分享
這篇文章主要介紹了JavaScript日期時(shí)間與時(shí)間戳的轉(zhuǎn)換函數(shù)分享,本文給出兩個(gè)函數(shù)實(shí)現(xiàn)日期時(shí)間和時(shí)間戳間的轉(zhuǎn)換,需要的朋友可以參考下2015-01-01
JavaScript find()方法及返回?cái)?shù)據(jù)實(shí)例
這篇文章主要介紹了JavaScript中的find()方法和返回?cái)?shù)據(jù)的內(nèi)存指向,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-04-04
讓你的博文自動(dòng)帶上縮址的實(shí)現(xiàn)代碼,方便發(fā)到微博客上
添加以下代碼到你的博客中: (呵呵,抄襲至lulu Studio http://s8.hk/0itw)2010-12-12
javascript實(shí)現(xiàn)輪顯新聞標(biāo)題鏈接
這篇文章主要介紹了javascript實(shí)現(xiàn)輪顯新聞標(biāo)題鏈接的相關(guān)資料,需要的朋友可以參考下2007-08-08
JavaScript數(shù)組清空常用的3種方式總結(jié)
數(shù)組是JavaScript中的十分常用且重要的數(shù)據(jù)類型,而刪除數(shù)組元素是一種常見的數(shù)組操作,下面這篇文章主要介紹了JavaScript數(shù)組清空常用的3種方式,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下2025-10-10

