资讯专栏INFORMATION COLUMN

underscore 0.1.0版本源码阅读

Coly / 3373人阅读

摘要:前面的的目的在于利用自定义抛出错误令遍历停止如果是数组直接过滤输出不是数组遍历操作压入数组返回有点像,过滤符合条件的注意感叹号取反有点像设置默认迭代器判断是否存在即需要所有元素都满足迭代条件。

前言

这篇文章是为之后的underscore现版本的源码做铺垫,先感受下最先版本

0.1.0版本足够小

这个版本已经有将近小10年的历史了

还是有一些不错的地方。

0.1.0版本源码分析
// Underscore.js
// (c) 2009 Jeremy Ashkenas, DocumentCloud Inc.
// Underscore is freely distributable under the terms of the MIT license.
// Portions of Underscore are inspired by or borrowed from Prototype.js, 
// Oliver Steele"s Functional, And John Resig"s Micro-Templating.
// For all details and documentation:
// http://documentcloud.github.com/underscore/
window._ = {
  
  VERSION : "0.1.0",
  
  /*------------------------ Collection Functions: ---------------------------*/
  // 集合函数
  // The cornerstone, an each implementation.
  // Handles objects implementing forEach, each, arrays, and raw objects.

  each : function(obj, iterator, context) {
    var index = 0;
    try {
      if (obj.forEach) {
        // 有forEach优先选择forEach
        obj.forEach(iterator, context);
      } else if (obj.length) {
        // 使用自定义迭代器迭代
        for (var i=0; i= result.computed) result = {value : value, computed : computed};
      // 对初始化以及每一次判断computed大于当前值更新
    });
    return result.value;
  },
  
  // Return the minimum element (or element-based computation).
  min : function(obj, iterator, context) {
    if (!iterator && _.isArray(obj)) return Math.min.apply(Math, obj);
    var result;
    _.each(obj, function(value, index) {
      var computed = iterator ? iterator.call(context, value, index) : value;
      if (result == null || computed < result.computed) result = {value : value, computed : computed};
    });
    return result.value;
  },
  
  // Sort the object"s values by a criteria produced by an iterator.
  sortBy : function(obj, iterator, context) {
    // 根据对象的一些值进行排序
    // 首先我们只要关注每个函数的目的即可
    // map一次遍历,返回多个对象数组。然后根据数组对象排序
    // 并且对象均有值为criteria表示我们迭代函数的值(就是根据什么排序)
    return _.pluck(_.map(obj, function(value, index) {
      return {
        value : value,
        criteria : iterator.call(context, value, index)
      };
    }).sort(function(left, right) {
      var a = left.criteria, b = right.criteria;
      // 判断大于小于等于
      return a < b ? -1 : a > b ? 1 : 0;
    }), "value");
    // 外面的一层pluck是为了解开map函数的一层打包
  },
  
  // Use a comparator function to figure out at what index an object should
  // be inserted so as to maintain order. Uses binary search.
  // 这是利用二分查找吧
  // 利用二分查找找出元素应该插入到哪个位置中
  sortedIndex : function(array, obj, iterator) {
    iterator = iterator || function(val) { return val; };
    // 初始化一个迭代器
    var low = 0, high = array.length;//不严谨直接去length
    // 初始化高低位
    // 
    while (low < high) {
      var mid = (low + high) >> 1;
      // 对中位取半(important快捷方法)
      iterator(array[mid]) < iterator(obj) ? low = mid + 1 : high = mid;
    }
    return low;
  },
  
  // Convert anything iterable into a real, live array.
  // 转换数组(转换一切可迭代的)
  toArray : function(iterable) {
    if (!iterable) return []; //为假值直接返回[]
    if (_.isArray(iterable)) return iterable; //判断是否为数组
    return _.map(iterable, function(val){ return val; });//如果为对象的话,利用map转成数组
  },
  
  // Return the number of elements in an object.
  // 返回对象的元素数量
  size : function(obj) {
    return _.toArray(obj).length;
  },
  
  /*-------------------------- Array Functions: ------------------------------*/
  
  // Get the first element of an array.
  // 返回数组第一个元素
  first : function(array) {
    return array[0];
  },
  
  // Get the last element of an array.
  // 返回数组最后一个元素
  last : function(array) {
    return array[array.length - 1];
  },
  
  // Trim out all falsy values from an array.
  //去除假值的数组元素
  //需要传入一个操作函数 false值在两次取反会被去掉
  compact : function(array) {
    return _.select(array, function(value){ return !!value; });
  },
  
  // Return a completely flattened version of an array.
  //多维数组返回一个一维数组
  // 数组扁平化
  // 开始展现出函数式编程的灵活性了
  flatten : function(array) {
    return _.inject(array, [], function(memo, value) {
      // 这边如果还是数组的话进行一个递归的扁平
      if (_.isArray(value)) return memo.concat(_.flatten(value));
      memo.push(value);
      return memo;
    });
  },
  
  // Return a version of the array that does not contain the specified value(s).
  // 对传入的数组进行筛选
  // 这里有一个点,我们在传参形参定义了array
  // 而在下面的地方我们可以直接使用array且slice截取arguments
  
  without : function(array) {
    var values = array.slice.call(arguments, 0);
    return _.select(array, function(value){ return !_.include(values, value); });
  },
  
  // Produce a duplicate-free version of the array. If the array has already
  // been sorted, you have the option of using a faster algorithm.
  // 唯一的数组。有一个参数可以选择是否排序的数组,是的话会选择最快的算法
  uniq : function(array, isSorted) {
    return _.inject(array, [], function(memo, el, i) {
      if (0 == i || (isSorted ? _.last(memo) != el : !_.include(memo, el))) memo.push(el);
      return memo;
    });
  },
  
  // Produce an array that contains every item shared between all the 
  // passed-in arrays.
  // 筛选多个元素数组的相同值
  intersect : function(array) {
    var rest = _.toArray(arguments).slice(1);
    // 获得其余多个参数
    // 最外面肯定是一层筛选。
    // 里面做筛选的条件
    return _.select(_.uniq(array), function(item) {
      return _.all(rest, function(other) { 
        // 目的在于取交集
        // 所以我们使用外层的item 对比层的个个数组 据此我们返回同时存在多个数组中的元素
        return _.indexOf(other, item) >= 0;
      });
    });
  },
  
  // Zip together multiple lists into a single array -- elements that share
  // an index go together.
  zip : function() {
    var args = _.toArray(arguments);
    var length = _.max(_.pluck(args, "length"));
    // 返回最大数组的长度。
    var results = new Array(length);
    // 创建一个存放点
    for (var i=0; i提取替换
    var fn = new Function("obj", 
      "var p=[],print=function(){p.push.apply(p,arguments);};" +
      "with(obj){p.push("" +
      str
        .replace(/[
	
]/g, " ") 
        .split("<%").join("	") 
        .replace(/((^|%>)[^	]*)"/g, "$1
") 
        .replace(/	=(.*?)%>/g, "",$1,"") 
        .split("	").join("");") 
        .split("%>").join("p.push("") 
        .split("
").join(""") 
    + "");}return p.join("");");
    return data ? fn(data) : fn;  
  }
  
};
总结

后面的模板实现挺亮眼。

try catch 设计each的跳出。

>> 取半的快捷

函数的复用。(有部分也许是不高效)

整个版本时间很前。所以我们可以从中看到一些现代api的影子,也许是在现代api中看到它们的影子。

源码篇幅较少,加上注释也不过400行左右。整篇阅读下来也没有很大的障碍,就是有复用性相对较高,但是对着test文件看看测试用例也就好了~~~

可以通过这些地方联系我

我的博客
我的邮箱:kang95630@gmail.com

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/93320.html

相关文章

  • 从用 void 0 代替 undefined 说起

    摘要:最近开始看源码,并将源码解读放在了我的计划中。相对于其他源码解读的文章,基本都会从整体设计开始讲起,楼主觉得这个库有点特殊,决定按照自己的思路,从用代替说起。源码没有出现注意,其实有出现一处,是为,而不是,而用代替之。 Why underscore 最近开始看 underscore源码,并将 underscore源码解读 放在了我的 2016计划 中。 阅读一些著名框架类库的源码,就好...

    Cc_2011 评论0 收藏0
  • underscore源码该如何阅读

    摘要:所以它与其他系列的文章并不冲突,完全可以在阅读完这个系列后,再跟着其他系列的文章接着学习。如何阅读我在写系列的时候,被问的最多的问题就是该怎么阅读源码我想简单聊一下自己的思路。感谢大家的阅读和支持,我是冴羽,下个系列再见啦 前言 别名:《underscore 系列 8 篇正式完结!》 介绍 underscore 系列是我写的第三个系列,前两个系列分别是 JavaScript 深入系列、...

    weknow619 评论0 收藏0
  • axios源码阅读(一)

    摘要:开始研究核心代码这个类首先是构造函数看完上面的内容大家应该有点印象,上挂了和,是默认的配置,顾名思义就是拦截器,目测包含了和两种类型。喜欢就点个赞吧参考文章源代码重点难点分析源代码重点难点分析 axios是一个基于promise的http库,支持浏览器和node端,最近我在做beauty-we的api设计,研读一个成熟的http库势在必行,axios功能完整、api简洁、注释清晰,再适...

    k00baa 评论0 收藏0
  • underscore源码阅读之一

    摘要:此次源码分析为以前曾读过一次,可是没有做下笔记。类似的兼容写法记录版本号优化回调特指函数中传入的回调是一个真正的因为是可以被赋值的防止值被篡改接下来就是保证回调函数的执行上下文。 此次源码分析为 1.8.3 version 以前曾读过一次,可是没有做下笔记。此次重新阅读特制此笔记 Baseline setup underscore是包裹在一个闭包内部的防止污染全局变量 (functio...

    Sleepy 评论0 收藏0
  • 源码解读这半年

    摘要:作者韩子迟不知不觉间,源码解读系列进入了真正的尾声,也请允许我最后一次下项目的原始地址这半年以来,花费了大量的业余时间,共计写了篇随笔包括此文,也给的源码加了差不多行注释,对于当初说的要做史上最详细的源码剖析,至此我也觉得问心无愧。 作者:韩子迟 What? 不知不觉间,「Underscore 源码解读系列」进入了真正的尾声,也请允许我最后一次 po 下项目的原始地址 https://...

    zzzmh 评论0 收藏0

发表评论

0条评论

Coly

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<