Underscore源码分析


Posted in Javascript onDecember 30, 2015

几年前就有人说javascript是最被低估一种编程语言,自从nodejs出来后,全端(All Stack/Full Stack)概念日渐兴起,现在恐怕没人再敢低估它了。javascrip是一种类C的语言,有C语言基础就能大体理解javascript的代码,但是作为一种脚本语言,javascript的灵活性是C所远远不及的,这也会造成学习上的一些困难。

一、集合

 1.首先是几个迭代的方法。

_.each = _.forEach = function(obj, iteratee, context) {
iteratee = optimizeCb(iteratee, context);
var i, length;
if (isArrayLike(obj)) {
 for (i = 0, length = obj.length; i < length; i++) {
  iteratee(obj[i], i, obj);
 }
} else {
 var keys = _.keys(obj);
 for (i = 0, length = keys.length; i < length; i++) {
  iteratee(obj[keys[i]], keys[i], obj);
 }
}
// 链式调用
return obj;
 };

ES为数组同样添加了原生的forEach()方法。不同的是这里的each(forEach)方法可以对所有集合使用,函数接受三个参数(集合、迭代函数、执行环境)。

optimizeCb函数根据迭代函数参数个数的不同为不同的迭代方法绑定了相应的执行环境,forEach迭代函数同样接受三个参数(值,索引,集合)。

接下来就是for循环调用迭代函数了。 

_.map中一种更优雅的判断isArrayLike的实现方式:(只用一个for循环)

var keys = !isArrayLike(obj) && _.keys(obj),
    length = (keys || obj).length,
    results = Array(length);
  for (var index = 0; index < length; index++) {
   var currentKey = keys ? keys[index] : index;
   results[index] = iteratee(obj[currentKey], currentKey, obj);
  }
  return results;
  // 合理使用&&、||、?:可以大大减少代码量

还有两个特别的地方:

•将集合分成了类数组集合和对象集合。使用了isArrayLike函数:

// js的最大精确整数
 var MAX_ARRAY_INDEX = Math.pow(2, 53) - 1;
 var isArrayLike = function(collection) {
var length = collection != null && collection.length;
return typeof length == 'number' && length >= 0 && length <= MAX_ARRAY_INDEX;
 }; // 如果集合有Length属性且为数字并且大于0小于最大的精确整数,则判定是类数组

 •使用了_.keys函数,Object同样有原生的keys函数,用于返回一个集合obj可被枚举的属性数组。实现比较简单,for in加上hasOwnProperty()方法。

--------------------------------------------------------------------------------

_.map,_.reduce方法原理类似.

 _.find函数和Array.some()类似,不同的是返回的是第一个使迭代结果为真的那个元素,而不是Array.some()那样返回布尔值。

_.find = _.detect = function(obj, predicate, context) {
  var key;
  if (isArrayLike(obj)) {
   key = _.findIndex(obj, predicate, context);
  } else {
   key = _.findKey(obj, predicate, context);
  }
  if (key !== void 0 && key !== -1) return obj[key];
 };
function createIndexFinder(dir) {
  return function(array, predicate, context) {
   predicate = cb(predicate, context);
   var length = array != null && array.length;
   // 如果dir为1,index为0,index+=1,index正序循环
   // 如果dir 为-1,index为length-1,index += -1反序循环
   // 判断循环条件则用了index >= 0 && index < length方法兼顾两种循环方式
   var index = dir > 0 ? 0 : length - 1;
   for (; index >= 0 && index < length; index += dir) {
    if (predicate(array[index], index, array)) return index;
   }
   return -1;
  };
 }
 _.findIndex = createIndexFinder(1);
 _.findLastIndex = createIndexFinder(-1);

值得借鉴的地方是这里的一个for循环能够根据传入的参数不同配置不同的循环顺序。

 1.集合中的其他方法基本都是基于迭代方法来实现的。

_.max = function(obj, iteratee, context) {
var result = -Infinity, lastComputed = -Infinity,
  value, computed;
if (iteratee == null && obj != null) {
 obj = isArrayLike(obj) ? obj : _.values(obj);
 for (var i = 0, length = obj.length; i < length; i++) {
  value = obj[i];
  if (value > result) {
   result = value;
  }
 }
} else {
 iteratee = cb(iteratee, context);
 _.each(obj, function(value, index, list) {
  computed = iteratee(value, index, list);
  if (computed > lastComputed || computed === -Infinity && result === -Infinity) {
   result = value;
   lastComputed = computed;
  }
 });
}
return result;
 };

  max方法用于寻找集合中的最大值,通过循环list中的所有项,然后比较当前项和结果项,如果当前项大于结果,则将其赋给结果项,最后返回结果项。

 2.集合转换为数组

_.toArray = function(obj) {
    if (!obj) return [];
    // 如果是数组,采用了Array.prototype.slice.call(this,obj)这种方法
    if (_.isArray(obj)) return slice.call(obj);
    // 类数组对象,这里没有采用Slice方法,而是利用.map对集合进行迭代,从而返回一个数组。 _.identity该方法传入的值和返回的值相等。(主要用于迭代)
    if (isArrayLike(obj)) return _.map(obj, _.identity);
    // 普通对象,则返回由属性值组成的数组。
    return _.values(obj);
   };

数据类型

STL需要对vector、list等进行区分是因为不同的数据结构需要或者可以进行不同的实现,但underscore里面Collections和Arrays分开是什么道理呢?这也要从javascript的数据类型说起,看下图。

Underscore源码分析

Javascript 相关文章推荐
从父页面读取和操作iframe中内容方法
Jul 25 Javascript
jQuery插件实现表格隔行换色且感应鼠标高亮行变色
Sep 22 Javascript
简单漂亮的js弹窗可自由拖拽且兼容大部分浏览器
Oct 22 Javascript
JS中产生20位随机数以0-9为例也可以是a-z A-Z
Aug 01 Javascript
jQuery+json实现的简易Ajax调用实例
Dec 14 Javascript
一个非常好用的文字滚动的案例,鼠标悬浮可暂停[两种方案任选]
Dec 01 Javascript
js构造函数创建对象是否加new问题
Jan 22 Javascript
electron实现qq快捷登录的方法示例
Oct 22 Javascript
vue日历/日程提醒/html5本地缓存功能
Sep 02 Javascript
layui禁用侧边导航栏点击事件的解决方法
Sep 25 Javascript
JavaScript进阶(四)原型与原型链用法实例分析
May 09 Javascript
Vue项目前后端联调(使用proxyTable实现跨域方式)
Jul 18 Javascript
Jsonp 关键字详解及json和jsonp的区别,ajax和jsonp的区别
Dec 30 #Javascript
javascript实现禁止复制网页内容汇总
Dec 30 #Javascript
jquery实现树形菜单完整代码
Dec 29 #Javascript
javascript设置页面背景色及背景图片的方法
Dec 29 #Javascript
js获取及修改网页背景色和字体色的方法
Dec 29 #Javascript
基于JavaScript实现根据手机定位获取当前具体位置(X省X市X县X街道X号)
Dec 29 #Javascript
jQuery中attr()与prop()函数用法实例详解(附用法区别)
Dec 29 #Javascript
You might like
php魔术方法与魔术变量、内置方法与内置变量的深入分析
2013/06/03 PHP
php 的多进程操作实践案例分析
2020/02/28 PHP
jquery特效 幻灯片效果示例代码
2013/07/16 Javascript
Nodejs极简入门教程(二):定时器
2014/10/25 NodeJs
24款热门实用的jQuery插件推荐
2014/12/24 Javascript
jQuery中[attribute=value]选择器用法实例
2014/12/31 Javascript
高性能JavaScript模板引擎实现原理详解
2015/02/05 Javascript
浅谈jQuery.easyui的datebox格式化时间
2015/06/25 Javascript
又一款MVVM组件 构建自己的Vue组件(2)
2017/03/13 Javascript
React Router V4使用指南(精讲)
2018/09/17 Javascript
详解基于webpack&amp;gettext的前端多语言方案
2019/01/29 Javascript
nodejs实现获取本地文件夹下图片信息功能示例
2019/06/22 NodeJs
ant design vue datepicker日期选择器中文化操作
2020/10/28 Javascript
[44:40]Serenity vs Pain 2018国际邀请赛小组赛BO2 第一场 8.19
2018/08/21 DOTA
基于Python数据可视化利器Matplotlib,绘图入门篇,Pyplot详解
2017/10/13 Python
Python实现聊天机器人的示例代码
2018/07/09 Python
Django代码性能优化与Pycharm Profile使用详解
2018/08/26 Python
python 找出list中最大或者最小几个数的索引方法
2018/10/30 Python
使用Python 自动生成 Word 文档的教程
2020/02/13 Python
解决jupyter notebook 前面书写后面内容消失的问题
2020/04/13 Python
Django微信小程序后台开发教程的实现
2020/06/03 Python
python 实现Harris角点检测算法
2020/12/11 Python
让IE可以变相支持CSS3选择器
2010/01/21 HTML / CSS
建筑毕业生自我鉴定
2013/10/18 职场文书
四好少年事迹材料
2014/01/12 职场文书
期末学生评语大全
2014/04/24 职场文书
我的理想演讲稿
2014/04/30 职场文书
乡镇党的群众路线教育实践活动领导班子对照检查材料
2014/09/25 职场文书
我们的节日重阳节活动总结
2015/03/24 职场文书
2016年植树节红领巾广播稿
2015/12/17 职场文书
安全生产标语口号
2015/12/26 职场文书
python基础之while循环语句的使用
2021/04/20 Python
Pytorch 中net.train 和 net.eval的使用说明
2021/05/22 Python
MySQL 百万级数据的4种查询优化方式
2021/06/07 MySQL
MySQL 用 limit 为什么会影响性能
2021/09/15 MySQL
Python字符串的转义字符
2022/04/07 Python