最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

JavaScript 中的 bind、apply、call用法與區(qū)別解析

 更新時(shí)間:2025年09月09日 11:03:16   作者:Pan Zonghui  
bind、apply 和 call 是 JavaScript 中控制 this 指向的核心工具,它們的應(yīng)用貫穿于日常開發(fā)的方方面面,本文給大家介紹JavaScript 中的 bind、apply、call用法與區(qū)別,感興趣的朋友跟隨小編一起看看吧

在 JavaScript 中,bind、applycall 是函數(shù)對(duì)象的三個(gè)重要方法,它們的核心作用是改變函數(shù)執(zhí)行時(shí)的上下文(this 指向),但在使用方式和應(yīng)用場(chǎng)景上又存在細(xì)微差異。掌握這三個(gè)方法,不僅能讓我們更靈活地控制函數(shù)執(zhí)行,也是理解 JavaScript 中 this 綁定機(jī)制的關(guān)鍵。

一、bind、apply、call 基本概念與區(qū)別

1.1 共同作用

三者的核心功能一致:在調(diào)用函數(shù)時(shí),指定函數(shù)內(nèi)部 this 的指向。這在處理回調(diào)函數(shù)、事件監(jiān)聽、對(duì)象方法借用等場(chǎng)景中尤為重要。

1.2 主要區(qū)別

方法調(diào)用方式參數(shù)傳遞方式執(zhí)行時(shí)機(jī)
call立即執(zhí)行函數(shù)逐個(gè)傳遞參數(shù)(逗號(hào)分隔)調(diào)用后立即執(zhí)行
apply立即執(zhí)行函數(shù)以數(shù)組(或類數(shù)組)形式傳遞參數(shù)調(diào)用后立即執(zhí)行
bind返回一個(gè)新的函數(shù)(綁定了 this 的函數(shù))逐個(gè)傳遞參數(shù)(逗號(hào)分隔)需手動(dòng)調(diào)用新函數(shù)才執(zhí)行

二、具體用法詳解

2.1 call 方法

call 方法的語法:

function.call(thisArg, arg1, arg2, ...);
  • thisArg:函數(shù)執(zhí)行時(shí)綁定的 this 值。若為 nullundefined,在非嚴(yán)格模式下 this 會(huì)指向全局對(duì)象(瀏覽器中為 window,Node.js 中為 global)。
  • arg1, arg2, ...:傳遞給函數(shù)的參數(shù)列表(逐個(gè)傳入)。

示例:對(duì)象方法借用

const person = {
  name: 'Alice',
  sayHello: function(greeting) {
    console.log(`${greeting}, I'm ${this.name}`);
  }
};
const anotherPerson = { name: 'Bob' };
// 調(diào)用 person 的 sayHello 方法,但 this 指向 anotherPerson
person.sayHello.call(anotherPerson, 'Hi'); // 輸出:Hi, I'm Bob

2.2 apply 方法

apply 方法的語法:

function.apply(thisArg, [argsArray]);
  • thisArg:同 call,指定 this 指向。
  • argsArray:參數(shù)數(shù)組(或類數(shù)組對(duì)象,如 arguments),函數(shù)的參數(shù)將從該數(shù)組中提取。

示例:數(shù)組拼接與合并

當(dāng)需要將一個(gè)數(shù)組的元素添加到另一個(gè)數(shù)組中時(shí),apply 可以便捷地實(shí)現(xiàn):

const arr1 = [1, 2, 3];
const arr2 = [4, 5, 6];
// 利用 apply 傳遞數(shù)組參數(shù),等價(jià)于 arr1.push(4, 5, 6)
arr1.push.apply(arr1, arr2); 
console.log(arr1); // 輸出:[1, 2, 3, 4, 5, 6]

這個(gè)案例中,push 方法原本需要逐個(gè)接收參數(shù),而 apply 讓我們可以直接傳遞數(shù)組 arr2,實(shí)現(xiàn)了數(shù)組的快速合并。

2.3 bind 方法

bind 方法的語法:

const boundFunction = function.bind(thisArg, arg1, arg2, ...);
  • thisArg:綁定到函數(shù)的 this 值(永久綁定,無法被再次修改)。
  • arg1, arg2, ...:預(yù)設(shè)的參數(shù)(柯里化參數(shù))。
  • 返回值:一個(gè)新的函數(shù),該函數(shù)的 this 已固定為 thisArg,且可預(yù)設(shè)部分參數(shù)。

示例:異步操作中的上下文保存

在異步回調(diào)中,this 指向常常會(huì)丟失,使用 bind 可以提前固定上下文:

const dataProcessor = {
  prefix: 'Result:',
  process: function(value) {
    console.log(`${this.prefix} ${value}`);
  }
};
// 模擬異步操作
function fetchData(callback) {
  setTimeout(() => {
    callback(100); // 回調(diào)函數(shù)執(zhí)行時(shí),this 可能指向全局對(duì)象
  }, 1000);
}
// 綁定 process 方法的 this 為 dataProcessor
fetchData(dataProcessor.process.bind(dataProcessor)); 
// 1秒后輸出:Result: 100

如果不使用 bind,回調(diào)函數(shù)中的 this 會(huì)指向 window(非嚴(yán)格模式),導(dǎo)致無法正確訪問 dataProcessorprefix 屬性。

三、手寫實(shí)現(xiàn) bind、apply、call

理解原生方法的實(shí)現(xiàn)原理,能幫助我們更深刻地掌握其本質(zhì)。下面分別實(shí)現(xiàn)這三個(gè)方法。

3.1 實(shí)現(xiàn) call 方法

call 方法的核心邏輯:

  1. 將函數(shù)作為指定 thisArg 的臨時(shí)方法(避免污染原對(duì)象)。
  2. 傳入?yún)?shù)并執(zhí)行函數(shù)。
  3. 刪除臨時(shí)方法,返回函數(shù)執(zhí)行結(jié)果。
Function.prototype.myCall = function(context, ...args) {
  // 1. 處理 context,如果為 null/undefined,則指向 window
  context = context || window;
  // 2. 創(chuàng)建一個(gè)唯一的 key,防止與 context 上的屬性沖突
  const uniqueKey = Symbol('fn');
  // 3. 將當(dāng)前函數(shù)(this)作為 context 的一個(gè)方法
  // this 在這里指向調(diào)用 myCall 的函數(shù)
  context[uniqueKey] = this;
  // 4. 通過 context 調(diào)用該方法,此時(shí) this 就指向了 context
  const result = context[uniqueKey](...args);
  // 5. 清理掉這個(gè)臨時(shí)方法,保持對(duì)象干凈
  delete context[uniqueKey];
  // 6. 返回函數(shù)的執(zhí)行結(jié)果
  return result;
}

測(cè)試:

const obj = { name: 'Test' };
function testCall(greeting) {
  console.log(`${greeting}, ${this.name}`);
}
testCall.myCall(obj, 'Hello'); // 輸出:Hello, Test

3.2 實(shí)現(xiàn) apply 方法

applycall 的區(qū)別僅在于參數(shù)傳遞方式(數(shù)組 vs 逐個(gè)),實(shí)現(xiàn)邏輯類似:

Function.prototype.myApply = function(thisArg, argsArray) {
  thisArg = thisArg || window;
  const fnSymbol = Symbol('fn');
  thisArg[fnSymbol] = this;
  // 處理參數(shù):若 argsArray 不存在,傳入空數(shù)組
  const result = thisArg[fnSymbol](...(argsArray || []));
  delete thisArg[fnSymbol];
  return result;
};

測(cè)試:

function sum(a, b, c) {
  return a + b + c;
}
const numbers = [1, 2, 3];
console.log(sum.myApply(null, numbers)); // 輸出:6

3.3 實(shí)現(xiàn) bind 方法

bind 的實(shí)現(xiàn)更復(fù)雜,需要滿足:

  1. 綁定 this 指向(永久綁定,即使使用 call/apply 也無法修改)。
  2. 支持預(yù)設(shè)參數(shù)(柯里化參數(shù))。
  3. 返回的函數(shù)可以被當(dāng)作構(gòu)造函數(shù)使用(此時(shí) this 應(yīng)指向?qū)嵗龑?duì)象)。
Function.prototype.myBind = function (context, ...bindArgs) {
  // this 指向調(diào)用 myBind 的原始函數(shù)
  const originalFunc = this;
  // 返回一個(gè)新的函數(shù)
  const fBound = function (...callArgs) {
    // 合并 bind 時(shí)傳入的參數(shù)和調(diào)用時(shí)傳入的參數(shù)
    const allArgs = [...bindArgs, ...callArgs];
    // 關(guān)鍵點(diǎn):判斷是否是通過 new 關(guān)鍵字調(diào)用的
    if (this instanceof fBound) {
      // 箭頭函數(shù)不能作為構(gòu)造函數(shù),原生 bind 返回 undefined
      if (!originalFunc.prototype) {
        return undefined;
      }
      // 是 new 關(guān)鍵字調(diào)用的,this 應(yīng)該指向新實(shí)例
      return new originalFunc(...allArgs);
    }
    // 如果是普通調(diào)用,就使用 call/apply 將 this 指向綁定的 context
    return originalFunc.apply(context, allArgs);
  };
  // 處理原型鏈:讓返回的函數(shù)的原型指向原始函數(shù)的原型
  // 這樣,由 bind 后的函數(shù) new 出來的實(shí)例,也能繼承原始函數(shù)的原型方法
  if (originalFunc.prototype) {
    fBound.prototype = Object.create(originalFunc.prototype);
    fBound.prototype.constructor = fBound;// 確保 constructor 指向正確
  }
  return fBound;
}

測(cè)試 1:綁定 this 與參數(shù)柯里化

const obj = { x: 10 };
function add(y, z) {
  return this.x + y + z;
}
const boundAdd = add.myBind(obj, 5);
console.log(boundAdd(3)); // 輸出:18(10 + 5 + 3)

測(cè)試 2:作為構(gòu)造函數(shù)使用

function Person(name) {
  this.name = name;
}
const BoundPerson = Person.myBind({});
const person = new BoundPerson('Alice');
console.log(person.name); // 輸出:Alice(this 指向?qū)嵗?,而非綁定?{})
console.log(person instanceof Person); // 輸出:true(原型鏈正確)

四、實(shí)際應(yīng)用場(chǎng)景

4.1 借用對(duì)象方法

當(dāng)需要使用某個(gè)對(duì)象的方法處理另一個(gè)對(duì)象的數(shù)據(jù)時(shí),callapply 非常實(shí)用。例如,用數(shù)組的 slice 方法將類數(shù)組轉(zhuǎn)為真正的數(shù)組:

function convertToArray() {
  // arguments 是類數(shù)組,借用數(shù)組的 slice 方法
  return Array.prototype.slice.call(arguments);
}
console.log(convertToArray(1, 2, 3)); // 輸出:[1, 2, 3]

4.2 回調(diào)函數(shù)中的 this 綁定

在定時(shí)器、事件監(jiān)聽等場(chǎng)景中,回調(diào)函數(shù)的 this 往往會(huì)丟失原上下文,bind 可以固定 this 指向:

class Timer {
  constructor() {
    this.seconds = 0;
    // 綁定 tick 方法的 this 為當(dāng)前實(shí)例
    setInterval(this.tick.bind(this), 1000);
  }
  tick() {
    this.seconds++;
    console.log(this.seconds);
  }
}
new Timer(); // 每秒輸出:1, 2, 3, ...

? 現(xiàn)代替代方案:箭頭函數(shù)

在 ES6+ 的環(huán)境中,處理上述場(chǎng)景有了更簡潔的選擇:箭頭函數(shù) (=>)。

箭頭函數(shù)沒有自己的 this,它會(huì)捕獲其所在上下文的 this 值作為自己的 this(詞法作用域 this)。因此,它可以完美地替代 bind 來固定上下文。

上面的 Timer 類可以寫成:

class Timer {
  constructor() {
    this.seconds = 0;
    // 使用箭頭函數(shù),tick 方法中的 this 會(huì)自動(dòng)指向 Timer 實(shí)例
    setInterval(() => this.tick(), 1000);
  }
  tick() {
    this.seconds++;
    console.log(this.seconds);
  }
}
// 或者更推薦的方式,將方法本身定義為箭頭函數(shù)(作為類字段)
class ModernTimer {
    constructor() {
        this.seconds = 0;
        setInterval(this.tick, 1000); // 無需 bind 或箭頭函數(shù)包裹
    }
    tick = () => {
        this.seconds++;
        console.log(this.seconds);
    }
}
new ModernTimer();

盡管箭頭函數(shù)在很多情況下更方便,但理解 bind 的工作原理依然是 JavaScript 基礎(chǔ)中不可或缺的一環(huán)。

4.3 函數(shù)柯里化

bind 可以實(shí)現(xiàn)函數(shù)柯里化(將多參數(shù)函數(shù)轉(zhuǎn)為單參數(shù)函數(shù)的鏈?zhǔn)秸{(diào)用),提高代碼復(fù)用性:

function multiply(a, b, c) {
  return a * b * c;
}
// 預(yù)設(shè)第一個(gè)參數(shù)為 2
const multiplyBy2 = multiply.bind(null, 2);
// 再預(yù)設(shè)第二個(gè)參數(shù)為 3
const multiplyBy2And3 = multiplyBy2.bind(null, 3);
console.log(multiplyBy2And3(4)); // 輸出:24(2 * 3 * 4)

五、注意事項(xiàng)

  1. 嚴(yán)格模式與非嚴(yán)格模式的區(qū)別:在嚴(yán)格模式下,若 thisArgnullundefined,函數(shù)內(nèi)的 this 會(huì)保持 nullundefined;非嚴(yán)格模式下則指向全局對(duì)象。
  2. bind 的不可修改性:用 bind 綁定的 this 無法被 callapply 再次修改,但可以通過 new 調(diào)用改變(此時(shí) this 指向?qū)嵗?/li>
  3. 性能考量:頻繁使用 bind 會(huì)創(chuàng)建新的函數(shù)對(duì)象,可能影響性能(尤其在循環(huán)中),需合理使用。

六、總結(jié)

bind、applycall 是 JavaScript 中控制 this 指向的核心工具,它們的應(yīng)用貫穿于日常開發(fā)的方方面面:

  • call:適合參數(shù)數(shù)量固定的場(chǎng)景,立即執(zhí)行函數(shù)。
  • apply:適合參數(shù)以數(shù)組形式存在的場(chǎng)景(如動(dòng)態(tài)參數(shù)列表),立即執(zhí)行函數(shù)。
  • bind:適合需要延遲執(zhí)行函數(shù)、固定 this 指向或?qū)崿F(xiàn)參數(shù)柯里化的場(chǎng)景。

通過手動(dòng)實(shí)現(xiàn)這三個(gè)方法,我們不僅能更深入地理解其工作原理,也能對(duì) JavaScript 中的 this 綁定、函數(shù)調(diào)用機(jī)制有更清晰的認(rèn)知。在實(shí)際開發(fā)中,根據(jù)具體場(chǎng)景選擇合適的方法,能讓代碼更簡潔、高效。

到此這篇關(guān)于JavaScript 中的 bind、apply、call用法與區(qū)別解析的文章就介紹到這了,更多相關(guān)js bind apply call用法內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • JavaScript常用數(shù)組元素搜索或過濾的四種方法詳解

    JavaScript常用數(shù)組元素搜索或過濾的四種方法詳解

    這篇文章主要介紹了JavaScript常用數(shù)組元素搜索或過濾的四種方法,每種方式通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-08-08
  • JavaScript下申明對(duì)象的幾種方法小結(jié)

    JavaScript下申明對(duì)象的幾種方法小結(jié)

    在JavaScript中可以用下面的幾種方法申明對(duì)象:(從"Truly"的文章中學(xué)到)
    2008-10-10
  • 基于js實(shí)現(xiàn)的限制文本框只可以輸入數(shù)字

    基于js實(shí)現(xiàn)的限制文本框只可以輸入數(shù)字

    本文主要介紹了js限制文本框只可以輸入數(shù)字的實(shí)例代碼,可復(fù)制直接調(diào)用函數(shù)實(shí)現(xiàn)其功能。需要的朋友可以看下
    2016-12-12
  • js+CSS實(shí)現(xiàn)彈出居中背景半透明div層的方法

    js+CSS實(shí)現(xiàn)彈出居中背景半透明div層的方法

    這篇文章主要介紹了js+CSS實(shí)現(xiàn)彈出居中背景半透明div層的方法,涉及javascript操作彈出div層的操作技巧,非常具有實(shí)用價(jià)值,需要的朋友可以參考下
    2015-02-02
  • js實(shí)現(xiàn)自定義滾動(dòng)條的示例

    js實(shí)現(xiàn)自定義滾動(dòng)條的示例

    這篇文章主要介紹了js實(shí)現(xiàn)自定義滾動(dòng)條的示例,幫助大家制作JS特效,美化自身網(wǎng)頁,感興趣的朋友可以了解下
    2020-10-10
  • JavaScript設(shè)計(jì)模式之迭代者模式詳情

    JavaScript設(shè)計(jì)模式之迭代者模式詳情

    這篇文章主要介紹了JavaScript設(shè)計(jì)模式之迭代者模式詳情,迭代器設(shè)計(jì)模式能夠可以讓我們更方便的且有規(guī)矩的進(jìn)行訪問復(fù)合數(shù)據(jù)的每一項(xiàng),也可以通過迭代器進(jìn)行完成一些流線式操作
    2022-06-06
  • JavaScript中Array.from()的超全用法詳解

    JavaScript中Array.from()的超全用法詳解

    Array.from方法用于將兩類對(duì)象轉(zhuǎn)為真正的數(shù)組:類似數(shù)組的對(duì)象(array-like?object)和可遍歷(iterable)的對(duì)象(包括?ES6?新增的數(shù)據(jù)結(jié)構(gòu)?Set?和?Map),別忘記就來講講他的具體用法吧
    2023-03-03
  • ES6數(shù)組的擴(kuò)展詳解

    ES6數(shù)組的擴(kuò)展詳解

    這篇文章主要介紹了ES6數(shù)組的擴(kuò)展,結(jié)合實(shí)例形式詳細(xì)對(duì)比分析了ES6數(shù)組的新增方法與相關(guān)使用技巧,需要的朋友可以參考下
    2017-04-04
  • 詳解ES6數(shù)組方法find()、findIndex()的總結(jié)

    詳解ES6數(shù)組方法find()、findIndex()的總結(jié)

    這篇文章主要介紹了詳解ES6數(shù)組方法find()、findIndex()的總結(jié),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-05-05
  • ActiveX控件與Javascript之間的交互示例

    ActiveX控件與Javascript之間的交互示例

    這篇文章主要介紹了ActiveX控件如何與Javascript進(jìn)行交互,需要的朋友可以參考下
    2014-06-06

最新評(píng)論

井冈山市| 刚察县| 苍溪县| 新乡市| 涡阳县| 洪雅县| 揭东县| 林州市| 鄂尔多斯市| 增城市| 潞城市| 云霄县| 新竹县| 景泰县| 西藏| 察隅县| 钦州市| 清苑县| 理塘县| 丰城市| 莒南县| 武冈市| 西丰县| 微博| 邯郸市| 泽州县| 连州市| 陇南市| 裕民县| 滦南县| 鹤山市| 张家界市| 科技| 昌黎县| 沂南县| 湖南省| 会泽县| 张家口市| 怀化市| 陆川县| 灌云县|