underscore源碼分析(1)

underscore 版本1.83 最主要的一個特性是鏈式調用app

_([1,2,3]).each(console.log)
// 1 0 (3) [1, 2, 3]
// 2 1 (3) [1, 2, 3]
// 3 2 (3) [1, 2, 3]

咱們先簡單的實現鏈式調用的功能
實現 _.each([1,2,3],console.log) 是很簡單的 ,直接_.each函數就搞定了函數

關鍵的_().each實現思路也很簡單,咱們能夠這麼理解
當咱們返回了new _(obj),若是想調用each方法時,只要把each綁定到prototype就能夠了
咱們再把傳參obj傳給each方法,可參考_.each.apply(_, args)
jsfiddle在線調試this

var _ = function(obj) {
  //由於new _持續調用_, 因此加入if 控制死循環
  if (!(this instanceof _)) return new _(obj);
  //把傳入的obj參數保存起來
  this._wrapped = obj;
};

_.each = function(obj, iteratee) {
  var i, length;
  for (i = 0, length = obj.length; i < length; i++) {
       iteratee(obj[i], i, obj);
    }
  return obj;
};

_.prototype.each = function() {
  var args = [this._wrapped];
  [].push.apply(args, arguments);
  return _.each.apply(_, args)
};

_.each([1,2,3],console.log)
_([1,2,3]).each(console.log)

可是 咱們怎麼實現下面的功能呢?.net

_([1,2,3]).map(function(a){return a * 2}).each(console.log) //報錯
// 2 0
// 4 1
// 6 2

在用underscore的時候咱們發現有個_.chain方法,能夠實現鏈式連寫prototype

_.chain([1,2,3]).map(function(a){return a * 2}).each(console.log)

// 2 0
// 4 1
// 6 2

咱們接下來簡單實現
主要的關鍵點是chainResult函數,返回_(obj).chain()jsfiddle在線調試調試

var _ = function(obj) {
  if (obj instanceof _) return obj;
  if (!(this instanceof _)) return new _(obj);
  this._wrapped = obj;
};

_.each = function(obj, iteratee) {
  var i, length;
  for (i = 0, length = obj.length; i < length; i++) {
       iteratee(obj[i], i, obj);
    }
  return obj;
};
_.map = function(obj, iteratee, context) {
    var length = obj.length,
        results = Array(length);
    for (var index = 0; index < length; index++) {
      results[index] = iteratee(obj[index], index, obj);
    }
    return results;
  };
 var chainResult = function(instance, obj) {
    return instance._chain ? _(obj).chain() : obj;
  };
  
_.chain = function(obj) {
  var instance = _(obj);
  instance._chain = true;
  return instance;
};

_.prototype.each = function() {
  var args = [this._wrapped];
  [].push.apply(args, arguments);
  return chainResult(this, _.each.apply(_, args))
};
_.prototype.map = function() {
  var args = [this._wrapped];
  [].push.apply(args, arguments);
  return chainResult(this, _.map.apply(_, args))
};
_.prototype.chain = function() {
  var args = [this._wrapped];
  [].push.apply(args, arguments);
  return chainResult(this, _.chain.apply(_, args))
};

_.chain([1,2,3]).map(function(a){ return a * 2}).each(console.log)

咱們發現prototype原型鏈的時候調用的方法都同樣的,能夠寫個函數循環jsfiddle在線調試code

function mixin(){
  _.each(['chain', 'each', 'map'], function(name) {
    var func = _[name]
    _.prototype[name] = function() {
      var args = [this._wrapped];
      [].push.apply(args, arguments);
      return chainResult(this, func.apply(_, args));
    };
  });
}
相關文章
相關標籤/搜索