我想链接这些方法调用:
utils.map([1,2,3,4,5], function (el) { return ++el; } )
和
utils.filter(function (el) {return !el%2; }
它们单独工作正常,但以下操作无法正常工作。如何使以下代码生效?
utils
.map([1,2,3,4,5], function (el) { return ++el; })
.filter(function (el) { return !el%2; }
这是我的utils
对象:
var utils = {
each: function (collection, iteratee){
return collection.forEach(iteratee);
},
map: function (collection, iteratee) {
return collection.map(iteratee);
},
filter: function (collection, predicate) {
return collection.filter(predicate);
},
find: function (collection, predicate) {
return collection.find(predicate);
}
}
我理解当我链接两个方法时,参数会发生变化,我只需要提供iteratee而不是集合。怎么办呢?
提前致谢。如果需要,我愿意解释一个特定的概念。
答案 0 :(得分:0)
如果你想链接这样的函数,每个函数都需要返回"这个"。
答案 1 :(得分:0)
请注意,为了使forEach
可链接,您需要添加return
语句。与MDN docs on forEach中一样:
与
map()
或reduce()
不同,它始终返回未定义的值且不可链接。典型的用例是在链的末尾执行副作用。
其次,map
和filter
等原始方法已经适合链接。正如您在问题末尾已经提到的,您的方法要求第一个参数是方法的主题,这是一种与链接不兼容的模式。使用链接时,主题必须是公开该方法的对象。
您可以通过链接每次传递一个新的utils
类对象来允许链接。对于创建utils
的这些新实例,可以更容易地将其定义为函数对象,因为这允许您使用utils
关键字创建新的new
对象。既然它确实是一个构造函数,那么用Utils
写一个大写是合适的:
function Utils(collection) { // "constructor"
this.collection = collection;
this.each = function(iteratee){
this.collection.forEach.call(this.collection, iteratee);
return this;
},
this.map = function(iteratee){
return new Utils(this.collection.map.call(this.collection, iteratee));
},
this.filter = function(predicate){
return new Utils(this.collection.filter.call(this.collection, predicate));
},
this.find = function(predicate){
return new Utils(this.collection.find.call(collection, predicate));
}
};
// test it
result = new Utils([1,2,3,4,5])
.map(function (el) { return ++el; })
.filter(function (el) { return !(el%2); });
document.write(JSON.stringify(result.collection));
输出:
[2,4,6]
此处Utils
是构造函数,并返回一个对象,该对象具有作用于私有集合属性的方法。每个方法都返回一个新的Utils
对象,但forEach
的情况除外,因为它只能返回当前对象。
因此,在此脚本中,对map
的测试呼叫实际上是对Utils.map
的调用。
应该说,与map
,filter
,...可以链接的原生方式相比,这并没有太大的好处。但我想你有其他计划来扩展这种模式。
次要注意:在表达式!el%2
中,您可能想先评估模运算符,然后是!
,但它会在另一个方向上执行。所以我在上面的代码中添加了括号。
答案 2 :(得分:0)
这是带有 ES6 类设计的 trincot 响应的更新版本。
class Collection {
constructor(collection) {
if (collection == null || !Array.isArray(collection)) {
throw new Error('collection is null or not an array');
}
this.collection = collection;
}
each(iteratee) {
this.collection.forEach.call(this.collection, iteratee);
return this;
}
map(iteratee) {
return new Collection(this.collection.map.call(this.collection, iteratee));
}
filter(predicate) {
return new Collection(this.collection.filter.call(this.collection, predicate));
}
find(predicate) {
return this.collection.find.call(this.collection, predicate);
}
contains(value) {
return this.collection.includes.call(this.collection, value);
}
get() {
return this.collection;
}
}
const result = new Collection([1, 2, 3, 4, 5])
.map(el => ++el)
.filter(el => !(el % 2))
.get();
console.log(result);
console.log(new Collection([1, 2, 3, 4, 5]).find(e => e === 2));
console.log(new Collection([1, 2, 3, 4, 5]).contains(2));
.as-console-wrapper { top: 0; max-height: 100% !important; }