关于改变this指向的call bind apply


    /**
     * 我们可以利用改变this指向,实现构造函数的继承
     */
    function Name(name,params) {
        this.name = name
        this.params = params
    }
    function title(age,params,name) {
        // 这里转化成了 this.name = name this.params = params
        // Name.call(this,name,params)
        var a = Name.bind(this)
        a(name,params)
        this.age = age
    }
    var a = new title('123','234','345')
    console.log(a); // title { name: '345', params: '234', age: '123' }
    


    /**
     * apply 的参数是数组,call 的参数直接往后面加
     * bind 可以预定义参数,会返回一个方法,不会立即执行(即硬绑定:被硬绑定过的函数,this指向不会再被改变)
     */
    let obj1 = {0:'a',1:'b',length:2}
    let obj2 = {0:'a',1:'b',length:2}
    let obj3 = {0:'a',1:'b',length:2}
    let re1 = Array.prototype.push.call(obj1,'c','d')
    let re2 = Array.prototype.push.apply(obj2,['c','d'])
    let re3 = Array.prototype.push.bind(obj3,'c')
    re3('d')
    console.log(obj1,re1);
    console.log(obj2,re2);
    console.log(obj3,re3);

    /**
     * 这里我们来试着自己实现一个硬绑定,看看为什么bind后,为什么就不能改变this了
     * 
     * 通过bind 把 foo 包裹在 bar 中,通过bar调用foo,所以就改变不了foo的this指向了
     * 这里其实我也可以发现,bind 好像是apply 或者call封装了一层
     */
    function foo(arg) {
        return {name:this.name,arg:arg}
    }
    Function.prototype.mybind = function mybind(fn,obj) {
    	const fn = this
        return function () {
            return fn.apply(obj,arguments)
        }
    }
    let tom = {name:'tom的name'}
    let bob = {name:'bob的name'}
    let bar = foo.mybind(tom)
    let bar1 = foo.bind(tom)
    console.log(bar(111)); // { name: 'tom的name', arg: 111 }
    console.log(bar.call(bob,222)); // { name: 'tom的name', arg: 222 }
    console.log(bar1.call(bob,222)); // { name: 'tom的name', arg: 222 }
    console.log(foo.call(bob,333)); // { name: 'bob的name', arg: 333 }

    /**
     * 下面是关于forEach的第二个参数 thisValue的描述
     * 《可选。传递给函数的值一般用 "this" 值。如果这个参数为空, "undefined" 会传递给 "this" 值》
     * 由此我们可以知道,call apply是由forEach封装的。这就像let也是try catch封装的
     */
    function foo(e) {
        console.log(e,this.id);
    }
    var obj = {id:'123'}
    var arr = Object.keys(obj)
    arr.forEach(foo,obj)
    

    let obj = {0:'a',1:'b',length:2}
    let myObj = {
        _push: function (...e) {
            let len = this.length
            let arg = arguments.length
            for (let i = 0; i < arg; i++) {
                this[len+i] = e[i]
            }
            this.length = len + arg
            return this.length
        }
    }
    myObj._push.apply(obj,['c','d']) // obj {'0': 'a','1': 'b','2': 'c','3': 'd',length: 4}
    myObj._push.bind(obj,'d')('e','f') // obj {'0': 'a','1': 'b','2': 'c','3': 'd','4': 'd','5': 'e','6': 'f',length: 7}

小结

  • this指向优先级问题 new > bind(显式-硬绑定) > apply/call(显式绑定) > 隐式绑定 > 默认绑定
  • 其中 new 可以用bind 实现; bind可以用 call 实现; call可以用 forEach 实现; forEach 就是 function + for
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值