【underscore 源码解读】Array Functions 相干源码拾遗 & 小结

Why underscore

近来最先看 underscore.js 源码,并将 underscore.js 源码解读 放在了我的 2016 设想中。

浏览一些有名框架类库的源码,就好像和一个个巨匠对话,你会学到许多。为何是 underscore?最主要的原因是 underscore 简短精干(约 1.5k 行),封装了 100 多个有效的要领,耦合度低,异常合适逐一要领浏览,合适楼主如许的 JavaScript 初学者。从中,你不仅能够学到用 void 0 替代 undefined 防止 undefined 被重写等一些小技能 ,也能够学到变量范例推断、函数撙节&函数去抖等经常使用的要领,还能够学到许多浏览器兼容的 hack,更能够学到作者的团体设想思绪以及 API 设想的道理(向后兼容)。

今后楼主会写一系列的文章跟人人分享在源码浏览中进修到的学问。

迎接围观~ (假如有兴致,迎接 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 支撑我~

    原文作者:fish
    原文地址: https://segmentfault.com/a/1190000005702146
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞