先bind再apply的结果

Tansum
  • 3
新手上路,请多包涵
const obj = {
  s:'s1',
  getS(){console.log(this.s);}
}
const o = {
  s:'s2'
}
let f = obj.getS.bind(obj);
f.apply(o);//s1

查了网上说bind多次绑定只有第一次是有效的,原理解析什么的没看懂。
上面这段代码是先bind绑定,然后使用apply改变this的指向,按我这样理解的话,应该是输出s2。但是正确结果却是s1,是不是跟“bind的多次绑定只有第一次是有效的”有关?有没有哪位大佬能给我解析一下为什么会是这个结果。

回复
阅读 1.4k
3 个回答
✓ 已被采纳

bind的作用是生成一个新函数,且永久的改变该函数的this指向。用apply和call可以模拟bind,简单实现如下

function bind(fn, scope){
    return function _bindFn(){
        fn.apply(scope, arguments)
    }
}

所以你的函数 f 就是下面的函数

function _bindFn(){
    obj.getS.apply(scope, arguments)
}

这里的scope已经因为闭包的关系永久的定性为obj了。

当我们再对 f 进行bind的时候,就相当于生成了一个新函数

function bind1(){
    (function _bindFn(){
        obj.getS.apply(scope, arguments)
    }).apply(scope1, arguments)
}

bind1运行的时候,scope1改变了_bindFn中的this,但是_bindFn中的this是无效的,因为最终运行的是受scope影响的obj.getS。这就是bind嵌套发生的过程,无论嵌套多少次,最终运行的都是obj.getS.apply(scope, arguments)

理解了上面的,那么f.apply(o)为什么输出s1就简单了。

以前也纠结过,改变this指向,这种说法非常不直观,可以理解为:

var a = {
    name: '小明'
};

function b (arg) {
    console.log(this.name);
    console.log('额外参数', arg)
}

// 将 b 方法挂载到 a 上并执行
b.call(a, '参数')

以上相当于


// 想象一下,临时改变a, 变成如下对象并执行
var a = {
    name: '小明',
    b: function (arg) {
        console.log(this.name)
        console.log('额外参数', arg)
    }
};

a.b('参数')

bind则是未执行版的apply/call

所以针对你的问题,其中

let f = obj.getS.bind(obj);

------------------------

// 此时f相当于

f = function () {
    console.log('s1')
}

之后

f.apply(o)

------------------------

// 发挥一点想象力,转化为
const o = {
    s: 's2',
    f() {
        console.log('s1')
    }
}

o.f()

getS中的参数在bind时就已经绑定好了,只是没有执行而已,推荐阅读关于JS中一些重要的api实现

apply 改变的是 f 的 this 的指向。

然后 f 会调用 getS ,这时会使用 bind 的时候指定的 obj 作为 getS 的 this 。

你知道吗?

宣传栏