By reference
Arguments to all functions in ECMAScript are passed by value. That is, copying a value from outside a function to an argument inside a function is the same as copying a value from one variable to another.
Pass by value
var name = 'nick';
function foo(v) {
v = 'tom';
console.log(v); //tom
}
foo(name);
console.log(name) //nick
Copy the code
When you pass a name to foo, you copy a name. If you copy a name to foo, you change the value of the name without affecting the original name
reference
var obj = {
value: 1
};
function foo(o) {
o.value = 2;
console.log(o.value); / / 2
}
foo(obj);
console.log(obj.value) / / 2
Copy the code
Share transfer
var obj = {
value: 1
};
function foo(o) {
o = 2;
console.log(o); / / 2
}
foo(obj);
console.log(obj.value) / / 1
Copy the code
Shared passing is when you pass an object, you pass a copy of the reference to the object. So if you change O. value, you can find the original value by reference, but if you change O directly, you won’t change the original value. So the second and third examples are actually shared.
So javascript function parameters are actually passed by value if they are primitive types, and shared if they are reference types.
Tail-call optimization
The ECMAScript 6 specification adds a memory-management optimization that allows the JavaScript engine to reuse stack frames when conditions are met. Specifically, this optimization is ideal for “tail calls,” where the return value of an external function is the return value of an internal function. Such as:
function outerFunction() { return innerFunction(); // end call}Copy the code
(1) When the outerFunction is executed, the first stack frame is pushed onto the stack.
(2) Execute the outerFunction function body to return statement. The innerFunction must be computed before calculating the return value.
When the innerFunction body is executed, the second stack frame is pushed onto the stack.
(4) Execute the innerFunction body and calculate its return value.
(5) Pass the return value back to the outerFunction, which then returns the value.
(6) Pop out the stack frame.
After ES6 optimization, executing this example will do the following in memory.
(1) When the outerFunction is executed, the first stack frame is pushed onto the stack.
(2) Execute the outerFunction body and reach the return statement. To evaluate the return statement, you must first evaluate innerFunction.
(3) The engine finds it’s okay to pop the first stack frame off the stack because the innerFunction return value is also the outerFunction return value.
(4) Pop up the stack frame of outerFunction.
When the innerFunction body is executed, the stack frame is pushed onto the stack.
(6) Execute the innerFunction body and calculate its return value.
(7) Pop the innerFunction stack frame off the stack.
Obviously, in the first case, each additional call to the nested function adds one more stack frame. In the second case, no matter how many times the nested function is called, there is only one stack frame. This is the key to ES6 tail-call optimization: If the logic of a function allows it to be destroyed based on a tail-call, the engine will do so.
Since the last call is the last operation of the function, there is no need to retain the call frame of the outer function, because the call location, internal variables and other information will not be used, as long as the call frame of the inner function is directly replaced by the call frame of the outer function.
Tail recursion
The function calls itself, called recursion. If the tail calls itself, it is called tail recursion.
Recursion is very memory intensive, because you need to hold hundreds or thousands of call frames at the same time, which is prone to “stack overflow” errors. For tail recursion, however, because there is only one call frame, there is never a stack overflow error.
function factorial(n) {
if (n === 1) return 1;
return n * factorial(n - 1);
}
Copy the code
The above code is a factorial function, calculate n factorial, need to save at most N call records, complexity O(n)
function factorial(n, total) {
if (n === 1) return total;
return factorial(n - 1, n * total);
}
Copy the code
If rewritten to tail recursion, only one call record is retained, complexity O(1).
Computes a function of the Fibonacci sequence recursively:
function fib(n) {
if (n < 2) {
return n;
}
return fib(n - 1) + fib(n - 2);
}
console.log(fib(0)); / / 0
console.log(fib(1)); / / 1
console.log(fib(2)); / / 1
console.log(fib(3)); / / 2
console.log(fib(4)); / / 3
console.log(fib(5)); / / 5
console.log(fib(6)); / / 8
Copy the code
Tail-call optimization
function Fibonacci2 (n , ac1 = 1 , ac2 = 1) {
if( n <= 1 ) {return ac2};
return Fibonacci2 (n - 1, ac2, ac1 + ac2);
}
Copy the code