问题
I have looked at this long and hard. I understand recursion, I understand the call stack and the concept of “Last in, first out” but in this example.
function countup(n) {
if (n < 1) {
return [];
} else {
const countArray = countup(n - 1);
countArray.push(n);
return countArray;
}
}
console.log(countup(5)); // [ 1, 2, 3, 4, 5 ]
When we meet the 'base condition' and we return [];
, how is the array accessible if it does not have a name? and when is the name countArray
attributed to this array?
I just don’t get it!
回答1:
It's a return value, so the value is passed back to the caller. For example, on this line:
const countArray = countup(n - 1)
...if n
was 1, then 0
is passed to countup
, and []
is returned. This means countArray
now has the value []
. Note that this is not related to recursion at all; it's the way any function call works.
回答2:
Recursion recurses down until n===1
. Then, when countup(0)
is called (as countup(1-1)
, an empty array is returned. In that instant, on the same line, the empty array is assigned to the variable countArray
. from there 1
is pushed, and the array [1]
is returned, assigned to the countArray
1 level back up the tree, and you continue recursing back up to your starting number.
This is the line where the array assignment occurs:
const countArray = countup(n - 1);
The function is called, and the return result of the function is assigned to the variable. At first it simply recurses to a deeper level. Then, when n==1
, it stops recursing, gets assigned an actual value, and begins climbing back up.
It needs this definitive, base value, []
before it can climb out of its deepest level of recursion.
回答3:
The array returned by return []
is the return value of the function countup
.
When you do console.log(countup(5))
really you are doing:
let something = countup(5);
console.log(something);
The array returned from the function countup
is being assigned to a variable, which is then written out to the console by being passed to console.log
.
回答4:
I'm not sure the best way to express this, but a step-by-step walkthrough of how code executes may help. Indentation here indicates a level of recursion (and thus a fresh "scope" for defining variables):
// n = 5
const countArray = countup(n - 1);
// n = 4
const countArray = countup(n - 1);
// n = 3
const countArray = countup(n - 1);
// n = 2
const countArray = countup(n - 1);
// n = 1
const countArray = countup(n - 1);
// n = 0
// n meets the condition (n < 1), so we return []
// we got [], as the reutn value and assigned it to countArray
// countArray = [] a this point
countArray.push(n);
// now countArray = [1]
// return [1]
// we got [1], as the reutn value and assigned it to countArray
// countArray = [1] a this point
countArray.push(n);
// now countArray = [1, 2]
// return [1, 2]
// we got [1, 2], as the reutn value and assigned it to countArray
// countArray = [1, 2] a this point
countArray.push(n);
// now countArray = [1, 2, 3]
// return [1, 2, 3]
// we got [1, 2, 3], as the reutn value and assigned it to countArray
// countArray = [1, 2, 3] a this point
countArray.push(n);
// now countArray = [1, 2, 3, 4]
// return [1, 2, 3, 4]
// we got [1, 2, 3, 4], as the reutn value and assigned it to countArray
// countArray = [1, 2, 3, 4] a this point
countArray.push(n);
// now countArray = [1, 2, 3, 4, 5]
// return [1, 2, 3, 4, 5]
// This value is then console logged
回答5:
let's see two ways to declare an empty array
const a = [];
const b = new Array();
console.log(a) // []
console.log(b) // []
So you get the same output, now with your question, []
is a way to declare an array, and javascript knows it.
Then if you have the function:
function countup(n) {
if (n < 1) {
// return [];
return new Array();
} else {
const countArray = countup(n - 1);
countArray.push(n);
return countArray;
}
}
console.log(countup(5)); // [ 1, 2, 3, 4, 5 ]
Maybe this way you can figure it out what is happening, you are creating and returning a new empty array, to end the clarification, let's change the function call:
// console.log(countup(5)); // [ 1, 2, 3, 4, 5 ]
const newArrayUpToFive = countup(5);
console.log(newArrayUpToFive); // [ 1, 2, 3, 4, 5 ]
// Now the empty array
const newArrayEmpty = countup(0) // the return value is new Array()
// const newArrayEmpty = new Array(); // It is like this sentence
console.log(newArrayEmpty) // []
Step by step:
console.log(countup(2));
// The function does (as n = 2)
const countArray = countup(1) // 2 - 1, Let's say this is the 'A' call
// The function has to wait for the countup return statement
// Now countup is called again with n = 1, and we have
const countArray = countup(0) // 1 - 1, 'B' call
// Again, the function has to wait for the countup return statement
// Finally countup is called n = 0 and the if condition
// is true, so:
return [];
// B call gets the value [], in 'B' call the value of n was 1
const countArray = [];
countArray.push[1]
return countArray; // returns [1]
// A call gets the value [1], in 'A' call the value of n was 2
const countArray = [1];
countArray.push(2);
return countArray; // returns [1, 2]
So at the end, console.log
is called with the value [1, 2]
.
回答6:
Recursion is a functional heritage and so using it with functional style yields a greater comprehension. In functional programming, you can simply replace a function call with it's return value and always get the correct answer. This is not always true for imperative programs which rely on side-effects to compute the result.
I think it helps to see the program and the spawned process like this -
const countup = (n = 0) =>
n < 1
? []
: [ ...countup(n - 1), n ]
console.log(countup(4))
// [ ...countup(3), 4 ]
// [ ...[ ...countup(2), 3 ], 4 ]
// [ ...[ ...[ ...countup(1), 2 ], 3 ], 4 ]
// [ ...[ ...[ ...[ ...[], 1 ], 2 ], 3 ], 4 ]
// [ ...[ ...[ ...[ 1 ], 2 ], 3 ], 4 ]
// [ ...[ ...[ 1, 2 ], 3 ], 4 ]
// [ ...[ 1, 2, 3 ], 4 ]
// [ 1, 2, 3, 4 ]
I'm not saying it's a better program (or worse!) but I do think it's easier to see how the recursive program directly relates to the recursive computational process.
来源:https://stackoverflow.com/questions/62205712/the-empty-array-in-this-recursive-code-is-accessible-how