【问题标题】:Spread element magically turns functions into 'not functions'扩展元素神奇地将函数变成“非函数”
【发布时间】:2017-05-19 13:42:38
【问题描述】:

假设我有这个简单的 JavaScript 函数:

function returnArray(){
    return [1, 2, 3];
}

进一步假设我说

var test = [0, ...returnArray()];

您希望 test 等于 [0,1,2,3],而且您是对的。我试过了,当然它有效。

现在我有这个练习,我想构建一个名为 double 的函数,它以一个数组作为参数并返回另一个数组,其中包含所有原始数组的加倍值。所以如果我调用 double([1,2,3]) 我应该得到 [2,4,6]。练习的限制是我必须使用only数组解构、递归和其余/扩展运算符来构建我的函数。不允许使用数组助手。所以我想出了这个:

function double(array){
  if (array.length===1) return 2*array[0];
  var [num, ...rest] = array;  
  if (rest.length!=0) return [2*num, ...double(rest)];  
}

如果我对任何大小至少为 2 的数组运行此函数,我会收到一条错误消息,指出 double 不是函数。如果我在 double 之前删除 ... 运算符,那么神奇地 double 又是一个函数,当然 double([1,2,3]) 的结果是 [2,[4,6]],这并不完全与 [2,4,6] 相同。

我的第一个想法是,也许出于某种奇怪的原因,你不能在函数前面使用 ...,即使函数返回一个数组,所以我用上面的 returnArray() 函数测试了这个假设,并发现它工作得很好。我不知道为什么它会在练习中崩溃。我只能猜测递归可能与它有关,但我不知道为什么会这样。谁能指出我的代码有什么问题?

编辑:谢谢大家,这是一个非常愚蠢的错误!我应该看到的。我在你的一些答案中添加了 cmets。

【问题讨论】:

标签: javascript arrays recursion


【解决方案1】:

您的逻辑错误已在 cmets 和 answers 中指出,但让我指出一种更简洁、更简单、不易出错的编写方式,它更符合递归的基本原则。

function double([head, ...tail]) {
  if (head === undefined) return [];
  return [2*head, ...double(tail)];
}

换句话说,只有一种“基本情况”,即空数组,它返回一个空数组。其他一切都是简单的递归。

你可以进一步“功能化”它

function map(fn) {
  return function iter([head, ...tail]) {
    return head === undefined ? [] : [fn(head), ...iter(tail)];
  };
}

const double = map(x => 2*x);
console.log(double([1, 2, 3]));

【讨论】:

  • +1 表示无积分样式。很高兴看到越来越多的人在 Javascript 世界中正确使用函数式编程。
  • @HenriqueBarcelos 我不能说我完全掌握了这些 Haskell 概念,比如无点、单子和其他东西,但是阅读一下它,你能解释一下为什么它是无点的,如果参数的功能存在?
  • 非常干净优雅的解决方案,谢谢。我没有勾选你的答案的唯一原因是因为没有其他解释就不容易掌握,但正如所说的谢谢! :)
  • 使用常规的未定义检查 (head === undefined) 可能会使这更加整洁。
  • 我喜欢这个答案的地方在于它只有一个基本案例,而不是两个(length = 0length = 1)。
【解决方案2】:

这是一个非常奇怪的错误消息,毫无疑问,但主要问题是 double 中的逻辑错误:在代码的两个分支中,调用 double 会导致一个不可迭代的值(在一种情况下是一个数字,在另一个undefined)。但是您总是对其应用扩展符号。所以在这两种情况下都失败了。 案例是:

  1. array.length === 1 的情况下,您只返回数字,而不是数组。
  2. array.length 不为1 且rest.length 为0 的情况下,您不会返回任何内容,因此在这种情况下调用double 的结果是undefined

您遇到了首先尝试传播数字的情况,如下所示:

function a() {
  return 42;
}
const b = [...a()];

对于#1,您应该返回一个包含一个条目的数组。对于 #2,您应该返回 []。所以最小的改动版本是:

function double(array) {
  if (array.length === 1) {
    return [2*array[0]];
    //     ^−−−−−−−−−−^−−−−−−−−−−− note
  }
  var [num, ...rest] = array;  
  if (rest.length > 0) {
    return [2*num, ...double(rest)];
  }
  return []; // <−−−−−−−−−−−−−−−−− note
}
console.log(double([1,2,3]));

【讨论】:

  • 比我的解释得更好
  • 谢谢,这对理解问题有很大帮助。我尝试了你的实现,它就像一个魅力。但是,我在没有返回 [ ] 的情况下尝试了您的解决方案,无论如何它似乎工作得很好。是否存在缺少 return [ ] 可能会破坏功能的情况?
  • @Nicola 传递空数组时。
【解决方案3】:

只是一个小改动:

function double(array) {
  // note the return here is an array, not a number
  if (array.length === 1) return [2 * array[0]];

  var [num, ...rest] = array;
  if (rest.length) return [2 * num, ...double(rest)];
}

console.log(double([1, 2, 3, 4]));

您正在返回一个数字,而对数字进行解构将给您带来错误。

...5 // throws SyntaxError

【讨论】:

  • 2 * 出现在两个地方,这在智力上并不令人满意。
  • @torazaburo 我同意。您的答案绝对是正确的,无论是修复错误还是简化。
【解决方案4】:

这是我使用node@6.10.3时遇到的错误

if (rest.length!=0) return [2*num, ...double(rest)];  
                                        ^

TypeError: double(...)[Symbol.iterator] is not a function
    at double (/home/henrique/labs/test.js:4:41)
    at double (/home/henrique/labs/test.js:4:41)
    at Object.<anonymous> (/home/henrique/labs/test.js:7:1)
    at Module._compile (module.js:570:32)
    at Object.Module._extensions..js (module.js:579:10)
    at Module.load (module.js:487:32)
    at tryModuleLoad (module.js:446:12)
    at Function.Module._load (module.js:438:3)
    at Module.runMain (module.js:604:10)
    at run (bootstrap_node.js:390:7)

这可能意味着某些函数调用的评估结果不是可迭代的。

错误在这里:

if (array.length===1) return 2*array[0];

改为:

if (array.length===1) return [2*array[0]];

它会起作用的。

【讨论】:

  • 另外@TJCrowder 正确识别出您缺少一个极端情况:空数组。
  • 这不是极端情况。
  • 好吧,我想这是一个语义问题,但为什么不呢?
  • 来自维基百科:在工程中,极端情况(或病态情况)涉及仅在正常操作参数之外发生的问题或情况——特别是在多个环境变量或条件下表现出来的问题或情况同时处于极端水平.
  • 是的,从这个定义来看,我必须同意你的观点。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-06-28
  • 1970-01-01
  • 1970-01-01
  • 2015-12-05
  • 1970-01-01
  • 2014-06-12
相关资源
最近更新 更多