You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: 1-js/06-advanced-functions/01-recursion/01-sum-to/solution.md
+1-1
Original file line number
Diff line number
Diff line change
@@ -37,4 +37,4 @@ P.S. Naturally, the formula is the fastest solution. It uses only 3 operations f
37
37
38
38
The loop variant is the second in terms of speed. In both the recursive and the loop variant we sum the same numbers. But the recursion involves nested calls and execution stack management. That also takes resources, so it's slower.
39
39
40
-
P.P.S. The standard describes a "tail call" optimization: if the recursive call is the very last one in the function (like in `sumTo` above), then the outer function will not need to resume the execution and we don't need to remember its execution context. In that case `sumTo(100000)`is countable. But if your JavaScript engine does not support it, there will be an error: maximum stack size exceeded, because there's usually a limitation on the total stack size.
40
+
P.P.S. Some engines support the "tail call" optimization: if a recursive call is the very last one in the function (like in `sumTo` above), then the outer function will not need to resume the execution, so the engine doesn't need to remember its execution context. That removes the burden on memory, so counting `sumTo(100000)`becomes possible. But if the JavaScript engine does not support tail call optimization (most of them don't), there will be an error: maximum stack size exceeded, because there's usually a limitation on the total stack size.
Copy file name to clipboardExpand all lines: 1-js/06-advanced-functions/01-recursion/article.md
+10-7
Original file line number
Diff line number
Diff line change
@@ -85,7 +85,7 @@ So, the recursion reduces a function call to a simpler one, and then -- to even
85
85
````smart header="Recursion is usually shorter"
86
86
A recursive solution is usually shorter than an iterative one.
87
87
88
-
Here we can rewrite the same using the ternary `?` operator instead of `if` to make `pow(x, n)` more terse and still very readable:
88
+
Here we can rewrite the same using the conditional operator `?` instead of `if` to make `pow(x, n)` more terse and still very readable:
89
89
90
90
```js run
91
91
function pow(x, n) {
@@ -100,11 +100,11 @@ The maximal recursion depth is limited by JavaScript engine. We can make sure ab
100
100
101
101
That limits the application of recursion, but it still remains very wide. There are many tasks where recursive way of thinking gives simpler code, easier to maintain.
102
102
103
-
## The execution stack
103
+
## The execution context and stack
104
104
105
105
Now let's examine how recursive calls work. For that we'll look under the hood of functions.
106
106
107
-
The information about a function run is stored in its *execution context*.
107
+
The information about the process of execution of a running function is stored in its *execution context*.
108
108
109
109
The [execution context](https://tc39.github.io/ecma262/#sec-execution-contexts) is an internal data structure that contains details about the execution of a function: where the control flow is now, the current variables, the value of `this` (we don't use it here) and few other internal details.
110
110
@@ -416,7 +416,7 @@ let arr = [obj1, obj2, obj3];
416
416
417
417
...But there's a problem with arrays. The "delete element" and "insert element" operations are expensive. For instance, `arr.unshift(obj)` operation has to renumber all elements to make room for a new `obj`, and if the array is big, it takes time. Same with `arr.shift()`.
418
418
419
-
The only structural modifications that do not require mass-renumbering are those that operate with the end of array: `arr.push/pop`. So an array can be quite slow for big queues.
419
+
The only structural modifications that do not require mass-renumbering are those that operate with the end of array: `arr.push/pop`. So an array can be quite slow for big queues, when we have to work with the beginning.
420
420
421
421
Alternatively, if we really need fast insertion/deletion, we can choose another data structure called a [linked list](https://en.wikipedia.org/wiki/Linked_list).
422
422
@@ -506,14 +506,17 @@ Naturally, lists are not always better than arrays. Otherwise everyone would use
506
506
507
507
The main drawback is that we can't easily access an element by its number. In an array that's easy: `arr[n]` is a direct reference. But in the list we need to start from the first item and go `next` `N` times to get the Nth element.
508
508
509
-
...But we don't always need such operations. For instance, when we need a queue or even a [deque](https://en.wikipedia.org/wiki/Double-ended_queue) -- the ordered structure that must allow very fast adding/removing elements from both ends.
509
+
...But we don't always need such operations. For instance, when we need a queue or even a [deque](https://en.wikipedia.org/wiki/Double-ended_queue) -- the ordered structure that must allow very fast adding/removing elements from both ends, but access to its middle is not needed.
510
510
511
-
Sometimes it's worth to add another variable named `tail` to track the last element of the list (and update it when adding/removing elements from the end). For large sets of elements the speed difference versus arrays is huge.
511
+
Lists can be enhanced:
512
+
- We can add property `prev` in addition to `next` to reference the previous element, to move back easily.
513
+
- We can also add a variable named `tail` referencing the last element of the list (and update it when adding/removing elements from the end).
514
+
- ...The data structure may vary according to our needs.
512
515
513
516
## Summary
514
517
515
518
Terms:
516
-
- *Recursion* is a programming term that means a "self-calling" function. Such functions can be used to solve certain tasks in elegant ways.
519
+
- *Recursion* is a programming term that means calling a function from itself. Recursive functions can be used to solve tasks in elegant ways.
517
520
518
521
When a function calls itself, that's called a *recursion step*. The *basis* of recursion is function arguments that make the task so simple that the function does not make further calls.
0 commit comments