自从进入七月以来,我的 underscore 源码解读系列 更新迟缓,再如许下去,本年更完的目的好像要落空,赶忙写一篇压压惊。
前文 跟人人简朴引见了下 ES5 中的 bind 要领以及运用场景(没读过的同砚发起先看看),毕竟 bind 是 ES5 的东西,低版本 IE 不支撑。本日就依据 underscore 的完成,来聊一聊怎样完成一个 bind 的 polyfill。
之前在 ECMAScript 5(ES5) 中 bind 要领简介备忘 一文中,给出了一个 “穷汉版” 的 polyfill,以下。
Function.prototype.bind = Function.prototype.bind || function(context) {
var that = this;
return function() {
return that.apply(context, arguments);
}
}
说实话,基础能够满足多半的场景需求了。bind 要领返回的照样一个要领(典范闭包),很奇妙地用 apply 转变(绑定)了 this 指向。然则毫无疑问如许简朴的完成是有题目的。
起首,该要领只支撑传入一个参数,为要领须要绑定的 this 指向,原生的 bind 要领能够传入多个参数,假如要问这些参数干吗用,转头翻翻 前文。怎样完成传参?异常简朴,传入,然后提取,不就 ok 了?
underscore 源码中重点看这几行:
var args = slice.call(arguments, 2);
var bound = function() {
// args.concat(slice.call(arguments))
// 终究函数的现实挪用参数由两部份构成
// 一部份是传入 _.bind 的参数
// 另一部份是传入 bound(_.bind 所返回要领)的参数
return executeBound(func, bound, context, this, args.concat(slice.call(arguments)));
};
return bound;
实在中心完成差不多,都是闭包返回函数。第一即将参数(args)提取保留(这些参数将会在要领中被优先挪用),返回的是一个叫做 bound 的要领,bound 也能传参啊,用 args.concat(slice.call(arguments))
将两个参数兼并当作原要领的参数,由于 args 会优先挪用,所以兼并效果 args 中元素在先。
接着来看 executeBound 函数,为什么 “穷汉版” 一行的代码,这里却要全部函数出来?原因是 “穷汉版” 没有斟酌 bind 返回函数被 new 操纵的状况。假如不是被 new 操纵,那就简朴了,和 “穷汉版” 是一样一样的,直接看 underscore 源码。
// 非 new 挪用 _.bind 返回的要领(即 bound)
// callingContext 不是 boundFunc 的一个实例
if (!(callingContext instanceof boundFunc))
return sourceFunc.apply(context, args);
假如举行 new 运算操纵呢?这里我们还要温习一下 new 运算,有兴致的能够看下我之前的文章 一道有意思的笔试题激发的关于 new 操纵符的思索。概括地讲,假如组织函数有返回值,且返回值是对象(不能是 null),那末对其举行 new 操纵返回该对象,不然返回组织实例。所以在要领 executeBound 中,我们须要进一步推断这个组织函数有无返回值,返回值是否是对象。
var executeBound = function(sourceFunc, boundFunc, context, callingContext, args) {
// 非 new 挪用 _.bind 返回的要领(即 bound)
// callingContext 不是 boundFunc 的一个实例
if (!(callingContext instanceof boundFunc))
return sourceFunc.apply(context, args);
// 假如是用 new 挪用 _.bind 返回的要领
// self 为 sourceFunc 的实例,继续了它的原型链
// self 理论上是一个空对象(还没赋值),然则有原型链
var self = baseCreate(sourceFunc.prototype);
// 用 new 天生一个组织函数的实例
// 一般状况下是没有返回值的,即 result 值为 undefined
// 假如组织函数有返回值
// 假如返回值是对象(非 null),则 new 的效果返回这个对象
// 不然返回实例
// @see http://www.cnblogs.com/zichi/p/4392944.html
var result = sourceFunc.apply(self, args);
// 假如组织函数返回了对象
// 则 new 的效果是这个对象
// 返回这个对象
if (_.isObject(result)) return result;
// 不然返回 self
// var result = sourceFunc.apply(self, args);
// self 对象当作参数传入
// 会直接转变值
return self;
};
关于这部份的源码,有兴致的同砚能够参考 https://github.com/hanzichi/u…。
关于 Function 这部份,接下去的打算是去抖一篇,撙节一篇,然后其他细碎的要领提要一篇,愿望能在十月中旬摆布完毕掉吧。