underscore链式操作

underscore链式操作

涉及函数:_.chain(obj) === _(obj).chain()

实例:

  // 非 OOP 链式调用
  _.chain([1, 2, 3])
  .map(function(a) {return a;})
  .reverse()
  .value(); // [3, 2, 1]

  // OOP 链式调用
  _([1, 2, 3])
  .chain()
  .map(function(a){return a;})
  .first()
  .value(); // 1

解析:

以上两种方式都可以达到链式调用的目的。在underscore内部实现中,这两种方式实现都是用了OOP的实现方法,具体来看实现函数:

  _.chain = function(obj) {
    var instance = _(obj);
    instance._chain = true;
    return instance;
  };

_.chain(obj)通过调用chain()方法将_(obj)先转化为_的实例对象,然后将实例对象添加_chain属性,返回该实例对象。
【注:对于_(obj)不熟悉的可以移步
underscore中_是弄啥的】

而对于_(obj).chain()来说,首先通过_(obj)创建_的实例对象,然后该实例调用_对象原型中的chain()方法【该方法通过_.mixin()方法混入到_.prototype中】详见:underscore中OOP思想—实例对象方法调用实现机制

_.prototype['chain']方法最后一步:

  // _.mixin()方法中_.prototype[name] = function() {...}最后返回
  return chainResult(this, func.apply(_, args));
  // chainResult实现函数
  var chainResult = function(instance, obj) {
      return instance._chain ? _(obj).chain() : obj;
  };

chainResult(this, func.apply(_, args))方法中this_对象,func.apply(_, args)调用_.chain()方法返回传入对象的实例,在上面例子中就是[1, 2, 3]对象的实例对象,并给该对象添加_chain属性,返回该实例对象。此时调用为chain(_对象, [1, 2, 3]添加了_chain属性的实例对象)_._chain === undefined所以直接返回添加了_chain属性的[1, 2, 3]对象实例。

到这里是不是发现了什么?!Yes,_.chain(obj)_(obj).chain()回到了同一起跑线!

最后再梳理一下其中逻辑:chainResult实现函数通过传入的obj实例和obj对象,判断如果obj实例中含有chain属性则继续调用(obj).chain()生成具有_chain属性的obj实例对象;如果没有,则说明obj本身已经有了chain属性【因为调用该函数的都是在.prototype[XXX]中,该函数的执行最后必然会调用上面说的chainResult方法,func.apply(this, args)最终返回的一定是带有_chain属性的实例对象】,直接返回obj即可。

你可能感兴趣的:(underscore链式操作)