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 相关文章推荐
通过ifame指向的页面高度调整iframe的高度
Oct 05 Javascript
10个基于jQuery或JavaScript的WYSIWYG 编辑器整理
May 06 Javascript
浅说js变量
May 25 Javascript
自定义一个jquery插件[鼠标悬浮时候 出现说明label]
Jun 27 Javascript
深入理解JavaScript系列(15) 函数(Functions)
Apr 12 Javascript
关于删除时的提示处理(确定删除吗)
Nov 03 Javascript
制作jquery遮罩层效果导航菜单代码分享
Dec 25 Javascript
js类式继承的具体实现方法
Dec 31 Javascript
解决JS请求服务器gbk文件乱码的问题
Oct 16 Javascript
跟我学习javascript的作用域与作用域链
Nov 19 Javascript
微信小程序scroll-x失效的完美解决方法
Jul 18 Javascript
微信小程序 导入图标实现过程详解
Oct 11 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运行时强制显示出错信息的代码
2011/04/20 PHP
php 下载保存文件保存到本地的两种实现方法
2013/08/12 PHP
PHP中将ip地址转成十进制数的两种实用方法
2013/08/15 PHP
jQuery+PHP+ajax实现微博加载更多内容列表功能
2014/06/27 PHP
php实现图片上传时添加文字和图片水印技巧
2020/04/18 PHP
PHP实现微信JS-SDK接口选择相册及拍照并上传的方法
2016/12/05 PHP
PHP7引入的&quot;??&quot;和&quot;?:&quot;的区别讲解
2019/04/08 PHP
PHP7新功能总结
2019/04/14 PHP
不使用jquery实现js打字效果示例分享
2014/01/19 Javascript
JavaScript字符串常用类使用方法汇总
2015/04/14 Javascript
基于jQuery实现的菜单切换效果
2015/10/16 Javascript
jQuery代码实现表格中点击相应行变色功能
2016/05/09 Javascript
Html中 IFrame的用法及注意点
2016/12/22 Javascript
vuejs2.0实现一个简单的分页示例
2017/02/22 Javascript
AngularJS实现根据不同条件显示不同控件
2017/04/20 Javascript
vue中路由参数传递可能会遇到的坑
2017/12/07 Javascript
nodejs微信开发之授权登录+获取用户信息
2019/03/17 NodeJs
Vue.js实现大转盘抽奖总结及实现思路
2019/10/09 Javascript
关于vue3.0中的this.$router.replace({ path: '/'})刷新无效果问题
2020/01/16 Javascript
[01:57]DOTA2上海特锦赛小组赛解说单车采访花絮
2016/02/27 DOTA
[01:11]回顾历届DOTA2国际邀请赛中国区预选赛
2017/06/26 DOTA
视觉直观感受若干常用排序算法
2017/04/13 Python
使用python telnetlib批量备份交换机配置的方法
2019/07/25 Python
python使用PIL和matplotlib获取图片像素点并合并解析
2019/09/10 Python
Python3 合并二叉树的实现
2019/09/30 Python
关于Python字符串显示u...的解决方式
2020/03/06 Python
Python如何使用PIL Image制作GIF图片
2020/05/16 Python
如何表示python中的相对路径
2020/07/08 Python
澳大利亚领先的在线美容商城:Adore Beauty
2017/04/14 全球购物
描述一下JVM加载class文件的原理机制
2013/12/08 面试题
介绍一下.NET构架下remoting和webservice
2014/05/08 面试题
英语道歉信范文
2014/01/09 职场文书
教师读书活动总结
2014/05/07 职场文书
2014审计局领导班子民主生活会对照检查材料思想汇报
2014/09/20 职场文书
一文简单了解MySQL前缀索引
2022/04/03 MySQL
Springboot集成kafka高级应用实战分享
2022/08/14 Java/Android