parâmetros reais Os parâmetros de função aparecerão em dois locais, ou seja, o local de definição da função e o local de chamada de função. Os parâmetros nesses dois locais são diferentes.
Parâmetros formais (parâmetros formais)
Os parâmetros que aparecem na definição da função podem ser considerados como um espaço reservado. Não possui dados e só pode esperar até que a função seja chamada para receber os dados passados, por isso é chamado de parâmetro formal, ou formal. parâmetro para abreviar.
Parâmetros reais (parâmetros reais)
Os parâmetros fornecidos quando a função é chamada contêm dados reais e serão usados pelo código dentro da função, por isso são chamados de parâmetros reais, ou parâmetros reais, para abreviar.
A diferença e a conexão entre parâmetros formais e parâmetros reais
1) Variáveis de parâmetros formais só alocarão memória quando a função for chamada. Após a conclusão da chamada, a memória será liberada imediatamente, portanto, as variáveis de parâmetros formais só serão válidas dentro da função e. não pode ser usado fora da função.
2) Os parâmetros reais podem ser constantes, variáveis, expressões, funções, etc. Não importa que tipo de dados sejam os parâmetros reais, eles devem ter determinados valores ao fazer chamadas de função para transferir esses valores para os parâmetros formais , portanto, você deve usar atribuição, entrada e outros métodos com antecedência para obter um determinado valor para os parâmetros reais.
3) Os parâmetros reais e os parâmetros formais devem ser estritamente consistentes em número, tipo e ordem, caso contrário ocorrerá um erro de "incompatibilidade de tipo". Obviamente, se a conversão automática de tipo for possível ou a conversão forçada de tipo for executada, o tipo de parâmetro real também poderá ser diferente do tipo de parâmetro formal.
4) A transferência de dados que ocorre em uma chamada de função é unidirecional e o valor do parâmetro real só pode ser transferido para o parâmetro formal, mas o valor do parâmetro formal não pode ser transferido para o parâmetro real na direção reversa ;em outras palavras, uma vez concluída a transferência de dados, os parâmetros reais e os parâmetros formais não estão mais relacionados, portanto, durante a chamada da função, as alterações no valor dos parâmetros formais não afetarão os parâmetros reais.
5) Embora os parâmetros formais e os parâmetros reais possam ter o mesmo nome, eles são independentes um do outro e não afetam um ao outro, porque os parâmetros reais são válidos fora da função, enquanto os parâmetros formais são válidos dentro da função.
A função dos parâmetros formais e dos parâmetros reais é passar dados. Quando ocorre uma chamada de função, o valor do parâmetro real será passado para o parâmetro formal.
função de passagem de parâmetro nos permite passar dados, e os dados passados afetam os resultados da execução da função, tornando a função mais flexível e reutilizável.
função foo(a, b) { console.log([a,b]); } foo(1, 2); //
Neste exemplo de saída [1, 2], a
e b
são variáveis locais na função e só podem ser acessadas dentro da função. Ao chamar a função, b
a
.
Ao criar uma função, os parâmetros definidos entre parênteses após function 函数名
são chamados de parâmetros formais ; ao chamar uma função, os parâmetros passados entre parênteses após o nome da função são chamados de parâmetros reais ; No exemplo acima, a
e b
são parâmetros formais e os passados em 1
e 2
são parâmetros reais.
Como os parâmetros formais são variáveis declaradas, eles não podem ser declarados repetidamente com let
e const
.
função foo(a, b) { let a = 1; // Erro, a foi declarado const b = 1; // Erro, b foi declarado}
Todas as transferências de funções em JavaScript são passadas por valor, não por referência. O chamado valor refere-se ao valor armazenado diretamente na variável. Se o objeto for passado como parâmetro, então o valor é uma referência ao objeto, não ao próprio objeto. Na verdade, este é um processo de atribuição implícito, portanto, ao passar parâmetros para uma função, equivale a atribuir valores de uma variável para outra variável .
Valor original:
function add(num) { retornar num + 1; } vamos contar = 5; let result = add(count); // O processo de passagem de parâmetros aqui pode ser considerado como num = count); console.log(contagem); // 5 console.log(resultado); // 6
valor de referência:
function setName(obj) { obj.name = "Xiao Ming"; } deixe pessoa = {}; setName(person); // O processo de passagem de parâmetro aqui pode ser visto como obj = person; console.log(person); // {name: "Xiao Ming"}
As funções em JavaScript não detectarão o tipo de parâmetros nem o número de parâmetros passados. Definir dois parâmetros formais ao definir uma função não significa que dois parâmetros devam ser passados durante a chamada. Ao chamar, não importa se um ou três parâmetros são passados, nenhum erro será relatado, mesmo que nenhum parâmetro seja passado.
Existe um objeto especial semelhante a um array chamado arguments
(não uma instância de Array
) em todas as funções (não setas), que contém uma cópia de todos os parâmetros reais. Podemos usá-lo para obter os valores de todos os parâmetros reais de acordo. ao método de acesso ao índice do valor da matriz, você também pode acessar sua propriedade arguments.length
para determinar o número de parâmetros passados quando a função é realmente chamada.
Por exemplo:
função foo(a, b) { console.log(argumentos[0]); console.log(argumentos[1]); console.log(argumentos.comprimento); } foo(10, 20); // Saída 10, 20, 2 em sequência.
No exemplo acima, o primeiro parâmetro da função foo() é a, e o segundo parâmetro é b, que pode ser obtido separadamente por meio de argumentos[ x]. Mesmo valor. Portanto, você pode até declarar uma função sem definir parâmetros formais.
função foo() { console.log(argumentos[0]); console.log(argumentos[1]); } foo(10, 20); // Saída 10 e 20 em sequência
Pode-se ver que os parâmetros formais da função JavaScript são escritos apenas por conveniência. Passar quantos parâmetros desejar não causará erro.
Outra coisa a notar é que arguments
podem ser usados em conjunto com parâmetros formais, e os valores no objeto arguments
serão sincronizados com os parâmetros formais correspondentes. Por exemplo:
função foo(a) { argumentos[0]++; console.log(a); } foo(10); // Saída 11 //------------------------------------------------------ função foo2(a) { um++; console.log(argumentos[0]); } foo2(10); // Saída 11
Quando o valor de argumentos[0] ou a é modificado, o outro também é alterado. Isso não significa que eles acessem o mesmo endereço de memória, afinal estamos passando um valor primitivo. Eles ainda estão separados na memória, mas seus valores são mantidos sincronizados devido a mecanismos internos.
Além disso, se o parâmetro estiver faltando, o valor deste parâmetro formal não será sincronizado com o valor correspondente no objeto arguments
. Por exemplo, no exemplo a seguir, apenas um parâmetro é passado, portanto, há apenas um valor de parâmetro real em arguments
. Neste momento, se argumentos[1] for definido como um determinado valor na função, esse valor não será sincronizado. para o segundo parâmetro formal, por exemplo:
function foo(a,b) { argumentos[1] = 2; console.log(b); } foo(1); // Saída indefinida
Neste exemplo, o parâmetro formal b não possui um parâmetro real passado e seu valor será padronizado como undefined
. Mas se:
foo(1, undefined); //
Quando a saída 2 é passada manualmente em undefined
, um elemento com valor undefined
aparecerá no array arguments
, que ainda pode ser sincronizado com o valor de b.
No modo estrito , os valores e parâmetros formais no objeto arguments
não serão mais sincronizados. É claro que, se os valores de referência forem passados, eles ainda afetarão uns aos outros, mas isso é apenas uma característica dos valores de referência. Portanto, é melhor não confiar neste mecanismo de sincronização durante o desenvolvimento, ou seja, não utilizar parâmetros formais e seus valores correspondentes no objeto arguments
ao mesmo tempo.
Não há argumentos nas funções de seta
. Se a função for definida usando a sintaxe de seta, não há nenhum objeto de argumentos na função e só pode ser acessado por meio dos parâmetros formais definidos.
deixe foo = () => { console.log(argumentos[0]); }foo(); // Erro, os argumentos são indefinidos.
Em alguns casos, arguments
podem ser acessados:
function fn1(){ deixe fn2 = () => { console.log(argumentos[0]); } fn2(); }fn1(5);
Mas esses arguments
não são da função de seta, mas pertencem à função ordinária externa. Quando arguments
são acessados na função de seta, arguments
da função externa são encontrados ao longo da cadeia de escopo.
Quando uma função contém vários parâmetros formais, chamar a função se torna um problema, porque você sempre precisa garantir que os parâmetros passados sejam colocados na posição correta. a limitação da ordem de passagem de parâmetros?
Como os atributos do objeto não são ordenados, o valor correspondente é determinado pelo nome do atributo. Portanto, você pode passar o objeto e usar as propriedades do objeto como parâmetros reais, de modo que a ordem dos parâmetros não importa.
função foo(obj) { console.log(obj.nome, obj.sexo, obj.idade); } foo({ sexo: 'Masculino', idade: 18, nome: 'Xiao Ming' }); // Xiao Ming é homem 18
Se nenhum parâmetro real for fornecido ao chamar uma função, o valor padrão dos parâmetros formais é undefined
.
Às vezes, queremos definir um valor padrão específico. Antes do ES6, quando a configuração explícita do valor padrão não era suportada, só podíamos usar uma solução alternativa:
function sayHi(name) {. nome = nome || 'todos'; console.log('Olá ' + nome + '!'); } sayHi(); // Saída 'Olá a todos!'
e determine se há alguma atribuição verificando o valor do parâmetro Embora o método acima seja simples, a desvantagem é que se o parâmetro real recebido corresponder a um valor booleano de false
, o parâmetro real não funcionará. Se precisar de mais precisão, você pode usar uma instrução if
ou uma expressão ternária para determinar se o parâmetro é igual a undefined
. Nesse caso, significa que o parâmetro está faltando:
// a instrução if determina a função sayHi(name) {. if (nome === indefinido) { nome = 'todos'; } console.log('Olá ' + nome + '!'); } //Função de julgamento de expressão ternária sayHi(name) { nome = (nome! == indefinido) ? nome: 'todos'; console.log('Olá ' + nome + '!'); }
ES6 é muito mais conveniente porque suporta a forma explícita de definir valores padrão, como este:
function sayHi(name = 'everyone') { // Ao definir uma função, atribua valores diretamente aos parâmetros formais console.log( 'Olá' + nome + '!'); } sayHi(); // Saída 'Olá a todos!' sayHi('Tony'); // Saída 'Olá Tony!' sayHi(undefined); // Saída 'Olá a todos!'
Esses resultados mostram que ele também determina se o parâmetro está faltando se o parâmetro é igual a undefined
.
O valor padrão não pode ser apenas um valor, mas também qualquer expressão legal, até mesmo uma chamada de função:
function sayHi(name = 'every'+'one') { console.log('Olá ' + nome + '!'); } sayHi(); // Saída 'Olá a todos!' //---------------------------------------------------- função foo() { console.log('Chamando foo'); retornar 'Tony'; } function digaOi(nome = foo()) { console.log('Olá ' + nome + '!'); } sayHi(); // Saída 'chamar foo' // Saída 'Olá Tony!' sayHi(indefinido); // Saída 'chamar foo' // Saída 'Olá Tony!' sayHi('John'); // Saída 'Hello John!'
Você pode ver que o valor padrão do parâmetro da função só será avaliado quando a função for chamada e o valor do parâmetro estiver faltando ou undefined
, e não será. avaliado quando a função é definida.
Normalmente definimos valores padrão para os parâmetros para que possamos omiti-los adequadamente ao chamar a função. O que deve ser observado aqui é que quando há vários parâmetros, se o parâmetro com valor padrão não for colocado no final, ele será colocado. é realmente impossível omitir.
função fn(x = 1, y) { console.log([x, y]); } fn(); // saída[1, indefinido] fn(2); //saída[2, indefinido] fn(, 2); // Erro, erro de sintaxe (slots vazios como arrays não são suportados aqui) fn(undefined, 2); // Saída [1, 2] (É melhor passar 1 por conveniência!)
No exemplo acima, o valor padrão definido para o parâmetro formal x parece sem sentido. Portanto, o melhor é colocar parâmetros com valores padrão no final:
função fn(x, y = 2) { console.log([x, y]); } fn(); // saída[indefinido, 2] fn(1); //saída[1, 2] fn(1, 1) //saída[1, 1]Problema de omissão de parâmetros
Quando vários parâmetros têm valores padrão definidos, o problema surge novamente. Você não pode omitir os parâmetros anteriores e passar apenas os parâmetros reais para o último parâmetro.
função fn(x, y = 2, z = 3) { console.log([x, y, z]); } fn(1, , 10) // Reportar erro
Sabíamos anteriormente que podemos evitar a restrição da ordem dos parâmetros passando objetos. Como implementar valores padrão de parâmetros? Usar ||
, instruções if
ou expressões ternárias para julgar também é uma solução, mas isso parece um pouco atrasado. A seguir estão dois outros novos métodos no ES6.
Os valores padrão dos parâmetros são usados em conjunto com Object.assign()
função fn(obj = {}) { deixe defaultObj = { x: indefinido, você: 2, z: 3 } deixe resultado = Object.assign (defaultObj, obj); console.log([resultado.x, resultado.y, resultado.z]); } fn(); // saída [indefinido, 2, 3] fn({ x: 1, z: 10 }); // Saída [1, 2, 10]
No exemplo acima, um objeto defaultObj
é definido na função e as propriedades nele são usadas como os valores padrão dos parâmetros. Em seguida, Object.assagin() é usado para mesclar o objeto recebido e o objeto padrão. propriedades em defaultObj serão Os mesmos atributos de obj serão substituídos. Se houver outros atributos em obj, eles serão atribuídos a defaultObj. Aqui uma variável é usada para receber o objeto mesclado retornado.
Ao mesmo tempo, o valor padrão do parâmetro formal obj
também é definido como um objeto vazio para evitar que nenhum parâmetro seja passado quando a função é chamada, porque isso fará com que o segundo parâmetro recebido por Object.assign() seja undefined
, resultando em um erro.
Valores padrão de parâmetros e atribuições de desestruturação são usados juntos
Quando uma função é chamada, a correspondência de parâmetros reais e parâmetros formais é na verdade um processo de atribuição implícito. Portanto, a passagem de parâmetros também pode ser desconstruída e atribuída:
função fn({ x, y = 2, z = 3 }) { console.log([x, y, z]); } fn({}); // Saída [indefinido, 2, 3] fn({ x: 1, z: 10 }); // Saída [1, 2, 10]
Neste exemplo, apenas o valor padrão da atribuição de desestruturação do objeto é usado e o valor padrão do parâmetro da função não é usado. Se nenhum parâmetro for passado quando a função for chamada, um erro também será relatado, pois isso fará com que a atribuição de desestruturação falhe durante a inicialização do parâmetro, o que equivale à execução de código como {x, y = 2, z = 3} = undefined
.
Da mesma forma, você pode usar a sintaxe dos valores padrão dos parâmetros para definir um objeto de desestruturação padrão para {x, y = 2, z = 3}
, para que funções sem passar parâmetros possam ser executadas sem problemas:
função fn({ x, y = 2, z = 3 } = {}) { console.log([x, y, z]); } fn(); // saída [indefinido, 2, 3]
Existem valores padrão duplos aqui, o que pode ser um pouco confuso. Portanto, use um pseudocódigo para explicar o processo de inicialização do parâmetro acima:
if(parâmetros reais=== {...}) { // quando fn({...}); { x, y = 2, z = 3 } = {...}; } else if (parâmetro real === indefinido){ // quando fn(); { x, y = 2, z = 3 } = {}; }
Há um detalhe que requer atenção especial aos valores padrão duplos, que é a diferença entre o valor padrão da atribuição de desestruturação e o valor padrão do parâmetro da função. Veja o exemplo a seguir:
função fn ({ x = 1 } = {}, { y } = { y: 2 }){ console.log(x,y); } fn(); // Saída 1 2 fn({ x: 10 }, { y: 20 }); // Saída 10 20 fn({},{}); // 1 indefinido
Nesta função, existem dois conjuntos de parâmetros que usam atribuição de desestruturação. Parece que xey têm valores padrão definidos. Embora sejam duas formas diferentes, os resultados obviamente não são os mesmos. Quando o parâmetro passado é {}
, y não obtém o valor padrão 2. Por que isso acontece? Combinado com o exemplo de pseudocódigo anterior:
fn({ x: 10 }, { y: 20 }); // Durante a inicialização: { x = 1 } = { x: 10 }, { y } = { y: 20 } fn({},{}); // Durante a inicialização: { x = 1 } = {}, { y } = {}
Quando o parâmetro passado é {}
, o parâmetro de função não está ausente ou undefined
, portanto, o valor padrão do parâmetro de função não tem efeito. Ao mesmo tempo, não há valores correspondentes para x e y em {}
1 obtido por x é o valor padrão da atribuição de desestruturação e y não tem valor padrão para a atribuição de desestruturação, portanto, o padrão é undefined
.
Escopo e zona morta temporária dos valores padrão dos parâmetros
Há outro pequeno detalhe. Uma vez que os parâmetros são definidos com valores padrão, eles formarão seu próprio escopo (envolvido em (...)
), portanto variáveis no corpo da função não podem ser referenciadas:
função foo(a = b) { seja b = 1; } foo(); // Erro, b é indefinido
Mas este escopo é apenas temporário. Após a inicialização dos parâmetros, esse escopo não existirá mais.
Também segue as regras dos escopos ordinários:
seja b = 2; função foo(a = b) { seja b = 1; retornar um; } foo(); // 2
No exemplo acima, existe uma variável global b, então o parâmetro formal a obterá o valor da variável global b.
Claro, se houver um parâmetro formal b no escopo do parâmetro formal, ele primeiro obterá o escopo atual:
seja b = 2; função foo(b = 3,a = b) { retornar um; } foo(); //3
Defina valores padrão para múltiplos parâmetros, eles serão inicializados na ordem, seguindo as regras da “zona morta temporária”, ou seja, os parâmetros anteriores não podem referir-se aos parâmetros posteriores:
função foo(a = b, b = 2) { retornar a + b; } foo(); // Erro, b não pode ser acessado antes da inicialização
parâmetros restantes
ES6 fornece a sintaxe **remaining parameters (rest)** ( ...变量名
), que pode coletar parâmetros reais redundantes da função (ou seja, parâmetros reais que não correspondem aos parâmetros formais), para que não haja precisa usar arguments
. Se o parâmetro formal for usado com o operador ...
, ele se tornará um array e os parâmetros reais redundantes serão colocados neste array.
Uso básico dos parâmetros restantes:
função soma(a, ...valores) { for (seja val de valores) { a += val; } retornar um; } soma(0, 1, 2, 3);
No exemplo acima, durante a inicialização do parâmetro, a correspondência é realizada primeiro com base na posição do parâmetro, 0 é atribuído a a e, em seguida, os parâmetros restantes 1, 2 e 3 serão colocados nos valores da matriz.
A seguir está um exemplo de comparação do uso de objetos arguments
e parâmetros restantes para obter parâmetros:
// Como escrever argumentos function sortNumbers() { retornar Array.prototype.slice.call(argumentos).sort(); } // Como escrever os parâmetros restantes const sortNumbers = (...numbers) => { retornar números.sort(); }
Pode-se observar que os demais parâmetros são escritos de forma mais concisa. Embora arguments
seja um objeto semelhante a um array e um objeto iterável, afinal não é um array. Ele não suporta métodos de array. Quando usamos arguments
, se quisermos chamar um método de array, devemos primeiro usar Array.prototype.slice.call
para convertê-lo em um array.
Os parâmetros restantes são diferentes do objeto arguments
. Eles são instâncias reais Array
e podem facilmente usar o método array. E as funções de seta também suportam os parâmetros restantes.
Além disso, o uso dos parâmetros restantes não afeta a funcionalidade do objeto arguments
, ele ainda pode refletir os parâmetros passados ao chamar a função.
A posição dos parâmetros restantes
O parâmetro restante deve ser o último parâmetro formal, caso contrário um erro será relatado.
// Função de relatório de erros fn1(a, ...rest, b) { console.log([a, b, descanso]); } //Maneira correta de escrever a função fn2(a, b, ...rest) { console.log([a, b, descanso]); } fn2(1, 2, 3, 4) // Saída [1, 2, [3, 4]]
Expandir sintaxe
Anteriormente sabíamos como coletar parâmetros redundantes em um array, mas às vezes precisamos fazer o oposto, como passar os elementos de um array para uma função separadamente em vez de passar um array, assim:
função soma(...valores) { seja soma = 0; for (seja val de valores) { soma += valor; } soma de retorno; } deixe arr = [1, 2, 3, 4]; soma(arr); // "01,2,3,4"
A função do exemplo acima irá acumular todos os valores passados. Se passarmos diretamente em um array, não obteremos o resultado que desejamos.
No exemplo, se um array for passado, o valor dos valores se tornará [[1, 2, 3, 4]]
, resultando em apenas um elemento no array valores, e o tipo deste elemento é um array . Então, o valor de retorno da função é o resultado da adição do valor 0
e da matriz [1, 2, 3, 4]
. Os dois tipos são convertidos implicitamente em strings e, em seguida, somados.
Para desmontar o array e passá-lo para a função, primeiro é impossível passar os parâmetros um por um - sum(arr[0], arr[1], arr[2], arr[3]);
nem sempre é possível Você sabe quantos elementos existem no array e pode haver muitos elementos no array. Não é aconselhável passá-lo manualmente.
É mais viável usar o método apply():
soma.apply(null, arr);
Mas esta ainda não é a solução ideal, então aí vem o ponto chave!
A nova **expandir sintaxe (spread)** no ES6 pode nos ajudar a enfrentar essa situação. Ele também usa ...变量名
. Embora seja igual à sintaxe de parâmetro restante, sua finalidade é completamente oposta. Ele pode dividir um objeto iterável em uma sequência de parâmetros separados por vírgula.
Quando a função é chamada, sua aplicação é a seguinte:
soma(...arr); // 10 // Equivalente a sum(1,2,3,4);
Ele pode até ser usado com valores regulares à vontade, não há restrição nas posições frontal e traseira e vários objetos iteráveis podem ser passados ao mesmo tempo:
soma(-1, ...arr); // 9 soma(...arr, 5); soma(-1, ...arr, 5); soma(-1, ...arr, ...[5, 6, 7]);
O operador de expansão ...
equivale a completar a operação de passagem manual de parâmetros separadamente para nós. A função só sabe que os parâmetros reais recebidos são valores individuais, e não terão outros efeitos devido à existência do operador de expansão.
Embora os exemplos acima sejam todos para arrays, a sintaxe de expansão pode fazer mais do que isso. Outros objetos iteráveis, como strings e objetos literais, podem ser expandidos.
Parâmetros formais são variáveis locais declaradas na função. Os parâmetros reais passados para a função serão atribuídos aos parâmetros formais. A passagem de parâmetros da função é, na verdade, um processo de atribuição implícito.
O número de parâmetros formais e parâmetros reais pode não ser igual:
● Parâmetros formais com parâmetros reais ausentes receberão o valor padrão undefined
.
● Parâmetros reais adicionais podem ser acessados através do objeto arguments
, exceto para funções de seta.
Você pode passar o objeto para que a ordem de passagem dos parâmetros não seja mais importante e permitir que as propriedades do objeto sejam usadas como parâmetros reais.
Valor padrão do parâmetro ES6 - o valor padrão será obtido somente se o valor do parâmetro estiver ausente ou undefined
quando a função for chamada.
● Os parâmetros que definem valores padrão só podem ser omitidos se forem colocados na última posição.
● O valor padrão da configuração do parâmetro formal não pode se referir às variáveis no corpo da função, mas pode se referir aos parâmetros formais anteriores e às variáveis externas.
● A implementação de valores padrão por meio de Object.assign() ou a desestruturação da atribuição pode tornar o método de passagem de parâmetros mais flexível.
A principal diferença entre parâmetros e arguments
restantes:
● Os parâmetros restantes contêm apenas os parâmetros reais que não possuem parâmetros formais correspondentes, enquanto arguments
contém todos os parâmetros reais passados para a função.
● Os parâmetros restantes são instâncias reais Array
, enquanto arguments
são apenas objetos semelhantes a array.
Tanto os parâmetros restantes quanto a sintaxe de expansão usam ...
, em cenários relacionados à função:
● Aparece no final da lista de parâmetros da função e é o parâmetro restante.
● Ocorre em chamadas de função, é uma sintaxe de expansão.
O artigo acima explica os detalhes dos parâmetros nas funções JavaScript. Para obter mais informações, preste atenção a outros artigos relacionados no site php chinês!