Why underscore
近来最先看 underscore.js 源码,并将 underscore.js 源码解读 放在了我的 2016 设想中。
浏览一些有名框架类库的源码,就好像和一个个巨匠对话,你会学到许多。为何是 underscore?最主要的原因是 underscore 简短精干(约 1.5k 行),封装了 100 多个有效的要领,耦合度低,异常合适逐一要领浏览,合适楼主如许的 JavaScript 初学者。从中,你不仅能够学到用 void 0 替代 undefined 防止 undefined 被重写等一些小技能 ,也能够学到变量范例推断、函数撙节&函数去抖等经常使用的要领,还能够学到许多浏览器兼容的 hack,更能够学到作者的团体设想思绪以及 API 设想的道理(向后兼容)。
今后楼主会写一系列的文章跟人人分享在源码浏览中进修到的学问。
underscore-1.8.3 源码解读项目地点 https://github.com/hanzichi/underscore-analysis
underscore-1.8.3 源码全文解释 https://github.com/hanzichi/underscore-analysis/blob/master/underscore-1.8.3.js/underscore-1.8.3-analysis.js
underscore-1.8.3 源码解读系列文章 https://github.com/hanzichi/underscore-analysis/issues
迎接围观~ (假如有兴致,迎接 star & watch~)您的关注是楼主继承写作的动力
Main
很快,Array Functions 部份到了尾声,本日来做个了(xiao)结。
underscore 给数组(以及 arguments,这里迥殊申明下,underscore 的数组扩大要领,一样适用于 arguments)增加了 20 个扩大要领,值得一提的是,许多有意义的要领,比方 map,shuffle 等,都被放在了 Collection Functions 中。本文来看看 Array Functions 中另有哪些有意义的要领(之前没有被说起)。
_.compact
这个要领很有意义,它的作用是剔除数组中的假值,返回数组副本。
完成异常的简朴:
_.compact = function(array) {
return _.filter(array, _.identity);
};
_.filter 我们在今后会讲到,这里你能够把它理解为 Array.prototype.filter 的一个 polyfill,来看看 _.identity 是个什么东东。
_.identity = function(value) {
return value;
};
乍一看,_.identity 好像没什么卵用,传入一个参数,一成不变返回这个参数,什么鬼?而再看 _.compact 的完成,就会发明异常奇妙!细细品味下,直接过滤了数组的假值,而 _.identity 在源码中能在多个处所复用。
从这个要领能够想到 PHP 的 array_filter 函数。array_filter 的基础用法和 Array.prototype.filter 类似,都是为了过滤数组中的元素。
function isOdd($num) {
return $num & 1;
}
$a = Array(1, 2, 3);
$a = array_filter($a, 'isOdd');
var_dump($a);
// array
// 0 => int 1
// 2 => int 3
然则,值得注意的是:
If no callback is supplied, all entries of array equal to FALSE (see converting to boolean) will be removed.
这就有点 6 了,直接把 _.filter 和 _.compact 两个要领合二为一了。
$a = Array(0, 1, 2, 3, null, false, 4);
$a = array_filter($a);
var_dump($a);
// array
// 1 => int 1
// 2 => int 2
// 3 => int 3
// 6 => int 4
Array.prototype.filter 为何不设想成如许呢?没有 callback 传入的时刻,直接过滤假值…
_.difference & _.without
先来看 _.without,它的作用是从数组中剔除指定的元素。
var a = [1, 2, 3, 4, 5];
var ans = _.without(a, 1, 2, 3);
console.log(ans); // [4, 5]
恩,没错,剔除数组 a 中的 value 为 1, 2, 3 的元素,这个历程顶用 ===
来举行比较。该要领传入的第一个参数是数组,背面的参数为单个元素。
而 _.difference 呢?和 _.without 的唯一区别是,第二个参数最先传入的是数组。(离别和数组中的元素比较)
var a = [1, 2, 3, 4, 5];
var ans = _.difference(a, [1, 2, 3], [5, 6]);
console.log(ans); // [4]
从 a 数组中剔除 1,2,3,5,6。
细致一想,假如已完成了 _.difference,我们把 _.without 的参数放入数组,然后传入 _.difference 就 ok 了!倒过来就不行了(思索下为何)。
来看 _.difference 的完成,异常简朴:
// _.difference(array, *others)
_.difference = function(array) {
// 将 others 数组睁开一层
// rest[] 保留睁开后的元素构成的数组
// strict 参数为 true
// 不能够如许用 _.difference([1, 2, 3, 4, 5], [5, 2], 10);
// 10 就会取不到
var rest = flatten(arguments, true, true, 1);
// 遍历 array,过滤
return _.filter(array, function(value){
// 假如 value 存在在 rest 中,则过滤掉
return !_.contains(rest, value);
});
};
不熟习 flatten 的能够看看 前文,当 shallow 和 strict 均为 true 时,睁开一层,而且过滤非数组元素,即能够起到将多个数组兼并的作用。今后应用 ._filter 举行过滤即可。
而 _.without 要领则建立在 _.difference 基础上。
_.without = function(array) {
// slice.call(arguments, 1)
// 将 arguments 转为数组(同时去掉第一个元素)
// 今后便能够挪用 _.difference 要领
return _.difference(array, slice.call(arguments, 1));
};
总结
数组的扩大要领就解读到这里了,相干源码能够参考 https://github.com/hanzichi/underscore-analysis/blob/master/underscore-1.8.3.js/src/underscore-1.8.3.js#L450-L693 这部份。接下去要解读的是 Collection Functions 部份,所谓 Collection,恰是 Object & Array,也就是说这部份要领既能够用于 Object 也能用于 Array,比方我们熟习的 map,filter,shuffle 等等,都在这部份内。
放个预报,下一篇会暂缓下 Collection Functions,讲下 array-like 相干的东西,敬请期待。
PS:对峙一件事真的挺难,一个月来,天天对峙看点源码,险些把一切业余时候花在了上面,写了 10 篇漫笔,每篇文章写的时候不短,症结还需要构想,怎样提炼出一个主题,怎样写让人看了会有所收成,恩,继承对峙。请关注我的 Repo https://github.com/hanzichi/underscore-analysis 支撑我~