call, apply, bind 区别

call 和 apply 都是为了解决改变 this 的指向。作用都是相同的,只是传参的方式不同。除了第一个参数外,call 可以接收一个参数列表,apply 只接受一个参数数组

let a = {
    value: 1
}
function getValue(name, age) {
    console.log(name)
    console.log(age)
    console.log(this.value)
}
getValue.call(a, 'QJ', '20')
getValue.apply(a, ['QJ', '20'])

call:

1.将函数设为传入参数的属性
2.获取传入的参数,并执行函数
3.如果不传入参数或者参数为null,默认指向为 window / global
4.删除参数上创建的属性

   Function.prototype._call = function (context) {
    // 1. 如果第一个参数传入的是 null 或者是 undefined, 那么指向this指向 window/global
    // 如果第一个参数传入的不是null或者是undefined, 那么必须是一个对象
    if (!context) {        //context为null或者是undefined
        context = typeof window === 'undefined' ? global : window;
    } else {
        context = Object(context)
    }
    // 2. 将函数设置为对象的属性 (this指向的是当前的函数,即bar)
    context.fn = this;
    // 3. 获取除了this指向对象以外的参数
    let args = [...arguments].slice(1);
    // 4. 执行函数
    let result = context.fn(...args);
    // 5. 删除新创建的属性
    delete context.fn;
    // 6. 返回值
    return result;
}


//测试代码
var foo = {
    a: 1
}

function bar(name,age) {
    console.log(name)
    console.log(age)
    console.log(this.a)
}

bar._call(foo,'qj',20) //	qj 20  1

apply:
apply与call原理一致,不同的只是传参的方式。

 Function.prototype._apply = function (context) {
    var result
    // 1. 如果第一个参数传入的是 null 或者是 undefined, 那么指向this指向 window/global
    // 如果第一个参数传入的不是null或者是undefined, 那么必须是一个对象
    if (!context) {        //context为null或者是undefined
        context = typeof window === 'undefined' ? global : window;
    } else {
        context = Object(context)
    }
    // 2. 将函数设置为对象的属性 (this指向的是当前的函数,即bar)
    context.fn = this;
    // 3. 执行函数
    if (arguments[1]) {
        result = context.fn(...arguments[1])
    } else {
        result = context.fn()
    }
    // 4. 删除新创建的属性
    delete context.fn;
    // 5. 返回值
    return result;
}


//测试代码
var foo = {
    a: 1
}

function bar(name,age) {
    console.log(name)
    console.log(age)
    console.log(this.a)
}

bar._apply(foo,['qj',20]) // qj 20 1

bind
bind 和 call/apply 有一个很重要的区别,一个函数被 call/apply 的时候,会直接调用,但是 bind 会创建一个新函数。当这个新函数被调用时,bind() 的第一个参数将作为它运行时的 this,第二个以及以后的参数加上绑定函数运行时本身的参数按照顺序作为原函数的参数来调用原函数。

   Function.prototype._bind = function (context) {
   // 调用bind的如果不是函数,抛出异常
    if (typeof this !== "function") {
        throw new TypeError("not a function");
    }
    //保存外部函数的this, 如果不保存的话,我们就无法在闭包中使用外部函数绑定的this
    //self指向的就是我们被绑定的函数, eg: func.bind(obj). self指向的是 func
    let self = this;
    let args = [...arguments].slice(1);
    // 使用原型式继承,避免修改bound.prototype 的时候,也会修改 this.prototype的值
    var Fn = function () {};
    Fn.prototype = this.prototype;
    let bound = function () {
        let res = [...args, ...arguments]; 
        // (this instanceof self) === true时, this 就是运行 new bindFunc 时 this 的指向对象, 它指向的就是新创建的实例对象
        // (this instanceof self) === false时,调用bindFunc的形式是直接调用, 此时让 this 指向我们传入的第一个参数
        context = this instanceof Fn ? this : context;
        return self.apply(context, res);
    }    //原型链
    bound.prototype = new Fn();
    return bound;
}

var foo = {
    a: 1
}

function bar(name,age) {
    console.log(name)
    console.log(age)
    console.log(this.a)
}

var myBind = bar._bind(foo,'qj',20)
myBind() // qj 20 1
console.log('-------')

var myBind2 = bar._bind(foo,'qj')
var myBind3 = new myBind2(20) // qj 20 undefined   

一旦函数通过bind传递了有效的this对象,则该函数在运行期的this将指向这个对象,即使通过call或apply来试图改变this的指向也是徒劳的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值