关于javascript:神奇的-JavaScript-之-bindbindbind

41次阅读

共计 1410 个字符,预计需要花费 4 分钟才能阅读完成。

事件起源于一段 JS 代码:

function bind(func, context) {var args = nativeSlice.call(arguments, 2);
    return function () {return func.apply(context, args.concat(nativeSlice.call(arguments)));
    };
}

源代码出自 echarts 的底层依赖 zrender,为了优化我的 offscreen-echarts 库我在读 echarts 的源码,于是就发现了这段代码。

干嘛要本人从新实现一遍 bind,难道还有浏览器不反对?于是去查了一下 MDN:

好吧,果然是我大 IE8。想到 echarts 里大量的 VML 代码,我大百度还是对 IE8 用户这类濒危物种放心不下啊。然而看这个 bind 实现又是 apply 又是 concat 又是 slice 又是 call 的,性能必定好不到哪去。

然而干嘛非要让咱们这些 Chrome 用户为 IE 这种糟粕付出代价呢?

不行,非得改改不可(重度强迫症患者)。然而代码都曾经用了 bind(f, xxx) 而不是 f.bind(xxx)function bind 是逃不掉了,你只能用原生的 Function.prototype.bind 去优化这个 function bind

仔细观察这个 function bind 的用法

bind(f, {}, 1, 2, 3)(4, 5, 6);

与原生 Function.prototype.bind 用法

f.bind({}, 1, 2, 3)(4,5,6);

的区别,function bind 把原生 bindthis 作为参数传了,这不就是 call 吗?所以能够改写为

Function.prototype.bind.call(f, {}, 1, 2, 3)(4, 5, 6);

所以咱们的 function bind 就是 Function.prototype.bind.call,只不过它的 thisFunction.prototype.bind。扭转一个函数的 this 须要 bind,所以就有

var bind = Function.prototype.bind.call.bind(Function.prototype.bind);

Function.prototype.bind.call.bindcallthis 曾经前面由 bind 指定了,call 后面的 this 曾经失去了意义,所以其等价于

var bind = Function.prototype.call.bind(Function.prototype.bind);

咱们须要在浏览器反对原生 bind 的前提下用新实现笼罩原始的 function bind,所以改写为

if (bind.bind) {bind = bind.call.bind(bind.bind);
}

bind.bind === Function.prototype.bind,和 [].slice === Array.prototype.slice 一个意思。

这里其实曾经是最佳实现了,因为只是把原生 bind 应用 call 办法调用,性能简直等同于原生 bind 的性能。如果把参数 bind.bind 移到函数后面再 bind 一层,就变成

if (bind.bind) {bind = bind.bind.bind(bind.call);
}

于是就呈现了 bind.bind.bind。然而因为这里其实有两层 bind 所以理论性能是有损耗的:https://jsben.ch/sEcop

正文完
 0