微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

Underscore源码分析

几年前就有人说javascript是最被低估一种编程语言,自从nodejs出来后,全端(All Stack/Full Stack)概念日渐兴起,现在恐怕没人再敢低估它了。javascrip是一种类C的语言,有C语言基础就能大体理解javascript的代码,但是作为一种脚本语言,javascript的灵活性是C所远远不及的,这也会造成学习上的一些困难。

一、集合

1.首先是几个迭代的方法

rush:js;"> _.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循环)

rush:js;"> 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函数

= 0 && length <= MAX_ARRAY_INDEX; }; // 如果集合有Length属性且为数字并且大于0小于最大的精确整数,则判定是类数组

•使用了_.keys函数,Object同样有原生的keys函数,用于返回一个集合obj可被枚举的属性数组。实现比较简单,for in加上hasOwnproperty()方法

--------------------------------------------------------------------------------

_.map,_.reduce方法原理类似.

_.find函数和Array.some()类似,不同的是返回的是第一个使迭代结果为真的那个元素,而不是Array.some()那样返回布尔值。

= 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.集合中的其他方法基本都是基于迭代方法来实现的。

rush:js;"> _.max = function(obj,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,list) { computed = iteratee(value,list); if (computed > lastComputed || computed === -Infinity && result === -Infinity) { result = value; lastComputed = computed; } }); } return result; };

max方法用于寻找集合中的最大值,通过循环list中的所有项,然后比较当前项和结果项,如果当前项大于结果,则将其赋给结果项,最后返回结果项。

2.集合转换为数组

rush:js;"> _.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的数据类型说起,看下图。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐