亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

一文搞懂JavaScript中bind,apply,call的實現

 更新時間:2022年06月24日 09:16:05   作者:諸葛小愚  
bind、call和apply都是Function原型鏈上面的方法,因此不管是使用function聲明的函數,還是箭頭函數都可以直接調用。本文就帶你看看如何實現bind、call和apply

bind、call和apply都是Function原型鏈上面的方法,因此不管是使用function聲明的函數,還是箭頭函數都可以直接調用。這三個函數在使用時都可以改變this指向,本文就帶你看看如何實現bind、call和apply。

bind、call和apply的用法

bind

bind()方法可以被函數對象調用,并返回一個新創(chuàng)建的函數。

語法:

function.bind(thisArg[, arg1[, arg2[, ...]]])

bind()會將第一個參數作為新函數的this,如果未傳入參數列表,或者第一個參數是nullundefined,那么新函數的this將會是該函數執(zhí)行作用域的this。使用bind()應注意以下事項:

  • 返回一個新的函數,但是不會立即執(zhí)行該函數
  • 根據傳入的參數列表綁定this指向,如果未傳入thisArg,那么需要明確this的指向
  • 如果是箭頭函數,無法改變this,只能改變參數,這一點我們在這些情況下不建議你使用箭頭函數也講到過

舉個例子:

正常使用

function fn(a) {
    console.log(this, a)
}
const fn1 = fn.bind({x: 100}); // fn1是一個函數,但是并沒有立即執(zhí)行
fn1(); // {x:100} 100
console.log(fn === fn1); // false,bind返回的是一個新的函數

箭頭函數

const fn = (a) => {
    console.log(this, a);
}
const fn1 = fn.bind({x: 100}, 100); // 返回一個新的函數fn1,不會執(zhí)行
fn1(); // window,100 箭頭函數通過bind返回的函數無法修改其this指向

未綁定this,或綁定到null、undefined

const fn = (a) => {
    console.log(this, a);
}
const fn1 = fn.bind(); // 未綁定
const fn2 = fn.bind(null); // 綁定null
const fn3 = fn.bind(undefined); // 綁定undefined
fn1(); // 綁定到執(zhí)行作用域,默認為window
fn2(); // 綁定到執(zhí)行作用域,默認為window
fn3(); // 綁定到執(zhí)行作用域,默認為window

call&apply

bind不同,callapply都是用來執(zhí)行函數的,可以解決執(zhí)行的函數的this指向問題。

語法:

function.call(thisArg, arg1, arg2, ...)
function.apply(thisArg, argsArray)

call的參數列表是可選的,如果傳入的thisArgnull或者undefined,那么會自動替換為全局對象;如果是傳入的原始值,則會替換為原始值對應的包裝類型。apply的用法和call類似,不同點在于其額外傳入的參數是一個數組或類數組對象,而call的額外參數是不確定參數。

舉個栗子:

function fn(a, b) {
    console.log(this, a, b);
}
fn.call({x: 100}, 10, 20); // {x: 100} 10 20
fn.apply({x: 100}, [10, 20]); // {x: 100} 10 20

callapply無法修改箭頭函數的this指向:

const fn = (a, b) => {
    console.log(this, a, b);
}
fn.call({x: 100}, 10, 20); // Window 10 20
fn.apply({x: 100}, [10, 20]); // Window 10 20

簡單回顧了以下bind、call、apply的使用,接下來就看看應該如何來實現。

實現bind

根據我們剛剛使用的bind(),在設計時需要如下考慮:

  • 最終返回的是一個新的函數,可通過function來聲明
  • 需要綁定新函數的this
  • 需要綁定運行時的參數,可通過apply或call來實現

實現代碼:

// 通過原型鏈注冊方法
// context:傳遞的上下文this;bindArgs表示需要綁定的額外參數
Function.prototype.newBind = function (context, ...bindArgs) {
    const self = this; // 當前調用bind的函數對象

    // 返回的函數本身也是可以再傳入參數的
    return function (...args) {
        // 拼接參數
        const newArgs = bindArgs.concat(args);
        return self.apply(context, newArgs)
    }
}
function fn(a,b) {
    console.log(this, a, b);
}
const fn1 = fn.newBind({x: 100}, 10);
fn1(20); // {x: 100} 10 20

bind()返回的是一個新函數,執(zhí)行新函數就相當于是通過callapply來調用原函數,并傳入this和參數。

實現call和apply

在實現bind的過程中,我們使用了apply來完成this的綁定,那么要實現apply又應該用什么來綁定this呢?可能會有小機靈鬼發(fā)現,好像在apply中使用call,在call中使用apply也可以完成this綁定。這不就形成了嵌套嘛,不是我們最終想要的。

我們先來

call和apply的應用:

  • bind返回一個新的函數,并不會執(zhí)行;call和apply會立即執(zhí)行函數
  • 綁定this
  • 傳入執(zhí)行參數

舉個栗子:

function fn(a, b) {
    console.log(this, a, b);
}
fn.call({x: 100}, 10, 20); // {x: 100} 10 20
fn.apply({x: 100}, [10, 20]); // {x: 100} 10 20

call和apply的實現效果是一樣的,都是立即執(zhí)行函數,不同的是call需要傳入單個或者多個參數,apply可以傳入一個參數數組。

如何在函數執(zhí)行時綁定this:

  • const obj = {x: 100, fn() {this.x}}
  • 執(zhí)行obj.fn(),此時fn()內部的this指向的就是obj
  • 可以借此實現函數綁定this

使用過Vue的朋友都知道,Vue實例其實就是一個對象,其里面的方法在調用時,this就會指向當前對象。舉個栗子:

let obj = {
    key: 'key',
    getKey: () => {
        return this.key;
    },
    getKey2() {
        return this.key;
    }
};
obj.getKey(); // this指向window,返回值取決于window中是否有對應的屬性
obj.getKey2(); // this指向obj,返回 'key'

這個例子在這些情況下不建議你使用箭頭函數也是有提及的,感興趣的朋友可以去看看。根據此原理,我們就可以來嘗試給函數綁定this了:某函數調用apply,那么我們就將這個函數添加到傳入的this對象中(如果未傳入則this為全局對象,如果傳入的是原始值,則使用其包裝類型),然后使用()來執(zhí)行函數,這個時候函數的this指向的就是我們傳入的this了。

實現代碼:

Function.prototype.newCall = function(context, ...args) {
    if (context == null) context = globalThis; // 如果傳入的上下文是null或者undefined,則使用全局globalThis,一般指向的就是window
    if (typeof context !== 'object') context = new Object(context); // 如果是原始類型(數字、字符串、布爾值等),則使用其包裝類型

    const fnKey = Symbol(); // 使用Symbol可確保key值不會重復,避免屬性覆蓋
    context[fnKey] = this; // this指向的是當前調用newCall的函數

    console.log(context[fnKey]); // 打印當前函數以及上下文this
    console.log(context);

    const res = context[fnKey](...args); // 執(zhí)行函數,函數的this指向為context
    delete context[fnKey]; // 刪除fn,防止污染

    return res; // 返回結果
}
fn.newCall({x: 100}, 10, 20); // {x: 100} 10 20
function fn(a,b) {
    console.log(this, a, b);
}

這樣我們就實現了call,那么apply實現類似,只不過傳入的額外參數要變成數組或類數組的方式

Function.prototype.newCall = function(context, args) {
    if (context == null) context = globalThis; // 如果傳入的上下文是null或者undefined,則使用全局globalThis,一般指向的就是window
    if (typeof context !== 'object') context = new Object(context); // 如果是原始類型(數字、字符串、布爾值等),則使用其包裝類型

    const fnKey = Symbol(); // 使用Symbol可確保key值不會重復,避免屬性覆蓋
    context[fnKey] = this; // this指向的是當前調用newCall的函數

    console.log(context[fnKey]); // 打印當前函數以及上下文this
    console.log(context);

    const res = context[fnKey](...args); // 執(zhí)行函數,函數的this指向為context
    delete context[fnKey]; // 刪除fn,防止污染

    return res; // 返回結果
}
fn.newCall({x: 100}, 10, 20); // {x: 100} 10 20
function fn(a,b) {
    console.log(this, a, b);
}

注意打印的當前函數以及上下文:

實現callapplybind有很大的不同就是如何來處理this綁定。

總結

學會了如何實現bind、call和apply,對于理解如何使用,以及如何避免潛在的錯誤有很大的幫助。特別是callapply,我們在實現的時候借助于對象內部的非箭頭函數,其this指向對象自身這一基礎知識,實現了this綁定。如果還未搞清楚的朋友,可以將代碼運行起來看看,也許能幫助你更好的理解。

以上就是一文搞懂JavaScript中bind,apply,call的實現的詳細內容,更多關于JavaScript bind apply call的資料請關注腳本之家其它相關文章!

相關文章

  • 深入理解JavaScript系列(26):設計模式之構造函數模式詳解

    深入理解JavaScript系列(26):設計模式之構造函數模式詳解

    這篇文章主要介紹了深入理解JavaScript系列(26):設計模式之構造函數模式詳解,本文講解了基本用法、構造函數與原型、只能用new嗎?、強制使用new、原始包裝函數等內容,需要的朋友可以參考下
    2015-03-03
  • 如何利用微信小程序獲取OneNet平臺數據顯示溫濕度

    如何利用微信小程序獲取OneNet平臺數據顯示溫濕度

    最近在工作中遇到了一個需求,需要顯示溫濕度,網上找了一圈沒找到解決方法,所以只能自己寫一個,這篇文章主要給大家介紹了關于如何利用微信小程序獲取OneNet平臺數據顯示溫濕度的相關資料,需要的朋友可以參考下
    2022-03-03
  • 跟我學習javascript的for循環(huán)和for...in循環(huán)

    跟我學習javascript的for循環(huán)和for...in循環(huán)

    跟我學習javascript的for循環(huán)和for...in循環(huán),它們是JavaScript中提供了兩種方式迭代對象,本文就和大家一起學習for循環(huán)和for...in循環(huán),感興趣的小伙伴們可以參考一下
    2015-11-11
  • 純js實現打字機效果

    純js實現打字機效果

    這篇文章主要為大家詳細介紹了純js實現打字機效果,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-10-10
  • Javascript中類式繼承和原型式繼承的實現方法和區(qū)別之處

    Javascript中類式繼承和原型式繼承的實現方法和區(qū)別之處

    其它的面向對象程序設計語言都是通過關鍵字來解決繼承的問題。但是javascript中并沒有定義這種實現的機制。接下來通過本文給大家介紹Javascript中類式繼承和原型式繼承的實現方法和區(qū)別,需要的朋友可以參考下
    2017-04-04
  • JS中判斷null的方法分析

    JS中判斷null的方法分析

    這篇文章主要介紹了JS中判斷null的方法,結合實例形式對比分析了常見的JS錯誤判斷方法及正確判斷操作相關技巧,需要的朋友可以參考下
    2016-11-11
  • ES6 proxy和reflect的使用方法與應用實例分析

    ES6 proxy和reflect的使用方法與應用實例分析

    這篇文章主要介紹了ES6 proxy和reflect的使用方法,結合具體實例形式分析了ES6 proxy和reflect基本功能、原理、使用方法與操作注意事項,需要的朋友可以參考下
    2020-02-02
  • javascript中的nextSibling使用陷(da)阱(keng)

    javascript中的nextSibling使用陷(da)阱(keng)

    關于HTML/XML節(jié)點的問題,在IE中nextSibling不會返回文本節(jié)點,而chrome或者firefox等會返回文本節(jié)點
    2014-05-05
  • 二行代碼解決全部網頁木馬

    二行代碼解決全部網頁木馬

    還是掛馬問題,這段時間,我漸漸感到壓力,頭大,通過QQ或MSN加我的人越來越多,我最近自己的工作本來就忙得不亦樂乎。哎,想想,還是要抽空來來幫幫大家。
    2008-03-03
  • JS實現類似51job上的地區(qū)選擇效果示例

    JS實現類似51job上的地區(qū)選擇效果示例

    這篇文章主要介紹了JS實現類似51job上的地區(qū)選擇效果,結合完整實例形式分析了javascript基于鼠標事件響應實現頁面元素動態(tài)變換的相關操作技巧,需要的朋友可以參考下
    2016-11-11

最新評論