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 建设银行登陆键盘
Jun 10 Javascript
jquery实现心算练习代码
Dec 06 Javascript
在IE和VB中支持png图片透明效果的实现方法(vb源码打包)
Apr 01 Javascript
jQuery 常见操作实现方式和常用函数方法总结
May 06 Javascript
javascript贪吃蛇完整版(源码)
Dec 09 Javascript
jQuery表单域属性过滤器用法分析
Feb 10 Javascript
JavaScript中property和attribute的区别详细介绍
Mar 03 Javascript
基于BootStrap Metronic开发框架经验小结【九】实现Web页面内容的打印预览和保存操作
May 12 Javascript
jQuery基础知识点总结(DOM操作)
Jun 01 Javascript
BootStrap初学者对弹出框和进度条的使用感觉
Jun 27 Javascript
JavaScript实现左侧菜单效果
Dec 14 Javascript
node.js中npm包管理工具用法分析
Feb 14 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中查询SQL Server或Sybase时TEXT字段被截断的解决方法
2009/03/10 PHP
php adodb连接不同数据库
2009/03/19 PHP
php后台程序与Javascript的两种交互方式
2009/10/25 PHP
PHP输入流php://input实例讲解
2015/12/22 PHP
php strftime函数的详细用法
2018/06/21 PHP
jQuery中add实现同时选择两个id对象
2010/10/22 Javascript
JavaScript中获取未知对象属性的代码
2011/04/27 Javascript
JS实现点击链接取消跳转效果的方法
2014/01/24 Javascript
jQuery 实现自动填充邮箱功能(带下拉提示)
2014/10/14 Javascript
jQuery EasyUi实战教程之布局篇
2016/01/26 Javascript
js实现简单的计算器功能
2017/01/16 Javascript
关于Bootstrap按钮组件消除黄框的方法
2017/05/19 Javascript
Vue2.x中的Render函数详解
2017/05/30 Javascript
jQuery实现手机号正则验证输入及自动填充空格功能
2018/01/02 jQuery
浅谈jquery fullpage 插件增加头部和版权的方法
2018/03/20 jQuery
详解Vue+axios+Node+express实现文件上传(用户头像上传)
2018/08/10 Javascript
Vue中props的详解
2019/05/16 Javascript
重学JS之显示强制类型转换详解
2019/06/30 Javascript
Node.js使用MongoDB的ObjectId作为查询条件的方法
2019/09/10 Javascript
在VUE中实现文件下载并判断状态的方法
2019/11/08 Javascript
vue 移动端记录页面浏览位置的方法
2020/03/11 Javascript
python绘图库Matplotlib的安装
2014/07/03 Python
python利用正则表达式提取字符串
2016/12/08 Python
使用python中的in ,not in来检查元素是不是在列表中的方法
2018/07/06 Python
python实现月食效果实例代码
2019/06/18 Python
Python图像处理库PIL中图像格式转换的实现
2020/02/26 Python
Django中F函数的使用示例代码详解
2020/07/06 Python
python Tornado框架的使用示例
2020/10/19 Python
Nixon手表英国官网:美国尼克松手表品牌
2020/02/10 全球购物
党支部综合考察材料
2014/05/19 职场文书
大二学生自我检讨书
2014/10/23 职场文书
文书工作总结(范文)
2019/07/11 职场文书
python随机打印成绩排名表
2021/06/23 Python
Python中异常处理用法
2021/11/27 Python
为什么MySQL不建议使用SELECT *
2022/04/03 MySQL
iOS 16进一步确认,一共支持16款iPhone
2022/04/28 数码科技