Open lessfish opened 8 years ago
仔细一想,如果已经实现了 .difference,我们把 .without 的参数放入数组,然后传入 _.difference 就 ok 了!倒过来就不行了(思考下为什么)。
感觉倒过来也可以
var args = _.union(arg1, arg2, ...);
args.unshift(array);
_.without.apply(null, args);
我哪里错了吗?
_.without.apply(null, args);
这步的结果还是 args 吧?不知道我有没有理解错 @WangBoxue
@hanzichi https://jsfiddle.net/WangBoxue/1z03b4h4/
apply() 方法在指定 this 值和参数(参数以数组或类数组对象的形式存在)的情况下调用某个函数。
所以执行_.without.apply(null, args)
相当于_.without(array, elements in arg1, elements in arg2, ...)
@WangBoxue 的确如此,感谢指出!
@WangBoxue @hanzichi
反过来实现可能需要通知 _.without()
是否是 _.difference()
来调用它。如果是,则展开参数中的所有数组,不然则不展开。当然,前提是 _.difference()
要保证调用 _.without()
时没有传递非数组元素。
_.without = function(array) {
var rest = (this == 'difference') ? _.flatten(arguments, false, false, 1) : Array.prototype.slice.call(arugments, 1);
return _.filter(array, function(value) {
return !_.contains(rest, value);
});
};
_.difference = function(array) {
/** filter out arguments which is not an array firstly */
var args = _.flatten(arguments, true, true, 1).unshift(array);
/**
* let the method `_.without()` know that whether it's called by `_.difference()`,
* if so, then flatten all the arrays from argments,
* if not, then do not flatten.
*/
return _.without.apply('difference', args);
};
hey I have another question if you dont mind?
So in .sample function, what is the point of having a Math.max(0,n) passed in .shuffle function, instead of passing just 'n' ? also why does it check for object before using shuffle? because shuffle function already checks for objects? it that redundant ? please let me know what you think?
also, why does .map function use cb(iteratee, context), instead of optimizeCb(iteratee, context) ? you cannot pass anything else but a function in .map right? so it should be optimizeCb I think, i tried to pass other stuff but it kind of broke the _.map code. Please let me kow what you think? thanks a ton!
@shaunzeng Math.max 是过滤负数= =
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
这个方法很有意思,它的作用是剔除数组中的假值,返回数组副本。
实现非常的简单:
.filter 我们在以后会讲到,这里你可以把它理解为 Array.prototype.filter 的一个 polyfill,来看看 .identity 是个什么东东。
乍一看,.identity 似乎没什么卵用,传入一个参数,原封不动返回这个参数,什么鬼?而再看 .compact 的实现,就会发现非常巧妙!细细品味下,直接过滤了数组的假值,而 _.identity 在源码中能在多个地方复用。
从这个方法可以想到 PHP 的 array_filter 函数。array_filter 的基本用法和 Array.prototype.filter 相似,都是为了过滤数组中的元素。
但是,值得注意的是:
这就有点 6 了,直接把 .filter 和 .compact 两个方法合二为一了。
Array.prototype.filter 为何不设计成这样呢?没有 callback 传入的时候,直接过滤假值...
.difference & .without
先来看 _.without,它的作用是从数组中剔除指定的元素。
恩,没错,剔除数组 a 中的 value 为 1, 2, 3 的元素,这个过程中用
===
来进行比较。该方法传入的第一个参数是数组,后面的参数为单个元素。而 .difference 呢?和 .without 的唯一区别是,第二个参数开始传入的是数组。(分别和数组中的元素比较)
从 a 数组中剔除 1,2,3,5,6。
仔细一想,如果已经实现了 .difference,我们把 .without 的参数放入数组,然后传入 _.difference 就 ok 了!
倒过来就不行了(思考下为什么)。倒过来也是可以实现的,不过会相对比较繁琐些,详见 comments 部分的讨论,感谢 WangBoxue 同学指出~来看 _.difference 的实现,非常简单:
不熟悉 flatten 的可以看看 前文,当 shallow 和 strict 均为 true 时,展开一层,并且过滤非数组元素,即可以起到将多个数组合并的作用。之后利用 ._filter 进行过滤即可。
而 .without 方法则建立在 .difference 基础上。
总结
数组的扩展方法就解读到这里了,相关源码可以参考 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 支持我~