Skip to content

call、apply和bind的联系和区别

js
众所周知:
call,apply,bind函数的作用是改变this指向问题。但是具体三者的区别在于哪呢?
call,apply,bind函数挂载在Function.prototype

apply用来改变this指向,然后传递参数的时候是以数组的形式进行传递;apply把传参方式,改由数组的方式传参,接受的时候是单个参数;

1. 首先传参的问题上:
fn.call(this, arg1, arg2, arg3);
fn.apply(this, [arg1, arg2, arg3]);
fn.bind(this, arg1, arg2, arg3);

我们可以发现,call和apply除了在传参形式不同,没有什么区别。而call,apply和bind到底有什么区别呢?

2. 返回值的问题上:
fn.call(this, arg1, arg2, arg3);
fn.apply(this, [arg1, arg2, arg3]);
fn.bind(this, arg1, arg2, arg3)();

fn.bind(this, arg1, arg2, arg3);bind方法改变完this指向后,并不能直接调用函数,而是返回一个改变this指向后全新的函数。
fn.bind(this, arg1, arg2, arg3)(); ---> var fn2 = fn.bind(this, arg1, arg2, arg3);
fn2();
而call和apply在改变this指向后,会直接调用执行函数。

重写bind

  1. 首先要满足bind函数不立即执行。
  2. 其次要满足bind(this, 'zhansan')(), bind(this, 'zhansan')('male')传参方式。
  3. 最后要处理new Fn()绑定失效的问题。
js
Function.prototype.myBind = function (/* thisArg, thisArgList */) {
    // 保存当前this指向,也就是谁调用的myBind函数
    var context = this,
        // 处理参数thisArg
        thisArg = arguments[0] == undefined ? window : arguments[0],
        // 处理参数问题
        outSideArgList = Array.prototype.slice.call(arguments, 1)
    var internalFn = function () {
        var internalArgList = Array.prototype.slice.call(arguments),
            argsCollect = outSideArgList.concat(internalArgList),
            // 保存this指向
            _self = this
        context.apply(_self instanceof context ? _self : thisArg, argsCollect)
    }
    // 圣杯继承
    var inherit = (function () {
        var Buffer = function () {}
        return function (Origin, Target) {
            Buffer.prototype = Origin.prototype
            Target.prototype = new Buffer()
            Target.prototype.constructor = Target
            Target.prototype.super_class = Origin
        }
    })()
    inherit(context, internalFn)
    return internalFn
}

// 测试
var fn = Person.myBind(obj, '张三', 'male')
new fn()