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 相关文章推荐
js 取时间差去掉周六周日实现代码
Dec 25 Javascript
div拖拽插件——JQ.MoveBox.js(自制JQ插件)
May 17 Javascript
JavaScript获得url查询参数的方法
Jul 02 Javascript
JavaScript利用HTML DOM进行文档操作的方法
Mar 28 Javascript
javascript中数组和字符串的方法对比
Jul 20 Javascript
AngularJS Select(选择框)使用详解
Jan 18 Javascript
webpack独立打包和缓存处理详解
Apr 03 Javascript
BootStrap 导航条实例代码
May 18 Javascript
基于zepto.js实现登录界面
Oct 09 Javascript
浅谈Vue SSR 的 Cookies 问题
Nov 20 Javascript
jQuery分组选择器简单用法示例
Apr 04 jQuery
vue 解决provide和inject响应的问题
Nov 12 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
咖啡与牛奶
2021/03/03 冲泡冲煮
一个高ai的分页函数和一个url函数
2006/10/09 PHP
PHP函数http_build_query使用详解
2014/08/20 PHP
php+mysqli数据库连接的两种方式
2015/01/28 PHP
PHP中使用hidef扩展代替define提高性能
2015/04/09 PHP
laravel 之 Eloquent 模型修改器和序列化示例
2019/10/17 PHP
Javascript的构造函数和constructor属性
2010/01/09 Javascript
提升PHP安全:8个必须修改的PHP默认配置
2014/11/17 Javascript
Bootstrap布局方式详解
2016/05/27 Javascript
JS简单实现DIV相对于浏览器固定位置不变的方法
2016/06/17 Javascript
详解nodejs微信公众号开发——3.封装消息响应模块
2017/04/10 NodeJs
基于angular实现模拟微信小程序swiper组件
2017/06/11 Javascript
基于JS递归函数细化认识及实用实例(推荐)
2017/08/07 Javascript
JS排序算法之冒泡排序,选择排序与插入排序实例分析
2017/12/13 Javascript
JS中数据结构之栈
2019/01/01 Javascript
17道题让你彻底理解JS中的类型转换
2019/08/08 Javascript
[03:24]DOTA2超级联赛专访hao 大翻盘就是逆袭
2013/05/24 DOTA
Python使用chardet判断字符编码
2015/05/09 Python
对Python中实现两个数的值交换的集中方法详解
2019/01/11 Python
Python魔法方法详解
2019/02/13 Python
Python实现计算文件MD5和SHA1的方法示例
2019/06/11 Python
python实现websocket的客户端压力测试
2019/06/25 Python
python栈的基本定义与使用方法示例【初始化、赋值、入栈、出栈等】
2019/10/24 Python
Python 3 使用Pillow生成漂亮的分形树图片
2019/12/24 Python
Python3.6 + TensorFlow 安装配置图文教程(Windows 64 bit)
2020/02/24 Python
利用python控制Autocad:pyautocad方式
2020/06/01 Python
Python接口自动化测试框架运行原理及流程
2020/11/30 Python
红色康乃馨酒店:Red Carnation Hotels
2017/06/22 全球购物
煤矿机修工岗位职责
2014/02/07 职场文书
诚信承诺书模板
2014/05/26 职场文书
党课培训心得体会
2014/09/02 职场文书
婚庆公司开业主持词
2015/06/30 职场文书
孙振耀退休感言
2015/08/01 职场文书
小学作文指导之如何写人?
2019/07/08 职场文书
详解Django中 render() 函数的使用方法
2021/04/22 Python
div与span之间的区别与使用介绍
2021/12/06 HTML / CSS