链接到本机 Javascript 函数
Chain onto native Javascript functions
tl;博士:
如何使用我自己的函数链接到 Javascript 的 map()?喜欢 -
stuff.map(i => i.key).avg()
其中 avg() 是我自己的函数,用于计算由 map 编辑的数组 return 的平均值?
在从对象转向使用纯函数的函数式编程的过程中,我失去了得心应手的东西
return this;
这让我可以链接。
如果我有
let stuff = [
{id: 1, name: 'tuan', country: 'VN', age: 23},
{id: 2, name: 'nhung', country: 'US', age: 25},
...
//my own filter to pass as a param to native filter()
var filt = x => j => j.country === x;
//my own reducer for an array that computes an average
let avg = (arr) => (arr.reduce((acc, i) => acc + i) / arr.length);
然后
stuff.filter(filt('VN')).map(i => i.age)
会 return 像
[23, 34, 45]
但是
stuff.filter(filt('VN')).map(i => i.age).avg()
给出类似
的错误
filter().map().avg() is not a function
我们如何编写链接到本机函数的函数?
链接并不神奇 — 您只是在函数的 return 值上调用方法。如果函数不支持该方法,则需要将其添加到原型中。
这是有效的,因为 map
returns 并且数组和数组有一个 join()
方法:
var a = [1, 2, 3, 4, 5]
a.map((i) => i *2 ).join(",")
但是数组没有 avg()
方法,除非您添加它,否则链接将不起作用。
应该是
avg(stuff.filter(filt('VN')).map(i => i.age))
因为您定义了期望 arr
作为参数的 avg
函数。您没有使用 avg
方法扩展 Array
原型。
在 Array.prototype
上创建一个 avg 方法
Array.prototype.avg = function() {
return this.reduce((a,b) => Number(a) + Number(b)) / this.length;
}
var array = [
{ id: 1, key:2 },
{ id: 2, key:3 },
{ id: 3, key:7 },
{ id: 4, key:6 },
{ id: 5, key:4 }
]
var avg = array.map(i => i.key).avg();
console.log(avg);
好吧,你肯定有一些选择。没有单一的正确方法可以实现您想要的。我认为你最好的选择是扩展 JavaScript 的数组 class.
class PizzaCollection extends Array {
// .. collection specific methods here...
avg() {
// you can iterate on `this`
}
}
.map、.filter 等都将 return 支持 PizzaCollection 的一个实例。
试试吧!
const j = new PizzaCollection(1, 2, 3)
const k = j.map((num) => num * num)
k instanceof PizzaCollection // returns true
k.avg() // returns the avg
方法链接与函数组合不兼容。但是,您可以创建一个容器类型,让您可以在方法链的上下文中组合纯函数,而不是修改内置原型或退回到子类型化:
function Box(x) {
return new.target ? (this.x = x, this) : new Box(x)
}
Box.prototype.fold = function fold(f) {return f(this.x)};
Box.prototype.map = function map(f) {return new Box(f(this.x))};
Box.prototype.toString = function toString() {return `Box(${this.x})`};
const id = x => x;
const stuff = [
{id: 1, name: 'foo', country: 'VN', age: 23},
{id: 2, name: 'bar', country: 'US', age: 25},
{id: 2, name: 'bat', country: 'VN', age: 34},
{id: 2, name: 'baz', country: 'VN', age: 45}
];
const filt = x => j => j.country === x;
const avg = (arr) => (arr.reduce((acc, i) => acc + i) / arr.length);
console.log(
Box(stuff.filter(filt('VN')).map(i => i.age))
.map(xs => avg(xs))
.fold(id) // yields 34
);
Box
是一个仿函数,您可以将任何类型的值放入此容器中。使用 map
您可以将函数应用于函子内部的值,并获得一个新的函子,并将转换后的值返回。 fold
行为相同,只是它 returns 是裸值。
也许您已经注意到我的示例有点冗长,我本可以省去映射。
tl;博士:
如何使用我自己的函数链接到 Javascript 的 map()?喜欢 -
stuff.map(i => i.key).avg()
其中 avg() 是我自己的函数,用于计算由 map 编辑的数组 return 的平均值?
在从对象转向使用纯函数的函数式编程的过程中,我失去了得心应手的东西
return this;
这让我可以链接。
如果我有
let stuff = [
{id: 1, name: 'tuan', country: 'VN', age: 23},
{id: 2, name: 'nhung', country: 'US', age: 25},
...
//my own filter to pass as a param to native filter()
var filt = x => j => j.country === x;
//my own reducer for an array that computes an average
let avg = (arr) => (arr.reduce((acc, i) => acc + i) / arr.length);
然后
stuff.filter(filt('VN')).map(i => i.age)
会 return 像
[23, 34, 45]
但是
stuff.filter(filt('VN')).map(i => i.age).avg()
给出类似
的错误filter().map().avg() is not a function
我们如何编写链接到本机函数的函数?
链接并不神奇 — 您只是在函数的 return 值上调用方法。如果函数不支持该方法,则需要将其添加到原型中。
这是有效的,因为 map
returns 并且数组和数组有一个 join()
方法:
var a = [1, 2, 3, 4, 5]
a.map((i) => i *2 ).join(",")
但是数组没有 avg()
方法,除非您添加它,否则链接将不起作用。
应该是
avg(stuff.filter(filt('VN')).map(i => i.age))
因为您定义了期望 arr
作为参数的 avg
函数。您没有使用 avg
方法扩展 Array
原型。
在 Array.prototype
上创建一个 avg 方法Array.prototype.avg = function() {
return this.reduce((a,b) => Number(a) + Number(b)) / this.length;
}
var array = [
{ id: 1, key:2 },
{ id: 2, key:3 },
{ id: 3, key:7 },
{ id: 4, key:6 },
{ id: 5, key:4 }
]
var avg = array.map(i => i.key).avg();
console.log(avg);
好吧,你肯定有一些选择。没有单一的正确方法可以实现您想要的。我认为你最好的选择是扩展 JavaScript 的数组 class.
class PizzaCollection extends Array {
// .. collection specific methods here...
avg() {
// you can iterate on `this`
}
}
.map、.filter 等都将 return 支持 PizzaCollection 的一个实例。
试试吧!
const j = new PizzaCollection(1, 2, 3)
const k = j.map((num) => num * num)
k instanceof PizzaCollection // returns true
k.avg() // returns the avg
方法链接与函数组合不兼容。但是,您可以创建一个容器类型,让您可以在方法链的上下文中组合纯函数,而不是修改内置原型或退回到子类型化:
function Box(x) {
return new.target ? (this.x = x, this) : new Box(x)
}
Box.prototype.fold = function fold(f) {return f(this.x)};
Box.prototype.map = function map(f) {return new Box(f(this.x))};
Box.prototype.toString = function toString() {return `Box(${this.x})`};
const id = x => x;
const stuff = [
{id: 1, name: 'foo', country: 'VN', age: 23},
{id: 2, name: 'bar', country: 'US', age: 25},
{id: 2, name: 'bat', country: 'VN', age: 34},
{id: 2, name: 'baz', country: 'VN', age: 45}
];
const filt = x => j => j.country === x;
const avg = (arr) => (arr.reduce((acc, i) => acc + i) / arr.length);
console.log(
Box(stuff.filter(filt('VN')).map(i => i.age))
.map(xs => avg(xs))
.fold(id) // yields 34
);
Box
是一个仿函数,您可以将任何类型的值放入此容器中。使用 map
您可以将函数应用于函子内部的值,并获得一个新的函子,并将转换后的值返回。 fold
行为相同,只是它 returns 是裸值。
也许您已经注意到我的示例有点冗长,我本可以省去映射。