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使用Max函数返回两个数字中较大数的方法
Apr 06 Javascript
jquery任意位置浮动固定层插件用法实例
May 29 Javascript
jquery 中ajax执行的优先级
Jun 22 Javascript
javascript解决IE6下hover问题的方法
Jul 28 Javascript
AngularJS向后端ASP.NET API控制器上传文件
Feb 03 Javascript
微信小程序 在Chrome浏览器上运行以及WebStorm的使用
Sep 27 Javascript
AngularJS extend用法详解及实例代码
Nov 15 Javascript
深入理解vue.js双向绑定的实现原理
Dec 05 Javascript
JS检测是否可以访问公网服务器功能代码
Jun 19 Javascript
详解javascript对数组和json数组的操作
Apr 15 Javascript
微信自定义分享链接信息(标题,图片和内容)实现过程详解
Sep 04 Javascript
TypeScript高级用法的知识点汇总
Dec 17 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处理换行符的问题 \r\n
2013/06/13 PHP
使用CodeIgniter的类库做图片上传
2014/06/12 PHP
利用PHP判断是否是连乘数字串的方法示例
2017/07/03 PHP
PHP多进程通信-消息队列使用
2019/03/08 PHP
PHP函数用法详解【初始化、嵌套、内置函数等】
2020/06/02 PHP
基于jQuery的获得各种控件Value的方法
2010/11/19 Javascript
jquery easyui滚动条部分设置介绍
2013/09/12 Javascript
JS调用页面表格导出excel示例代码
2014/03/18 Javascript
JavaScript中对JSON对象的基本操作示例
2016/05/21 Javascript
关于JavaScript数组你所不知道的3件事
2016/08/24 Javascript
获取jqGrid中选择的行的数据
2016/11/30 Javascript
JavaScript实现无穷滚动加载数据
2017/05/06 Javascript
javascript  数组排序与对象排序的实例
2017/07/17 Javascript
node版本管理工具n包使用教程详解
2018/11/09 Javascript
vue elementui form表单验证的实现
2018/11/11 Javascript
JavaScript实现的联动菜单特效示例
2019/07/08 Javascript
jquery 插件重新绑定的处理方法分析
2019/11/23 jQuery
2020淘宝618理想生活列车自动领喵币js脚本的代码
2020/06/02 Javascript
JavaScript实现点击图片换背景
2020/11/20 Javascript
常见的python正则用法实例讲解
2016/06/21 Python
django中的HTML控件及参数传递方法
2018/03/20 Python
Flask框架踩坑之ajax跨域请求实现
2019/02/22 Python
详解Django 时间与时区设置问题
2019/07/23 Python
python3.7 openpyxl 删除指定一列或者一行的代码
2019/10/08 Python
Python requests设置代理的方法步骤
2020/02/23 Python
Python如何实现在字符串里嵌入双引号或者单引号
2020/03/02 Python
Python实现Kerberos用户的增删改查操作
2020/12/14 Python
python常量折叠基础知识点讲解
2021/02/28 Python
html5自定义video标签的海报与播放按钮功能
2019/12/04 HTML / CSS
StubHub新加坡:购买和出售全球活动门票
2017/03/10 全球购物
希腊香水和化妆品购物网站:Parfimo.gr
2019/10/03 全球购物
技术入股合作协议书
2014/10/07 职场文书
先进党组织事迹材料
2014/12/26 职场文书
2016最新离婚协议书范本及程序
2016/03/18 职场文书
JavaScript模拟实现网易云轮播效果
2022/04/04 Javascript
MySQL数据库表约束讲解
2022/06/21 MySQL