通过函数调用迭代

时间:2017-10-08 00:41:11

标签: javascript c++ d3.js functional-programming

多年来用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 documentation 库展示了另一种选择。可以通过编写

来遍历数组
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循环。 {{3}} {{3}} 很好地解释了连接的客户端视图。我缺少的是一个 (函数式编程?)风格的独立例子 将函数调用转换为迭代。

毫无疑问,这不是D3.js独有的。这就是我遇到这个成语的地方。

您能否提出几行独立的JavaScript代码? 通过函数调用演示迭代?

2 个答案:

答案 0 :(得分:5)

我至少会想到几个内置函数。

地图()

这个非常明显。

[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()在我们想要编写一些代码时非常有用,这些代码会导致正在迭代的集合中每个条目产生副作用。

过滤器()

过滤功能使用谓词来从谷壳中筛选小麦。谓词是在下一个&#34;阶段定义您想要处理的项目的标准&#34;。

[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.hasOwnProperty(...)时,您可能希望使用Object.keys(...)。有关详细信息,请参阅documentation

找到()

这个几乎是微不足道的。让我们搜索与谓词匹配的项目。搜索是从左到右&#34;,只要第一个&#34;匹配&#34;它就会停止。找到了。

[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循环总是比forEachmap和其他迭代函数更快。除非性能受到严重影响,否则我仍然更喜欢这些功能。有两个主要原因:1)更容易避免一个错误; 2)代码更具可读性,因为每个单个函数在数据处理流程中定义了一个独立的步骤,从而使代码更简单,更易于维护。

我希望,这是一些内置的可链式JavaScript函数的概述。更多是described here。请查看concat()sort()fill()join()slice()reverse() - 我也经常使用它们。

如果您需要first()last()之类的内容,则无法在原生函数中找到它们。您可以自己编写,也可以使用第三方库(例如lodashrambda.js)。

答案 1 :(得分:0)

以下是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: %s\nindex: %s\n", 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());
}