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 相关文章推荐
根据地区不同显示时间的javascript代码
Aug 13 Javascript
在IE和VB中支持png图片透明效果的实现方法(vb源码打包)
Apr 01 Javascript
JavaScript快速检测浏览器对CSS3特性的支持情况
Sep 26 Javascript
利用javascript实现禁用网页上所有文本框,下拉菜单,多行文本域
Dec 14 Javascript
js实现特定位取反原理及示例
Jun 30 Javascript
jQuery三级下拉列表导航菜单代码分享
Apr 15 Javascript
微信公众号开发 实现点击返回按钮就返回到聊天界面
Dec 15 Javascript
读Javascript高性能编程重点笔记
Dec 21 Javascript
react native带索引的城市列表组件的实例代码
Aug 08 Javascript
Vue递归实现树形菜单方法实例
Nov 06 Javascript
原生js实现下拉框选择组件
Jan 20 Javascript
node中使用shell脚本的方法步骤
Mar 23 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
在JavaScript中调用php程序
2009/03/09 PHP
php若干单维数组遍历方法的比较
2011/09/20 PHP
apache php模块整合操作指南
2012/11/16 PHP
Zend Framework实现多文件上传功能实例
2016/03/21 PHP
OAuth认证协议中的HMACSHA1加密算法(实例)
2017/10/25 PHP
asp函数split()对应php函数explode()
2019/02/27 PHP
php7 list()、session及其他模块的修改实例分析
2020/05/25 PHP
验证码按回车不变解决方法
2013/03/29 Javascript
js触发select onchange事件的小技巧
2014/08/05 Javascript
js实现功能比较全面的全选和多选
2017/03/02 Javascript
webpack4 配置 ssr 环境遇到“document is not defined”
2019/10/24 Javascript
借助云开发实现小程序短信验证码的发送
2020/01/06 Javascript
js判断在哪个浏览器打开项目的方法
2020/01/21 Javascript
javascript 易错知识点实例小结
2020/04/25 Javascript
Vue Router中应用中间件的方法
2020/08/06 Javascript
TypeScript 运行时类型检查补充工具
2020/09/28 Javascript
[00:13]天涯墨客二技能展示
2018/08/25 DOTA
Python实现的当前时间多加一天、一小时、一分钟操作示例
2018/05/21 Python
python矩阵转换为一维数组的实例
2018/06/05 Python
Python检查ping终端的方法
2019/01/26 Python
python实现单链表的方法示例
2019/09/03 Python
Python使用socketServer包搭建简易服务器过程详解
2020/06/12 Python
python全栈开发语法总结
2020/11/22 Python
Python 利用flask搭建一个共享服务器的步骤
2020/12/05 Python
Python用access判断文件是否被占用的实例方法
2020/12/17 Python
Css3新特性应用之视觉效果实例
2016/12/12 HTML / CSS
美国高端医师级美容产品电商:BeautifiedYou.com
2017/04/17 全球购物
ALDO美国官网:加拿大女鞋品牌
2018/12/28 全球购物
某公司C#程序员面试题笔试题
2014/05/26 面试题
工地安全检查制度
2014/02/04 职场文书
财务管理专业自荐书
2014/09/02 职场文书
办公室文员工作自我鉴定
2014/09/19 职场文书
2015年幼儿园中班开学寄语
2015/05/27 职场文书
2015暑期工社会实践报告
2015/07/13 职场文书
基层医务人员三严三实心得体会
2016/01/05 职场文书
《槐乡的孩子》教学反思
2016/02/20 职场文书