硬绑定 vs 软绑定

332 阅读1分钟

模拟面试场景

面试官:修改this指向的方法有哪些?
求职者:call、apply、bind
面试官:你可以手写bind吗?
求职者:可以(心中窃喜,刚好准备过)
面试官:这些方法都是显示的修改this指向,那你知道软绑定吗?可以手写一个软绑定吗?
求职者:。。。

硬绑定

可以通过call、apply、bind将函数的this指向强制绑定到指定的对象上,但是存在一个问题,就是会降低函数的灵活性,并且硬绑定之后无法再使用隐式绑定或显示绑定来修改this的执行。

软绑定

是让this在默认情况下不再指向全局对象(非严格模式)或undefined(严格模式),而是指向两者之外的一个对象,这点和硬绑定效果相同,但是同时又保留了隐式绑定和显示绑定在之后可以修改this指向的能力。

软绑定代码解释

Function.prototype.softBind = function (obj, ...arg1) {
    let that = this
    return function (...arg2) {
        return that.apply((!this || this === (window || global)) ? obj : this,
            [...arg1, ...arg2])
    }
}
function foo() {
    console.log(`name: ${this.name}`);
}
let a = { name: "a" };
let b = { name: "b" };
let c = { name: "c" };

let result = foo.softBind(a)
result() // name:a

b.foo = foo.softBind(a)
b.foo()  // name:b

result.call(c) // name:c

具体可以参考《你不知道的JavaScript 上》中的软绑定的代码实现:

if (!Function.prototype.softBind) {
    Function.prototype.softBind = function (obj) {
        var fn = this;
        var args = Array.prototype.slice.call(arguments, 1);
        var bound = function () {
            return fn.apply(
                (!this || this === (window || global)) ? obj : this,
                args.concat.apply(args, arguments)
            );
        };
        bound.prototype = Object.create(fn.prototype);
        return bound;
    };
}