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 相关文章推荐
IE6、IE7中setAttribute不支持class/for/rowspan/colspan等属性
Aug 28 Javascript
JS控件的生命周期介绍
Oct 22 Javascript
cookie.js 加载顺序问题怎么才有效
Jul 31 Javascript
jQuery让控件左右移动的三种实现方法
Sep 08 Javascript
director.js实现前端路由使用实例
Feb 03 Javascript
让图片跳跃起来  javascript图片轮播特效
Feb 16 Javascript
JavaScript中关于for循环删除数组元素内容时出现的问题
Nov 21 Javascript
Javascript ES6中对象类型Sets的介绍与使用详解
Jul 17 Javascript
ECMAScript6变量的解构赋值实例详解
Sep 19 Javascript
Vue 去除路径中的#号
Apr 19 Javascript
js实现简单模态框实例
Nov 16 Javascript
JavaScript在web自动化测试中的作用示例详解
Aug 25 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 fastcgi模式上传大文件(大约有300多K)报错
2014/09/28 PHP
如何使用PHP给图片加水印
2016/10/12 PHP
详解Yii2 之 生成 URL 的方法
2017/06/16 PHP
PHP单例模式模拟Java Bean实现方法示例
2018/12/07 PHP
JavaScript window.setTimeout() 的详细用法
2009/11/04 Javascript
jQuery操作 input type=checkbox的实现代码
2012/06/14 Javascript
Js 回车换行处理的办法及replace方法应用
2013/01/24 Javascript
jquery实现商品拖动选择效果代码(自写)
2013/05/28 Javascript
javascript创建数组之联合数组的使用方法示例
2013/12/26 Javascript
动态加载iframe时get请求传递中文参数乱码解决方法
2014/05/07 Javascript
利用jquery禁止外层滚动条的滚动
2017/01/05 Javascript
jquery.cookie.js的介绍与使用方法
2017/02/09 Javascript
Angular.js中定时器循环的3种方法总结
2017/04/27 Javascript
纯js代码生成可搜索选择下拉列表的实例
2018/01/11 Javascript
JS实现520 表白简单代码
2018/05/21 Javascript
浅谈vue父子组件怎么传值
2018/07/21 Javascript
使用原生js编写一个简单的框选功能方法
2019/05/13 Javascript
JS浮点数运算结果不精确的Bug解决
2019/08/01 Javascript
Vuex模块化应用实践示例
2020/02/03 Javascript
Python的多态性实例分析
2015/07/07 Python
Python中datetime模块参考手册
2017/01/13 Python
Python实现Smtplib发送带有各种附件的邮件实例
2017/06/05 Python
使用pandas模块读取csv文件和excel表格,并用matplotlib画图的方法
2018/06/22 Python
python hook监听事件详解
2018/10/25 Python
pycharm修改file type方式
2019/11/19 Python
Tensorflow累加的实现案例
2020/02/05 Python
Pycharm同步远程服务器调试的方法步骤
2020/11/04 Python
英国最大的奢侈珠宝和手表网站:C W Sellors
2017/02/10 全球购物
英国最大最好的无人机商店:Drones Direct
2019/07/12 全球购物
车间操作工岗位职责
2013/12/19 职场文书
放飞中国梦演讲稿
2014/04/23 职场文书
实习护士自荐信
2014/06/21 职场文书
平凡的世界读书笔记
2015/06/25 职场文书
python中os.path.join()函数实例用法
2021/05/26 Python
MySQL中distinct和count(*)的使用方法比较
2021/05/26 MySQL
分享几种python 变量合并方法
2022/03/20 Python