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 相关文章推荐
jQuery 判断元素上是否绑定了事件
Oct 28 Javascript
基于jQuery的弹出消息插件 DivAlert之旅(一)
Apr 01 Javascript
JavaScript 存在陷阱 删除某一区域所有节点
May 10 Javascript
一个简单的js动画效果代码
Jul 20 Javascript
jquery.post用法关于type设置问题补充
Jan 03 Javascript
基于JavaScript实现定时跳转到指定页面
Jan 01 Javascript
javascript 中事件冒泡和事件捕获机制的详解
Sep 01 Javascript
Less 安装及基本用法
May 05 Javascript
AngularJS与后端php的数据交互方法
Aug 13 Javascript
JS实现在线ps功能详解
Jul 31 Javascript
javascript设计模式 ? 解释器模式原理与用法实例分析
Apr 17 Javascript
利用JavaScript模拟京东按键输入功能
Dec 01 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
PHP5在Apache下的两种模式的安装
2006/09/05 PHP
一些需要禁用的PHP危险函数(disable_functions)
2012/02/23 PHP
PHP使用preg_split和explode分割textarea存放内容的方法分析
2017/07/03 PHP
如何通过Apache在本地配置多个虚拟主机
2020/07/29 PHP
鼠标事件的screenY,pageY,clientY,layerY,offsetY属性详解
2015/03/12 Javascript
基于jQuery实现Ajax验证用户名是否存在实例
2016/03/30 Javascript
javascript弹出带文字信息的提示框效果
2016/07/19 Javascript
js 数字、字符串、布尔值的转换方法(必看)
2017/04/07 Javascript
vue项目中用cdn优化的方法
2018/01/03 Javascript
AngularJS下$http服务Post方法传递json参数的实例
2018/03/29 Javascript
JavaScript函数、闭包、原型、面向对象学习笔记
2018/09/06 Javascript
vue-父子组件和ref实例详解
2019/11/10 Javascript
微信小程序图片加载失败时替换为默认图片的方法
2019/12/09 Javascript
angularjs模态框的使用代码实例
2019/12/20 Javascript
vue从零实现一个消息通知组件的方法详解
2020/03/16 Javascript
[05:08]顺网杯ISS-DOTA2赛歌 少女偶像Lunar青春演绎
2013/12/05 DOTA
pymongo为mongodb数据库添加索引的方法
2015/05/11 Python
python验证码识别实例代码
2018/02/03 Python
Python实现的网页截图功能【PyQt4与selenium组件】
2018/07/12 Python
pandas去除重复列的实现方法
2019/01/29 Python
pandas DataFrame索引行列的实现
2019/06/04 Python
python对象转字典的两种实现方式示例
2019/11/07 Python
PyInstaller将Python文件打包为exe后如何反编译(破解源码)以及防止反编译
2020/04/15 Python
Python将二维列表list的数据输出(TXT,Excel)
2020/04/23 Python
pycharm实现print输出保存到txt文件
2020/06/01 Python
Python xlrd/xlwt 创建excel文件及常用操作
2020/09/24 Python
资产经营总监岗位职责
2013/12/04 职场文书
捐书活动总结
2014/05/04 职场文书
公证委托书
2014/08/01 职场文书
大学生自我评价200字(4篇)
2014/09/17 职场文书
群众路线教育实践活动对照检查材料思想汇报(副处级领导)
2014/10/04 职场文书
装配车间主任岗位职责
2015/04/08 职场文书
2015年汽车销售员工作总结
2015/07/24 职场文书
基于Nginx实现限制某IP短时间访问次数
2021/03/31 Servers
Python中的程序流程控制语句
2022/02/24 Python
NoSQL优缺点与MongoDB数据库简介
2022/06/05 MongoDB