call、apply、bind的使用和實現

call

  • 參數:
    • target:目標對象
    • params:函數參數
  • 做用:
    1. 修改函數this爲目標對象
  • 說明:
    1. 與apply的區別:傳參形式不一樣, call是單個傳參,apply是數組傳參
    2. 與bind的區別:bind是返回別修改過this的函數,而call是修改this,並直接調用
  • code:
var name = 'window';

var obj = {
  name: 'obj'
};

function showName(age, gender) {
  console.log(this.name, age, gender)
}

// 直接調用(this => window)
showName(18, 'MAN'); // 執行結果:輸出window 18 MAN
// call調用(this => obj)
showName.call(obj, 18, 'MAN');// 執行結果:輸出obj 18 MAN
複製代碼

apply

  • 參數:
    • target:目標對象
    • params:函數參數(數組)
  • 做用:
    1. 修改函數this爲目標對象
  • 說明:
    1. 與call的區別:傳參形式不一樣, call是單個傳參,apply是數組傳參
    2. 與bind的區別:bind是返回別修改過this的函數,而call是修改this,並直接調用
  • code:
var name = 'window';

var obj = {
  name: 'obj'
};

function showName(age, gender) {
  console.log(this.name, age, gender)
}

// 直接調用(this => window)
showName(18, 'MAN'); // 執行結果:輸出window 18 MAN
// apply調用(this => obj)
showName.apply(obj, [18, 'MAN']);// 執行結果:輸出obj 18 MAN
複製代碼

bind

  • 參數:
    • target:目標對象
    • params:函數參數
  • 做用:
    1. 修改函數this爲目標對象
  • 說明:
    1. 與apply和call的區別:bind是返回別修改過this的函數,而call和apply是修改this,並直接調用
    2. new修改過this的構造函數,裏面的this指向new出來的實例對象
  • code:
var name = 'window';

var obj = {
  name: 'obj'
};

function showName(age, gender) {
  console.log(this.name, age, gender)
}

// 直接調用(this => window)
showName(18, 'MAN'); // 執行結果:輸出window 18 MAN
// bind調用(this => obj)
var newShowName = showName.bind(obj, 18, 'MAN');
newShowName();  // 執行結果:輸出obj 18 MAN
複製代碼

原理實現

call:

Function.prototype.myCall = function () {
    // 獲取目標對象
    var zl = arguments[0] == null ? window : arguments[0];
    // 獲取參數長度
    var len = arguments.length;
    // 存儲參數
    var args = [];
    // this指目標函數,zl.fn是讓目標函數做爲目標對象的方法來調用
    zl.fn = this;
    for (var i = 1; i < len; i++) {
        args.push('arguments[' + i + ']');
    }
    var result = eval('zl.fn(' + args + ')');
    delete zl.fn;
    return result;
};
複製代碼

apply:

Function.prototype.myApply = function (zl, arr) {
    var zl = zl == null ? window : zl;
    var result;
    zl.fn = this;
    if (!arr) {
        result = zl.fn();
    } else {
        var args = [];
        for (var i = 0; i < arr.length; i++) {
            args.push('arr[' + i + ']');
        }
        result = eval('zl.fn(' + args + ')');
    }
    delete zl.fn;
    return result;
};
複製代碼

bind:

Function.prototype.myBind = function () {
    var zl = arguments[0] == null ? window : arguments[0];
    var paramArr = Array.prototype.call(arguments, 1);
    var self = this;
    var temp = function () {};
    var fn = function () {
        var args = paramArr.concat(Array.prototype.call(arguments));
        // 判斷是new 仍是直接調用,若是是new則目標函數的this爲實例對象
        // 若是是直接調用,目標函數的this爲目標對象
        return slef.apply(this.constructor === self ? this : zl, args);
    };
    temp.prototype = self.prototype;
    fn.prototype = new temp();
    return fn;
};
複製代碼
相關文章
相關標籤/搜索