欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

JavaScript中call,apply,bind的區(qū)別與實現(xiàn)

 更新時間:2022年09月14日 09:59:40   作者:XerDemo  
這篇文章主要介紹了JavaScript中call,apply,bind的區(qū)別與實現(xiàn),文章通過圍繞主題思想展開詳細(xì)的內(nèi)容介紹,具有一定的參考價值,需要的小伙伴可以參考一下

區(qū)別

  • call、apply、bind相同點(diǎn):都是改變this的指向,傳入的第一個參數(shù)都是綁定this的指向,在非嚴(yán)格模式中,如果第一個參數(shù)是nul或者undefined,會把全局對象(瀏覽器是window)作為this的值,要注意的是,在嚴(yán)格模式中,null 就是 null,undefined 就是 undefined
  • call和apply唯一的區(qū)別是:call傳入的是參數(shù)列表,apply傳入的是數(shù)組,也可以是類數(shù)組
  • bind和call、apply的區(qū)別: bind返回的是一個改變了this指向的函數(shù),便于稍后調(diào)用,不像call和apply會立即調(diào)用;bind和call很像,傳入的也是參數(shù)列表,但是可以多次傳入,不需要像call,一次傳入
  • 值得注意:當(dāng) bind 返回的函數(shù) 使用new作為構(gòu)造函數(shù)時,綁定的 this 值會失效,this指向?qū)嵗龑ο?,但傳入的參?shù)依然生效 (new調(diào)用的優(yōu)先級 > bind調(diào)用)

call實現(xiàn)

對象context想調(diào)用一個它沒有的方法f 怎么辦呢?f.call(context) 通過call來借用方法f ,怎么做到的呢?

  • 對象context添加f方法
  • 對象context執(zhí)行f方法
Function.prototype.myCall = function(context, ...arg) {
    // 如果第一個參數(shù)傳入的是undefined和null,context為window對象
    context = context || window;  
    
    // 為context對象添加函數(shù)bar
    context.fn = this;   // this:bar,this指向調(diào)用myCall的bar  

    // context對象執(zhí)行函數(shù)bar,并返回結(jié)果
    return  context.fn(...arg); 
}

// 測試一下
var value = 2;

var obj = {
    value: 1
}
function bar(name, age) {
    console.log(this.value);
    return {
        value: this.value,
        name: name,
        age: age
    }
}

bar.myCall(null); // 2

console.log(bar.myCall(obj, 'kevin', 18)); //1
// Object {
//    value: 1,
//    name: 'kevin',
//    age: 18
// }

apply實現(xiàn)

apply和call唯一的區(qū)別是:call傳入的是參數(shù)列表,apply傳入的是數(shù)組,也可以是類數(shù)組

Function.prototype.myApply = function(context, arg) {
    // 如果第一個參數(shù)傳入的是undefined和null,context為window對象
    context = context || window;  
    
    // context對象添加函數(shù)bar
    context.fn = this;   // this:bar,this指向調(diào)用myCall的函數(shù)bar  

    // context對象執(zhí)行函數(shù)bar,并返回結(jié)果
    let result = null;
    if (!arg) { // 沒有傳入數(shù)組
        result = context.fn();
    }else{      // 傳入了參數(shù)數(shù)組
        result = context.fn(...arg);
    } 
    return result;
}

// 測試一下
var value = 2;

var obj = {
    value: 1
}
function bar(name, age) {
    console.log(this.value);
    return {
        value: this.value,
        name: name,
        age: age
    }
}

bar.myApply(null); // 2
console.log(bar.myApply(obj, ['kevin', 18])); // 1

bind實現(xiàn)

  • bind和call、apply的區(qū)別: bind返回的是一個改變了this指向的函數(shù),便于稍后調(diào)用,不像call和apply會立即調(diào)用;bind和call很像,傳入的也是參數(shù)列表,但是可以多次傳入,不需要像call,一次傳入
  • 值得注意:當(dāng) bind 返回的函數(shù) 使用new作為構(gòu)造函數(shù)時,綁定的 this 值會失效,this指向?qū)嵗龑ο?,但傳入的參?shù)依然生效 (new調(diào)用的優(yōu)先級 > bind調(diào)用)

bind實現(xiàn)最為復(fù)雜,因為經(jīng)過bind綁定過的函數(shù),既可以被當(dāng)作普通函數(shù)調(diào)用,又可以被當(dāng)作構(gòu)造函數(shù)調(diào)用

  • bind 返回的函數(shù) 作為普通函數(shù)調(diào)用
// bind 返回的函數(shù) 作為普通函數(shù)調(diào)用
let bindFun = normalFun.myBind(obj, '我是參數(shù)傳進(jìn)來的name') // this:obj
bindFun('我是參數(shù)傳進(jìn)來的age')
  • bind 返回的函數(shù) 作為構(gòu)造函數(shù)調(diào)用,綁定的 this 值obj會失效,this指向?qū)嵗龑ο骯
// bind 返回的函數(shù) 作為構(gòu)造函數(shù)調(diào)用
let bindFun = Person.myBind(obj, '我是參數(shù)傳進(jìn)來的name') // this:obj
let a = new bindFun('我是參數(shù)傳進(jìn)來的age')               // this:a

bind 返回的函數(shù) 作為普通函數(shù)調(diào)用 代碼實現(xiàn)

// bind 返回的函數(shù) 作為普通函數(shù)調(diào)用
Function.prototype.myBind = function (context, ...args){
    // 如果第一個參數(shù)傳入的是undefined和null,context為window對象
    context = context || window;

    // context對象(obj)添加函數(shù)normalFun
    context.fn = this;  // this:normalFun, context.fn === normalFun,下面出現(xiàn)context.fn都可以直接看成normalFun
    
    // bind返回的函數(shù)  
    return function (...innerArgs) {
        // bind 返回的函數(shù) 作為普通函數(shù)被執(zhí)行
        context.fn(...[...args,...innerArgs]);  //相當(dāng)于normalFun(...[...args,...innerArgs])
    }
}

// 測試
let obj = {
  objName: '我是obj傳進(jìn)來的name',
  objAge: '我是obj傳進(jìn)來的age'
}
// 普通函數(shù)
function normalFun(name, age) {
  console.log(name);          //'我是第一次參數(shù)傳進(jìn)來的name被args接收'
  console.log(age);           //'我是第二次參數(shù)傳進(jìn)來的age被innerArgs接收'
  console.log(this === obj);  // true,this指向obj
  console.log(this.objName);  //'我是obj傳進(jìn)來的name'
  console.log(this.objAge);   //'我是obj傳進(jìn)來的age'
}

// bind 返回的函數(shù) 作為普通函數(shù)調(diào)用
let bindFun = normalFun.myBind(obj, '我是第一次參數(shù)傳進(jìn)來的name被args接收'); // this指向obj 
bindFun('我是第二次參數(shù)傳進(jìn)來的age被innerArgs接收'); 

bind 返回的函數(shù) 作為構(gòu)造函數(shù)調(diào)用

// bind 返回的函數(shù) 再經(jīng)過new調(diào)用  
Function.prototype.myBind = function (context, ...args){
    // 如果第一個參數(shù)傳入的是undefined和null,context為window對象
    context = context || window;

    // context對象添加函數(shù)Person
    context.fn = this;     // this:Person,context.fn:Person,_this:Person
    let _this = this;

    // bind返回的函數(shù) 
    const result = function (...innerArgs) { 
        if (this instanceof _this ) { // this:a (new出來的實例對象) ,  _this:Person
            // 為實例對象a添加Person方法
            this.fn = _this;
            // 實例對象a執(zhí)行Person方法
            this.fn(...[...args,...innerArgs]);
        }
    }
    result.prototype = Object.create(this.prototype);  // 為什加這一句?看原型圖下面會解釋
    return result;
}
// 測試
function Person(name, age) {
  console.log(name); //'我是第一次參數(shù)傳進(jìn)來的name被args接收'
  console.log(age); //'我是第二次參數(shù)傳進(jìn)來的age被innerArgs接收'
  console.log(this); //構(gòu)造函數(shù)this指向?qū)嵗龑ο?
}
// 構(gòu)造函數(shù)原型的方法
Person.prototype.say = function() {
  console.log(123);
}

let obj = {
  objName: '我是obj傳進(jìn)來的name',
  objAge: '我是obj傳進(jìn)來的age'
}

// bind 返回的函數(shù) 作為構(gòu)造函數(shù)調(diào)用
let bindFun = Person.myBind(obj, '我是第一次參數(shù)傳進(jìn)來的name被args接收') // this:obj
let a = new bindFun('我是第二次參數(shù)傳進(jìn)來的age被innerArgs接收')               // this:a
a.say() //123

畫以下兩條語句的原型圖方便理解

let bindFun = Person.myBind(obj, '我是第一次參數(shù)傳進(jìn)來的name被args接收') // this:obj
let a = new bindFun('我是第二次參數(shù)傳進(jìn)來的age被innerArgs接收')               // this:a

當(dāng)執(zhí)行下面語句時,原型圖如下:

let bindFun = Person.myBind(obj, '我是第一次參數(shù)傳進(jìn)來的name被args接收') // this:obj

當(dāng)執(zhí)行下面語句時,bindFun就是result看代碼,原型圖如下:

let a = new bindFun('我是第二次參數(shù)傳進(jìn)來的age被innerArgs接收')               // this:a

在這里實例對象a還需要繼承構(gòu)造函數(shù)Person的原型,所以加上了

result.prototype = Object.create(this.prototype);

原型圖最終如下:

bind代碼最終實現(xiàn)

Function.prototype.myBind = function (context, ...args){
    // 如果第一個參數(shù)傳入的是undefined和null,context為window對象
    context = context || window;

    // context對象添加函數(shù)Person
    context.fn = this;     // this:Person,context.fn:Person,_this:Person
    let _this = this;
    
    // bind返回的函數(shù) 
    const result = function (...innerArgs) { 
        if (this instanceof _this ) { // this:a (new出來的實例對象) ,  _this:Person
            // 為實例對象a添加Person方法
            this.fn = _this;
            // 實例對象a執(zhí)行Person方法
            this.fn(...[...args,...innerArgs]);
        }else{
            // 普通函數(shù)被調(diào)用
            context.fn(...[...args,...innerArgs]);
        }
    }
    
    result.prototype = Object.create(this.prototype);  // 為什加這一句?看原型圖下面會解釋
    return result;
}

// 測試
// function Person(name, age) {
//   console.log(name); //'我是第一次參數(shù)傳進(jìn)來的name被args接收'
//   console.log(age); //'我是第二次參數(shù)傳進(jìn)來的age被innerArgs接收'
//   console.log(this); //構(gòu)造函數(shù)this指向?qū)嵗龑ο?
// }
// // 構(gòu)造函數(shù)原型的方法
// Person.prototype.say = function() {
//   console.log(123);
// }

// let obj = {
//   objName: '我是obj傳進(jìn)來的name',
//   objAge: '我是obj傳進(jìn)來的age'
// }

// // bind 返回的函數(shù) 作為構(gòu)造函數(shù)調(diào)用
// let bindFun = Person.myBind(obj, '我是第一次參數(shù)傳進(jìn)來的name被args接收') // this:obj
// let a = new bindFun('我是第二次參數(shù)傳進(jìn)來的age被innerArgs接收')               // this:a
// a.say() //123

// 測試
let obj = {
  objName: '我是obj傳進(jìn)來的name',
  objAge: '我是obj傳進(jìn)來的age'
}

// 普通函數(shù)
function normalFun(name, age) {
  console.log(name);          //'我是第一次參數(shù)傳進(jìn)來的name'
  console.log(age);           //'我是第二次參數(shù)傳進(jìn)來的age'
  console.log(this === obj);  // true
  console.log(this.objName);  //'我是obj傳進(jìn)來的name'
  console.log(this.objAge);   //'我是obj傳進(jìn)來的age'
}

// bind 返回的函數(shù) 作為普通函數(shù)調(diào)用
let bindFun = normalFun.myBind(obj, '我是第一次參數(shù)傳進(jìn)來的name被args接收'); // this指向obj 
bindFun('我是第二次參數(shù)傳進(jìn)來的age被innerArgs接收');  

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

相關(guān)文章

  • JS實現(xiàn)秒殺倒計時特效

    JS實現(xiàn)秒殺倒計時特效

    這篇文章主要為大家詳細(xì)介紹了JS實現(xiàn)秒殺倒計時特效,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-01-01
  • JavaScript面向?qū)ο缶幊绦∮螒?--貪吃蛇代碼實例

    JavaScript面向?qū)ο缶幊绦∮螒?--貪吃蛇代碼實例

    這篇文章主要介紹了JavaScript貪吃蛇的實現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-05-05
  • JavaScript字符串轉(zhuǎn)數(shù)字的簡單實現(xiàn)方法

    JavaScript字符串轉(zhuǎn)數(shù)字的簡單實現(xiàn)方法

    這篇文章主要給大家介紹了關(guān)于JavaScript字符串轉(zhuǎn)數(shù)字的簡單實現(xiàn)方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-11-11
  • 利用Math.js解決JS計算小數(shù)精度丟失問題

    利用Math.js解決JS計算小數(shù)精度丟失問題

    電商系統(tǒng)中訂單、庫存中有數(shù)字等加減乘除算術(shù),下面這篇文章主要給大家介紹了關(guān)于利用Math.js解決JS計算小數(shù)精度丟失問題的相關(guān)資料,mathjs是一個前端在計算上面必定會用到的類庫,需要的朋友可以參考下
    2022-04-04
  • 鼠標(biāo)點(diǎn)擊input,顯示瞬間的邊框顏色,對之修改與隱藏實例

    鼠標(biāo)點(diǎn)擊input,顯示瞬間的邊框顏色,對之修改與隱藏實例

    下面小編就為大家?guī)硪黄髽?biāo)點(diǎn)擊input,顯示瞬間的邊框顏色,對之修改與隱藏實例。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧,祝大家游戲愉快哦
    2016-12-12
  • 多瀏覽器兼容的獲取元素和鼠標(biāo)的位置的js代碼

    多瀏覽器兼容的獲取元素和鼠標(biāo)的位置的js代碼

    獲取元素和鼠標(biāo)的位置(兼容IE6.0,IE7.0,IE8.0,FireFox2.0,FireFox3.5,Opera),該功能是我一同事鉆研出來的,目標(biāo)是為了實現(xiàn)與QQ自定義布局和拖放模塊類似的功能。
    2009-12-12
  • 微信小程序?qū)崿F(xiàn)打卡日歷功能

    微信小程序?qū)崿F(xiàn)打卡日歷功能

    這篇文章主要為大家詳細(xì)介紹了微信小程序?qū)崿F(xiàn)打卡日歷功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-11-11
  • JS中關(guān)于Class類的靜態(tài)屬性和靜態(tài)方法

    JS中關(guān)于Class類的靜態(tài)屬性和靜態(tài)方法

    這篇文章主要介紹了JS中關(guān)于Class類的靜態(tài)屬性和靜態(tài)方法,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-10-10
  • bootstrap與pagehelper實現(xiàn)分頁效果

    bootstrap與pagehelper實現(xiàn)分頁效果

    這篇文章主要為大家詳細(xì)介紹了bootstrap與pagehelper實現(xiàn)分頁效果,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-12-12
  • js父頁面與子頁面不同時顯示的方法

    js父頁面與子頁面不同時顯示的方法

    這篇文章主要介紹了js父頁面與子頁面不同時顯示的方法,打開一個頁面后,父頁面DISABLE,在子頁面關(guān)閉后,父頁面ENABLE,是比較實用的技巧,需要的朋友可以參考下
    2014-10-10

最新評論