ES6: Function extension content

New features of function content in ES6

Parameter setting default value

ES6 allows to set default values ​​for the parameters of the function, that is, write directly after the parameter definition.

function log(x,y='world'){
    
    
	console.log(x,y);
}

log('hello')	//hello world
log('hello','yivi')	//hello yivi
log('hello','') //hello 

Parameter variables are declared by default, so you can no longer use let or const to declare again, nor can you use parameters with the same name.

function foo(x=5){
    
    
    let x=5	//error
    const x=5 //error
}

Used in conjunction with destructuring assignment

The parameter default value can be combined with the default value of destructuring assignment.

function foo({
    
    x,y=5}){
    
    
    console.log(x,y)
}

foo({
    
    })	//undefined,5
foo()	//error: cannot read property 'x' of undefined
foo({
    
    x:1})	// 1,5
foo({
    
    x:1,y:2})	//1,2

Let's take a look at the following two forms:

function f1({
    
    x,y} = {
    
    x:0,y:0}){
    
    
    return [x,y];
}
function f2({
    
    x=1,y=1} = {
    
    }){
    
    
    return [x,y];
}

f1()	//[0,0]
f2()	//[0,0]

f1({
    
    x:3})	//[3,undefined]
f2({
    
    x:3})	//[3,1]

f1({
    
    })	//[undefined,undefined]
f2({
    
    })	//[1,1]

The position of the parameter default value

If the parameter that defines the default value is at the end of the function, it can be omitted; if the non-tail parameter is set to the default value, in fact, this parameter cannot be omitted and must be filled with undefined.

function foo(x,y=1,z){
    
    
    return [x,y,z]
}

foo();	//[undefined,1,undefined]
foo(1,2,3)	//[1,2,3]
foo(1,,2)	//error
foo(1,undefined,2)	//[1,1,2]

Distorted length

After specifying the default, the length method of the function will only return the number of parameters without default values, that is, length will be distorted. This is because the original intention of length is the number of parameters expected by the function.

(function(x,y,z=1){
    
    }).length = 2	//参数个数为3,但返回2

Scope

Once the default value is set, the parameters will form a separate scope when the function declaration is initialized, and the scope will become invalid when the initialization is over.

var x=1;
function foo(x,y=x){
    
    
    return [x,y]
}

f(2)	//[2,2]

In the above example, because the function is set with a default value, a separate scope is formed inside the function, so y=xthe x in the function refers to the parameter x, not the global variable x.

rest parameter

ES6 introduces the rest parameter ...restto get the extra parameters of the function, so that there is no need to reference the arguments object. The variable with the rest parameter is an array, and the variable puts the extra parameters into it.

function add(...num){
    
    
    let sum = 0;
    for(var item in num){
    
    
        sum += item;
    }
    return sum;
}

add(1,2,3,4,5)	//15

Note: The length attribute of the function does not include the number of rest parameters


Tail call optimization

What is a tail call?

Tail call, as the name suggests, means that the last step of a function is to call another function.

function f(x){
    
    
    return g(x)
}


//以下都不属于尾调用
function f(x){
    
    
    let y = g(x);
    return y;
}

function f(x){
    
    
    return g(x) + 1;
}

function f(x){
    
    
    g(x);
}

The sign of tail call is that the function must be called at the end, not the result of the operation call.

Tail call optimization

We know that a function call will form a "call record" in the memory, also known as a "call frame", which saves information such as the call location and internal variables. If function B is called inside function A, then a call frame of B will also be formed above the call frame of A. The call frame of returning the result to A and B will disappear after the end of B operation. If function B also calls function c, then there is a call frame of c, and so on. All call frames form a "call stack" (call stack).

Since the tail call is the last operation of the function, there is no need to keep the call frame of the outer function, because the call location, internal variables and other information will not be used anymore. The call frame of the inner function is directly used to replace the call frame of the outer function. can.

function f(){
    
    
    let x = 1;
    let y = 2;
    return g(x+y);
}

//等同于
g(3);

In the above code, if it is not a tail call, the function f needs to save the values ​​of the variables x and y, the call information of g, and so on. But because of the tail call, the function f ends, so the call record of f can be deleted in the memory, and only the call frame of g is kept. This is tail call optimization, which can save a lot of memory.

Tail recursion

Recursion is a very memory-consuming method, because it needs to save a large number of call frames, which is prone to errors such as memory overflow, but tail recursion can solve this problem because it will only occupy one call frame forever.

// 阶乘函数
function factorial(n){
    
    
    if(n == 1){
    
    
        return 1;
    }else{
    
    
        return n*factorial(n-1);
    }
}
// 我们尾递归真的太厉害了(老财富密码了)
// 普通递归,不好用!尾递归,好用!
function factorial(n,total){
    
    
    if(n == 1){
    
    
        return total
    }else{
    
    
        return factorial(n-1,n*total); 
    }
}

//fibonacci数列
function fibonacci(n){
    
    
    if(n <= 1){
    
    
        return 1
    }else{
    
    
        return fibonacci(n-1) + fibonacci(n-2);
    }
}
// 普通递归,不好用!尾递归,好用!
function fibonacci(n,ac = 1,ac = 1){
    
    
    if(n <= 1){
    
    
        return ac2;
    }else{
    
    
        return fibonacci(n-1,ac2,ac1+ac2);
    }
}

Tail recursive rewrite

The above code doesn't seem very logical. Why should I pass a total in when I count a factorial? Can't it give me the result directly? The answer is yes. Don't forget, ES6 provides us with default value operations!

function factorial(n,total = 1){
    
    
    if(n == 1){
    
    
        return total
    }else{
    
    
        return factorial(n-1,n*total); 
    }
}

factorial(5) 	//120

There is also a tail call method, which is to provide a normal form of function in addition to the tail recursive function to perform tail recursion:

function tailFactorial(n,total){
    
    
    if(n == 1){
    
    
        return total
    }else{
    
    
        return factorial(n-1,n*total); 
    }
}

function factorial(n){
    
    
    return tailFactorial(n,1);
}
factorial(5);	//120

This is actually a kind of currying thinking. Wait a minute! What is currying? ? ?

Currying

There is an important concept in functional programming, called currying, which means converting a multi-parameter function into a single-parameter form.

function curry(fn,n){
    
    
    return function(m){
    
    
        return fn.call(this,m,n);
    }		//返回一个可执行函数
}

function tailFactorial(n,total){
    
    
    if(n == 1){
    
    
        return total
    }else{
    
    
        return factorial(n-1,n*total); 
    }
}

const factorial = curry(tailFactorial,1);
factorial(5)	//120

Guess you like

Origin blog.csdn.net/yivisir/article/details/107579933