Spread element magically turns functions into 'not functions'

前端 未结 4 869
北恋
北恋 2021-01-07 23:37

Suppose I have this simple JavaScript function:

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

Further suppose that I then say

<         


        
相关标签:
4条回答
  • 2021-01-08 00:14

    Just a minor change:

    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]));

    You were returning a number, and destructuring a number will leave you with an error.

    ...5 // throws SyntaxError
    
    0 讨论(0)
  • 2021-01-08 00:16

    Here is the error I get using 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)
    

    Which probably means that the result of the evaluation of some of your function call is not an iterable.

    The error is here:

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

    Change to:

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

    and it will work.

    0 讨论(0)
  • 2021-01-08 00:17

    It's a very strange error message, no question, but the main problem is a logical error in double: In two branches of the code, calling double results in a non-iterable value (in one case a number, in another undefined). But you're always applying spread notation to it. So that fails in those two cases. The cases are:

    1. You're only returning the number, not an array, in the array.length === 1 case.
    2. You're not returning anything in the case where array.length is not 1 and rest.length is 0, so the result of calling double in that case is undefined.

    You're hitting the case where you try to spread a number first, like this:

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

    For #1, you should be returning an array with one entry. For #2, You should be returning []. So the minimal changes version is:

    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]));

    0 讨论(0)
  • 2021-01-08 00:21

    Your logical error has been pointed out in comments and answers, but let me point out a cleaner, simpler, less bug-prone way to write this which is more in line with basic principles of recursion.

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

    In other words, there is only one "base case", namely the empty array, which returns an empty array. Everything else is simple recursion.

    You could "functionalize" this further with

    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]));
    
    0 讨论(0)
提交回复
热议问题