underscore 源码解读之 bind 要领的完成

自从进入七月以来,我的 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 这部份,接下去的打算是去抖一篇,撙节一篇,然后其他细碎的要领提要一篇,愿望能在十月中旬摆布完毕掉吧。

    原文作者:fish
    原文地址: https://segmentfault.com/a/1190000006823820
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞