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;
};
复制代码
相关文章
相关标签/搜索