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学习笔记(十七)js 优化
Feb 04 Javascript
Firefox中beforeunload事件的实现缺陷浅析
May 03 Javascript
iframe中使用jquery进行查找的方法【案例分析】
Jun 17 Javascript
Bootstrap Table使用方法详解
Aug 01 Javascript
angularjs定时任务的设置与清除示例
Jun 02 Javascript
微信小程序 监听手势滑动切换页面实例详解
Jun 15 Javascript
基于jquery实现多级菜单效果
Jul 25 jQuery
史上最全JavaScript常用的简写技巧(推荐)
Aug 17 Javascript
详解vuex中mapState,mapGetters,mapMutations,mapActions的作用
Apr 13 Javascript
小谈angular ng deploy的实现
Apr 07 Javascript
JS实现斐波那契数列的五种方式(小结)
Sep 09 Javascript
vue打包时去掉所有的console.log
Apr 10 Vue.js
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验证码实现代码
2014/05/10 PHP
9个比较实用的php代码片段
2016/03/15 PHP
PHP中FTP相关函数小结
2016/07/15 PHP
打开超链需要“确认”对话框的方法
2007/03/08 Javascript
jQuery 对象中的类数组操作
2009/04/27 Javascript
js chrome浏览器判断代码
2010/03/28 Javascript
jQuery EasyUI API 中文文档 DateTimeBox日期时间框
2011/10/16 Javascript
简介JavaScript中fixed()方法的使用
2015/06/08 Javascript
JavaScript字符串删除重复字符的方法
2015/12/25 Javascript
jQuery 3 中的新增功能汇总介绍
2016/06/12 Javascript
详解nodeJS中读写文件方法的区别
2017/03/06 NodeJs
jQuery之动画ajax事件(实例讲解)
2017/07/18 jQuery
以BootStrap Tab为例写一个前端组件
2017/07/25 Javascript
javascript中神奇的 Date对象小结
2017/10/12 Javascript
浅析JavaScript异步代码优化
2019/03/18 Javascript
解决vue axios跨域 Request Method: OPTIONS问题(预检请求)
2020/08/14 Javascript
Vue实现点击导航栏当前标签后变色功能
2020/08/19 Javascript
Python中计算三角函数之cos()方法的使用简介
2015/05/15 Python
Python中的变量和作用域详解
2016/07/13 Python
python获取当前运行函数名称的方法实例代码
2017/04/06 Python
解决python3爬虫无法显示中文的问题
2018/04/12 Python
举例讲解Python常用模块
2019/03/08 Python
python查询文件夹下excel的sheet名代码实例
2019/04/02 Python
pycharm2020.2 配置使用的方法详解
2020/09/16 Python
英国在线药房:Chemist.co.uk
2019/03/26 全球购物
ASICS印度官方网站:日本专业运动品牌
2020/06/20 全球购物
Java程序员面试90题
2013/10/19 面试题
初中生学习生活的自我评价
2013/11/20 职场文书
电大会计学自我鉴定
2014/02/06 职场文书
班组建设经验交流材料
2014/05/12 职场文书
医院见习报告范文
2014/11/03 职场文书
加入学生会自荐书
2015/03/05 职场文书
贫困证明书范文
2015/06/16 职场文书
2016大学生优秀志愿者事迹材料
2016/02/25 职场文书
2016年圣诞节活动总结范文
2016/04/01 职场文书
python实现批量移动文件
2021/04/05 Python