ES6: Conteúdo de extensão de função

Novos recursos de conteúdo funcional no ES6

Valor padrão de configuração de parâmetro

ES6 permite definir valores padrão para os parâmetros da função, ou seja, escrever diretamente após a definição do parâmetro.

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

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

Variáveis ​​de parâmetro são declaradas por padrão, então você não pode mais usar let ou const para declarar novamente, nem pode usar parâmetros com o mesmo nome.

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

Usado em conjunto com a atribuição de desestruturação

O valor padrão do parâmetro pode ser combinado com o valor padrão da atribuição de desestruturação.

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

Vamos dar uma olhada nas duas formas a seguir:

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]

A posição do valor padrão do parâmetro

Se o parâmetro que define o valor padrão estiver no final da função, ele pode ser omitido; se o parâmetro não final for definido com o valor padrão, na verdade, este parâmetro não pode ser omitido e deve ser preenchido com indefinido.

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]

Comprimento distorcido

Após especificar o padrão, o método de comprimento da função retornará apenas o número de parâmetros sem valores padrão, ou seja, o comprimento será distorcido. Isso ocorre porque a intenção original de comprimento é o número de parâmetros esperados pela função.

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

Escopo

Assim que o valor padrão for definido, os parâmetros formarão um escopo separado quando a declaração da função for inicializada, e o escopo se tornará inválido quando a inicialização terminar.

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

f(2)	//[2,2]

No exemplo acima, como a função é definida com um valor padrão, um escopo separado é formado dentro da função, de modo que y=xx na função se refere ao parâmetro x, não à variável global x.

parâmetro de descanso

ES6 introduz o parâmetro rest ...restpara obter os parâmetros extras da função, de forma que não haja necessidade de fazer referência ao objeto de argumentos. A variável com o parâmetro rest é uma matriz e a variável coloca os parâmetros extras nela.

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

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

Nota: O atributo de comprimento da função não inclui o número de parâmetros de descanso


Otimização da chamada final

O que é uma chamada de cauda?

Chamada de cauda, ​​como o nome sugere, significa que a última etapa de uma função é chamar outra função.

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

O sinal da chamada final é que a função deve ser chamada no final, não o resultado da chamada da operação.

Otimização da chamada final

Sabemos que uma chamada de função formará um “registro de chamada” na memória, também conhecido como “quadro de chamada”, que guarda informações como o local da chamada e variáveis ​​internas. Se a função B for chamada dentro da função A, então um quadro de chamada de B também será formado acima do quadro de chamada de A. O call frame de retornar o resultado para A e B desaparecerá após o final da operação B. Se a função B também chamar a função c, haverá um quadro de chamada de c e assim por diante. Todos os quadros de chamadas formam uma "pilha de chamadas" (pilha de chamadas).

Uma vez que a chamada final é a última operação da função, não há necessidade de manter o quadro de chamada da função externa, pois o local da chamada, as variáveis ​​internas e outras informações não serão mais utilizadas. O quadro de chamada da função interna é usado diretamente para substituir o quadro de chamada da função externa.

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

//等同于
g(3);

No código acima, se não for uma chamada final, a função f precisa salvar os valores das variáveis ​​xey, as informações de chamada de ge assim por diante. Mas, por causa da chamada final, a função f termina, de modo que o registro da chamada de f pode ser excluído da memória e apenas o quadro de chamada de g é mantido. Esta é a otimização da chamada final, que pode economizar muita memória.

Recursão de cauda

A recursão é um método que consome muita memória, porque precisa salvar um grande número de quadros de chamada, o que está sujeito a erros como estouro de memória, mas a recursão de cauda pode resolver esse problema porque ocupará apenas um quadro de chamada para sempre.

// 阶乘函数
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);
    }
}

Reescrita recursiva de cauda

O código acima não parece muito lógico. Por que passo um total quando conto um fatorial? Não pode me dar o resultado diretamente? A resposta é sim. Não se esqueça, o ES6 nos fornece operações de valor padrão!

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

factorial(5) 	//120

Há também um método de chamada final, que fornece uma forma normal de função além da função recursiva final para realizar a recursão final:

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

Este é realmente um tipo de pensamento currying. Espere um minuto! O que é currying? ? ?

Escovando

Existe um conceito importante na programação funcional, chamado currying, que significa converter uma função multiparâmetro em uma forma de parâmetro único.

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

Acho que você gosta

Origin blog.csdn.net/yivisir/article/details/107579933
Recomendado
Clasificación