通过函数调用进行迭代
Iterating through a function call
经过多年在C++中编写循环的繁琐方式
for(int i=0; i<N; ++i) {
...
}
使用迭代器变得非常好
for(it i=v.begin(); i<v.end(); ++i) {
...
}
并最终转向范围迭代器
for(auto i:v) {
...
}
在JavaScript中也可以使用for
,其风格几乎相同(减去类型声明和前/后增量运算符)上面的第一个。
尽管如此,在所有这些中,for
仍然存在。D3.js图书馆展示了另一种选择。可以通过写入来迭代数组
d3.select("body")
.selectAll("p")
.data([4, 8, 15, 16, 23, 42])
.enter().append("p")
.text(function(d) { return "I’m number " + d + "!"; });
在这里,enter
突变为for
循环。文件很好地解释了联接的客户端视图。我缺少的是(函数式编程?)风格的独立示例将函数调用转换为迭代。
毫无疑问,这并不是D3.js独有的。这正是我遇到这个成语的地方。
你能建议几行独立的JavaScript代码吗通过函数调用演示迭代?
我脑海中至少有几个内置函数。
映射()
这一点很明显。
[1, 2, 3]
.map(someNumber => someNumber * someNumber)
.map((powered, index) => index + "::" + powered);
// --> [ "1::1", "2::4", "3::9" ]
链条很好,对吧?接受一些输入并生成由元素组成的结果,这些元素是通过逐元素应用函数计算得出的。
建议:尽可能尝试与纯函数一起使用(对相同的输入产生相同的结果,如果可能的话不要变异原始集合,也不会产生任何副作用)。
forEach()
这个函数也遍历数组的所有元素,并应用一个函数,而不返回任何内容。因此,它只能结束调用链,但不能用于进一步的链接。
[1, 2, 3, 4]
.forEach(number => console.info(number));
建议:forEach()
在我们想要编写一些代码时非常有用,这些代码会导致迭代集合中的每个条目产生副作用。
筛选器()
Filter函数使用一个谓词,用于从谷壳中筛选小麦。谓词为您要在下一个"阶段"中处理的项目定义了一个标准。
[null, undefined, 0, 1, 2, 3, NaN, "", "You get the idea"]
.filter(Boolean)
.map(filteredElement => filteredElement + "!")
// --> [ "1!", "2!", "3!", "You get the idea!" ]
建议:尽可能尝试与纯函数一起使用。也就是说,除了与过滤逻辑本身直接相关的事情之外,不要在filter
中做任何其他事情。
Object.keys()和Object.entries()
当我们需要迭代对象的键或键值对,而不是数组的元素时,这两个函数非常有用。
const targetObject = { a: 1, b: 2, c: 3 };
Object
.keys(targetObject)
.map(key => key + "=" + targetObject[key])
// --> [ "a=1", "b=2", "c=3" ]
可以像这个一样获得相同的结果
Object
.entries({ a: 1, b: 2, c: 3 })
.map((key, value) => key + "=" + value)
// --> [ "a=1", "b=2", "c=3" ]
建议:使用Object.keys(...)
时,可能需要使用Object.hasOwnProperty(...)
。有关详细信息,请参阅文档。
find()
这个几乎微不足道。让我们搜索与谓词匹配的项。搜索是"从左到右"的,只要找到第一个"匹配",搜索就会停止。
[1, 5, 10, 15]
.find(number >= 7)
// --> 10
findIndex()函数可用于查找与谓词匹配的元素的位置。
some()和every()
这些功能检查
a) 存在与谓词匹配的至少一个元素;或b) 每个元素都匹配一个谓词。
const arrayOfNumbers = [2, 4, 6, 8, 10];
arrayOfNumbers.every(number => number % 2 === 0); // --> true
arrayOfNumbers.every(number => number % 2 === 1); // --> false
arrayOfNumbers.some(number => number > 1); // --> true
arrayOfNumbers.some(number => number <= 1); // --> false
reduce()和`reduceRight()`
在这个快速回顾中最后要提到的是函数,它获取一个事物列表并将其聚合为一个结果。
[-1, 0, 1, 2, 3]
.filter(value => value >= 0) // [0, 1, 2, 3]
.map(value => value + 1) // [1, 2, 3, 4]
.reduce((subTotal, currentValue) => subTotal + currentValue, 5);
// --> 15
建议:尽可能尝试与纯函数一起使用。
普遍适用的性能说明。在我的基准测试中(手头没有),手工编写的for
循环总是比forEach
、map
和其他迭代函数快。除非性能受到严重影响,否则我仍然更喜欢这些功能。这主要有两个原因:1)更容易避免一次失误;2) 代码可读性更强,因为每个函数都定义了数据处理流程中的独立步骤,从而使代码更简单、更易于维护。
我希望,这是对一些内置的可链式JavaScript函数的一个好的概述。此处介绍更多内容。看看concat()
、sort()
、fill()
、join()
、slice()
、reverse()
——我也经常使用它们。
如果您需要first()
或last()
之类的东西,您将无法在本机函数中找到它们。要么编写自己的库,要么使用第三方库(例如lodash、rambda.js)
以下是Array.prototype.forEach
:的示例实现
function foreach(array, cb) {
for (var i = 0; i < array.length; ++i)
cb(array[i], i, array);
}
foreach([2,8,739,9,0], (n, i) =>
console.log("number: %snindex: %sn", n, i));
我当然不用用勺子喂你了,是吗
function array_iterator(array) {
var i = 0;
function next() {
return array[i++];
}
function head() {
return array[i];
}
function tail() {
return array[array.length-1];
}
function more() {
return i < array.length;
}
function done() {
return !more();
}
function reset() {
i = 0;
}
return { next, head, tail, done, more, reset };
}
var nums = [3,34,4];
var iter = array_iterator(nums);
while (iter.more()) {
console.log(iter.next());
}
- 如何将迭代器调用转发给类的私有成员?
- 调用迭代函数的次数
- HPX 是否提供具有粒度控制的基于任务的并行化迭代函数?
- 如何将递归函数(具有两个基本情况)转换为迭代函数
- 将递归函数转换为迭代函数
- 当我计算它并给我 O(n^3) 时,这个迭代函数是如何是 O(n/2) 的
- C 的自定义迭代函数
- 迭代时调用成员函数时,迭代时
- 通过迭代器调用功能无法在派生对象上编译
- 如何记录C 重复迭代函数的总时间
- 使用迭代函数调用初始化std::vector
- 如何使用for循环使用反向迭代器调用erase
- 将递归可变参数模板函数转换为迭代函数
- 在元组中迭代和调用异构函数
- 将迭代函数转换为递归函数
- 通过迭代器调用函数
- C++ 笛卡尔乘积迭代器在第一次迭代时调用基类函数
- 从迭代器调用函数
- 使用随机访问迭代器调用模板函数
- 使用迭代器调用STL Set中的非静态函数