Introdução
Em muitos idiomas tradicionais (C/C ++/Java/C#, etc.), as funções existem como cidadãos de segunda classe. Você só pode declarar uma função com as palavras -chave do idioma e depois chamá -lo. Se você precisar passar a função como um parâmetro para outra função ou atribuir um valor a uma variável local ou como um valor de retorno, precisará fazer um avanço através de métodos especiais, como ponteiro de função e proxy (delegado).
No mundo JavaScript, as funções são cidadãos de primeira classe. Eles não apenas têm todas as maneiras de usar funções tradicionais (declarações e chamadas), mas também podem atribuir valores, passar parâmetros e retornar como valores simples. Tais funções também são chamadas de funções de primeira classe. Além disso, as funções no JavaScript também atuam como construtores de classe e também são instâncias de classe de função. Tais identidades múltiplas tornam as funções do JavaScript muito importantes.
1. Javascript Função de entrada
Como os idiomas comuns, as funções JavaScript também seguem o princípio da declaração primeiro e depois o uso. Os nomes de funções podem conter apenas letras, números, sublinhados ou $ e não podem começar com números. Existem duas maneiras comuns de declarar funções:
A cópia do código é a seguinte:
// Declare a função myfunc diretamente
função myfunc (/ * argumentos */) {
}
// atribui funções anônimas à variável local myfunc
var myfunc = função (/ * argumentos */) {
}
Observe que existem diferenças sutis nas duas funções acima, métodos de declaração: o primeiro método é uma função nomeada quando declarada, seja uma função declarada antes, após a chamada ou mesmo o local em que não será executado (por exemplo, após a declaração de retorno ou em um ramo que nunca será verdadeiro), é acessível em toda a milha; O segundo método é atribuir funções anônimas a variáveis. Estritamente falando, isso não é uma declaração de função, mas uma expressão de função. Antes da atribuição, essa função não pode ser acessada por nenhum código, o que significa que a atribuição deve ser concluída antes da chamada; caso contrário, um erro será exibido ao chamar: "TypeError: indefinido não é uma função". Por exemplo:
A cópia do código é a seguinte:
myfunc1 (); // pode ser chamado normalmente, porque o myfunc1 usa um método de declaração direta
função myfunc1 () {
}
myfunc2 (); // Erro TypeError: indefinido não é uma função
var myfunc2 = function () {
};
O método de chamadas básicas de funções é chamado da mesma maneira que nos idiomas tradicionais: myfunc (). As funções JavaScript também suportam chamadas recursivas diretas ou indiretas. Por exemplo, a função clássica de Fibonacci pode ser implementada em JavaScript como este:
A cópia do código é a seguinte:
função fib (n) {
if (n == 1 || n == 2) {
retornar 1;
} outro {
retornar fib (n - 2) + fib (n - 1);
}
}
As funções no JavaScript podem lidar com parâmetros de comprimento variável. Todos eles têm uma variável local chamada argumentos dentro da função. É um objeto semelhante a uma matriz que contém todos os parâmetros passados ao ligar e ter um atributo de comprimento para representar o número de parâmetros. Por exemplo:
A cópia do código é a seguinte:
function test () {
alerta (argumentos.length);
}
teste (1); // 1
teste (1, 'a'); // 2
teste (true, [], {}); // 3 Use argumentos para implementar funções semelhantes ao printf no idioma C e também pode ser usado para implementar o polimorfismo de métodos.
2. Funções avançadas de JavaScript
2.1 Funções anônimas e aninhadas
No JavaScript, você pode declarar uma função sem nome, chamada de função anônima (função anônima). Ao mesmo tempo, o JavaScript também permite a declaração de funções dentro das funções, chamadas funções aninhadas, e o escopo das funções aninhadas é a função inteira.
Na parte anterior da declaração da função, vi um uso de funções anônimas e funções aninhadas. Como as funções anônimas não têm nome, elas não introduzirão novas variáveis para poluir o contexto e trarão novos escopos variáveis. Portanto, as funções anônimas são frequentemente usadas para impedir a poluição ambiental global.
Existe um objeto global especial no tempo de execução do JavaScript. Este objeto armazena funções e variáveis globais. No desenvolvimento real, várias bibliotecas de terceiros ou vários arquivos JS são frequentemente usados. Se você acidentalmente introduzir variáveis duplicadas ou declarações de função no objeto global, isso causará confusão na execução do código. Por exemplo, dois arquivos JS são introduzidos sucessivamente e seu próprio log de funções é definido como uso interno. A segunda função introduzida substituirá a definição do primeiro e não lançará erros. Chamar a função de log na execução subsequente pode causar um erro. Neste momento, o uso de uma função anônima para envolver a lógica em todo o JS pode evitar esse erro. Este método foi usado pela maioria das bibliotecas JS de código aberto.
A cópia do código é a seguinte:
(function () {// função anônima
Log da função (msg) {
console.log (msg);
}
// Outros códigos
} ()); // execute imediatamente
O código acima é um exemplo simples. O escopo da função de log é limitado a essa função anônima. A função anônima é incluída em um par de colchetes () fora para formar uma expressão de função. O valor da expressão é uma função, seguida por um par de colchetes para indicar que a função é executada imediatamente, para que o código original possa ser executado normalmente. No entanto, as funções declaradas dessa maneira, variáveis declaradas através do VAR, etc. são internas e não podem ser acessadas por qualquer código que não seja funções anônimas. Se você precisar expor algumas funções como interfaces, existem vários métodos:
A cópia do código é a seguinte:
var mylib = (função (global) {
Log da função (msg) {
console.log (msg);
}
log1 = log; // Método 1: use o comportamento padrão da declaração variável sem VAR para se tornar uma variável global no log1 (não recomendado)
global.log2 = log; // Método 2: Adicione diretamente o atributo log2 ao objeto global e atribua -o a uma função de log (recomendado)
Retornar {// Método 3: retorne uma série de objetos de coleta de funções de interface por meio de funções anônimas e atribua -as à variável global MyLib (recomendada)
LOG: LOG
};
}(janela));
2.2 Função de alta ordem
Se uma função for usada como um parâmetro ou valor de retorno, ela será chamada de função de ordem superior. As funções no JavaScript podem ser usadas como funções de ordem superior, que também é um recurso do primeiro tipo de funções. Vamos analisar esses dois métodos de uso abaixo.
A cópia do código é a seguinte:
função negativa (n) {
retornar -n; // Tome o valor oposto de n
}
Função quadrada (n) {
retornar n*n; // quadrado de n
}
Processo de função (NUMS, retorno de chamada) {
var resultado = [];
for (var i = 0, comprimento = nums.length; i <comprimento; i ++) {
resultado [i] = retorno de chamada (nums [i]); // Passe todos os elementos no Array nums para retorno de chamada para processamento e salve o valor de retorno como resultado
}
resultado de retorno;
}
var nums = [-3, -2, -1, 0, 1, 2, 3, 4];
var n_neg = Process (nums, negativo);
// n_neg = [3, 2, 1, 0, -1, -2, -3, -4];
var n_square = processo (nums, quadrado);
// n_square = [9, 4, 1, 0, 1, 4, 9, 16];
O código acima mostra um exemplo de aprovação de uma função como um parâmetro em outra chamada de processo de função. Na implementação da função do processo, o retorno de chamada é considerado uma caixa preta, responsável por transmitir o parâmetro e, em seguida, obter o valor de retorno. A implementação específica do retorno de chamada não está clara antes da chamada. Somente quando 20 e 22 linhas são executadas, o retorno de chamada é representado por negativo ou quadrado, respectivamente, e cada elemento é obtido com o valor oposto ou o valor quadrado.
A cópia do código é a seguinte:
função generator () {
var i = 0;
Return function () {
retornar i ++;
};
}
var gen1 = gerador (); // Obtenha um gerador de números naturais
var gen2 = gerador (); // Obtenha outro gerador de números naturais
var r1 = gen1 (); // r1 = 0
var r2 = gen1 (); // r2 = 1
var r3 = gen2 (); // r3 = 0
var r4 = gen2 (); // r4 = 1
O código acima mostra um exemplo de uso de uma função como um valor de retorno. O gerador é uma função de gerador de números naturais e o valor de retorno é uma função de gerador de números naturais. Cada gerador de tempo é chamado, uma função anônima será retornada como resultado. Essa função anônima retorna cada número natural, por sua vez, quando é realmente chamado. A variável I no gerador aumentará em 1 sempre que essa função anônima é chamada, o que é na verdade um fechamento. Vamos introduzir fechamentos abaixo.
2.3 Fechamento
Os fechamentos não são um conceito novo, e muitos idiomas funcionais usam fechamentos. No JavaScript, quando você usa variáveis dentro do escopo das funções externas em uma função incorporada, você usa o fechamento. Use uma analogia comumente usada para explicar a relação entre um fechamento e uma classe: uma classe é dados com funções e um fechamento é uma função com dados.
As variáveis usadas nos fechamentos têm uma característica de que não são liberadas quando a função pai retorna, mas termina com o final do ciclo de vida do fechamento. Por exemplo, como no exemplo do gerador na seção anterior, Gen1 e Gen2 usam variáveis independentes I, respectivamente (quando o Gen1 I é aumentado em 1, o Gen2 não será afetado e vice -versa). Enquanto as duas variáveis Gen1 ou Gen2 não forem coletadas com lixo pelo mecanismo JavaScript, suas respectivas variáveis não serão liberadas. Na programação JavaScript, os fechamentos são usados inconscientemente. Esse recurso do fechamento é fácil de usar, mas também leva facilmente a problemas de vazamento de memória. Por exemplo:
A cópia do código é a seguinte:
var elem = document.getElementById ('teste');
elem.addeventListener ('click', function () {
alerta ('você clicou' + elem.tagname);
});
O objetivo deste código é exibir seu nome de etiqueta ao clicar em um nó. Ele registra uma função anônima como uma função de manuseio de eventos de clique de um nó DOM. Um objeto DOM elem é referenciado na função, que forma um fechamento. Isso gerará uma referência circular, ou seja: Dom-> clossary-> dom-> clossary ... O objeto DOM não será liberado antes que o fechamento seja liberado; E o fechamento existe como a função de manuseio de eventos do objeto DOM, para que o fechamento não seja liberado antes que o objeto DOM seja liberado. Mesmo que o objeto DOM seja excluído na árvore DOM, devido à existência dessa referência circular, nem o objeto DOM nem o fechamento serão liberados. Este vazamento de memória pode ser evitado usando os seguintes métodos:
A cópia do código é a seguinte:
var elem = document.getElementById ('teste');
elem.addeventListener ('click', function () {
alert ('você clicou' + this.TagName); // não mais diretamente referencia a variável elem
});
No código acima, isso é usado em vez de elem (esse ponteiro aponta para o próprio elemento DOM na função de manuseio de eventos DOM), para que o tempo de execução do JS não acredite mais que a função use as variáveis da classe pai, para que não seja mais um fechamento.
Os fechamentos também trarão muitos problemas de vazamento de memória semelhantes. Você só pode prestar atenção ao fechamento ao escrever código e tentar evitar esses problemas.
2.4 Construtor de classe
As funções JavaScript também são usadas como construtores de classe, para que você possa usar a nova palavra -chave para criar uma instância da classe, desde que declare uma função.
A cópia do código é a seguinte:
Função Pessoa (nome) {
this.name = nome;
this.toString = function () {
retornar 'Olá,' + this.name + '!';
};
}
var p = nova pessoa ('GhostTheAven');
alerta (P); // Olá, GhostTheaven! No exemplo acima, a função de pessoa é usada como construtor de classe. No momento, isso aponta para o objeto de instância recém -criado e pode adicionar propriedades e métodos à instância. Para uma programação JavaScript detalhada orientada a objetos, consulte este artigo. O que eu quero dizer aqui é o problema do valor de retorno ao usar as funções JavaScript como construtores de classe.
A cópia do código é a seguinte:
função myclass (nome) {
this.name = nome;
Nome de retorno; // O valor de retorno do construtor?
}
var obj1 = new myclass ('foo');
var obj2 = myclass ('foo');
var obj3 = novo myclass ({});
var obj4 = myclass ({});
O construtor acima é bastante especial, com uma declaração de retorno, então quais objetos obj1 ~ obj4 apontam? O resultado real é o seguinte:
A cópia do código é a seguinte:
obj1 = objeto myclass
obj2 = 'foo'
obj3 = {}
obj4 = {}
Os motivos específicos são explicados neste artigo, e eu não o repetirei neste artigo. Como os construtores com valores de retorno produzirão resultados estranhos, não ligue para declarações de retorno com valores de retorno no construtor (o retorno vazio pode ser feito).
3. Javascript Functions Monster Nível
Bem-vindo à área de ensino da função no nível do monstro, onde você terá como enfrentar o velho monstro calma e livremente. . .
3.1 Classe de função
Há uma classe interna chamada função no tempo de execução do JavaScript. Declarar uma função com a palavra -chave da função é na verdade uma abreviação para criar objetos de classe de função. Todas as funções possuem todos os métodos da classe de função, como chamada, aplicação, ligação, etc. Você pode verificar essa instrução através da instância da palavra -chave.
Como a função é uma classe, seu construtor é a função (é um objeto da classe de função) e um objeto de função deve ser gerado através da nova palavra -chave. O primeiro monstro está aqui, que é como construir uma função usando a classe de função. A sintaxe da função é a seguinte:
A cópia do código é a seguinte:
nova função ([arg1 [, arg2 [, ... argn]],] functionbody)
onde arg1, arg2, ... argn é uma string, representando o nome do parâmetro, e functionbody também é uma string, representando o corpo da função. O nome do parâmetro anterior é mais ou menos. O construtor da função tratará o último parâmetro como o corpo da função e os anteriores como parâmetros.
A cópia do código é a seguinte:
var func1 = new function ('nome', 'return "hello," + name + "!";');
func1 ('GhostTheaven'); // Olá, GhostTheaven!
O método acima constrói uma função através da função, o que é exatamente o mesmo que outras funções declaradas com a palavra -chave da função.
Vendo isso, muitas pessoas podem perguntar por que esse monstro é necessário? "O que existe é razoável", a classe de função tem seu objetivo único. Você pode usá -lo para gerar dinamicamente várias lógicas de função ou substituir as funções da função de avaliação e impedir que o ambiente atual seja poluído*.
3.2 Função de auto-atualização
Em muitos idiomas, uma vez declarado uma função, ela não pode declarar a função do mesmo nome novamente, caso contrário, ocorrerão erros de sintaxe. As funções no JavaScript não só podem ser declaradas repetidamente, mas também se atualizam. O monstro que eu como está aqui!
A cópia do código é a seguinte:
função autopdate () {
window.selfupdate = function () {
alerta ('segunda corrida!');
};
alerta ('primeira corrida!');
}
autopdate (); // Primeira corrida!
autopdate (); // segunda corrida! Essa função pode ser usada para a lógica executada apenas uma vez e, após a primeira execução, é substituída por uma nova peça de lógica.
resumo
As funções do JavaScript são muito poderosas. Ao resolver muitos problemas lindamente, eles também trazem muitos problemas negativos. As funções no nível de monstros geralmente são usadas com uso pouco conhecido. A menos que seja particularmente necessário, causará dificuldades de leitura de código e afetará a eficiência do desenvolvimento da equipe.
* Um modo rigoroso foi introduzido no novo ECMAScript. No modo rigoroso, a função de avaliação é bastante restrita e pode garantir que o ambiente não seja poluído.
Você entende, é muito prático. Se houver algum lugar ausente, dê -me alguns conselhos e faça progresso juntos.