call apply bind

130 阅读2分钟

相同之处:

都可以改变函数体内 this 的指向。


不同之处:

call、apply的区别:接受参数的方式不一样。
call接受的参数不是数组。 apply接受的参数是数组。

bind:不立即执行,返回的是一个函数。而apply、call 立即执行。
bind 除了返回是函数以外,它的参数和 call 一样。

默认实现使用

不带参数使用

var jack = {
    name: "jack",
    showName: function() {
        console.log(this.name)
    }
}

var tom = {
    name: 'tom'
}

jack.showName();  //jack
jack.showName.call(tom); //tom
jack.showName.apply(tom); // tom
jack.showName.bind(tom)();  //tom

带参数使用

var jack = {
    age: 1,
    showAge: function(num1,num2) {
        console.log(this.age + num1 + num2)
    }
}

var tom = {
    age: 12
}

jack.showAge(1,1); //3
jack.showAge.call(tom, 1, 1); //14
jack.showAge.apply(tom,[1, 1]); //14
jack.showAge.bind(tom, 1, 1)(); //14

模拟实现

call apply bind 底层是c++实现的,但是为了理解其内部实现,接下来我们用js简单模拟一下这三个函数的内部实现

js代码模拟实现call(myCall)

Function.prototype.myCall = function(thisArg, ...args) {
    //保存需要被执行的函数
    var fn = this
    //简单边界判断
    thisArg = (thisArg !== null && thisArg !== undefined) ? Object(thisArg): window
    //传入的对象thisArg,新增一个属性保存函数
    thisArg.fn = fn
    //通过新传入的对象调用函数,这一步导致需要被执行的函数this指向改变
    var result = thisArg.fn(...args)
    //删除属性
    delete thisArg.fn
    //返回结果
    return result
}

//测试
var jack = {
    age: 1,
    showAge: function(num1,num2) {
        console.log(this.age + num1 + num2)
    }
}

var tom = {
    age: 12
}

jack.showAge(1,1); //3
jack.showAge.myCall(tom, 1, 1); //14

js代码模拟实现apply(myApply)

Function.prototype.myApply = function(thisArg, argArray) {
    var fn = this
    thisArg = (thisArg !== null && thisArg !== undefined) ? Object(thisArg): window
    thisArg.fn = fn
    var result
    argArray = argArray || []
    result = thisArg.fn(...argArray)
    delete thisArg.fn
    return result
}

//测试
var jack = {
    age: 1,
    showAge: function(num1,num2) {
        console.log(this.age + num1 + num2)
    }
}

var tom = {
    age: 12
}

jack.showAge(1,1); //3
jack.showAge.myApply(tom, [1, 1]); //14

js代码模拟实现bind(myBind)

Function.prototype.myBind = function(thisArg, ...argArray) {
    //获取到实际需要调用的函数
    var fn = this
    thisArg = (thisArg !== null && thisArg !== undefined) ? Object(thisArg): window
    function proxyFn(...args) {
      //将函数放到thisArg中进行调用
      thisArg.fn = fn
      // 特殊: 对两个传入的参数进行合并
      var finalArgs = [...argArray, ...args]
      var result = thisArg.fn(...finalArgs)
      delete thisArg.fn
      //返回结果
      return result
    }
    //返回函数
    return proxyFn
}

//测试
var jack = {
    age: 1,
    showAge: function(num1,num2) {
        return this.age + num1 + num2;
    }
}

var tom = {
    age: 12
}

console.log(jack.showAge(1,1)); //3
console.log(jack.showAge.myBind(tom, 1, 1)()); //14
console.log(jack.showAge.myBind(tom, 1)(1)); //14