Entendendo os fechamentos
Pano ofuscado
Primeiro, o que é um fechamento? Você pode entendê-lo como compartilhando variáveis em dois escopos desconectados.
Dê uma castanha:
function foo() {
var a = 10;
function bar () {
console.log(a);
}
return bar;
}
foo()();// 10 请注意这里的10怎么来的。
Você notou que as variáveis dentro da função foo são usadas abaixo do escopo global, este é o encerramento! ! !
O escopo da barra de funções abrange a função foo. Passamos a referência da função bar como valor de retorno e, em seguida, podemos usar a referência da função foo na referência.
A mágica do fechamento em si não está aqui.De um modo geral, o escopo de foo é coletado pelo coletor de lixo após a execução da função foo ser concluída, mas não está aqui, porque ainda há uma referência ao escopo de foo. Desmaiado, ou seja, bar, bar possui um ponteiro para a variável a, portanto, o escopo de foo não é recuperado após a utilização da função foo. bar ainda mantém uma referência ao escopo de foo, que é chamado de fechamento.
Há também uma variedade de fechamentos de funções.
function foo() {
var a = 2;
function baz() {
console.log( a ); // 2
}
bar( baz );
}
function bar(fn) {
fn(); // 妈妈快看呀,这就是闭包!
}
Talvez depois que você entenda, o fechamento é apenas um brinquedo um pouco estranho, mas o que eu quero dizer é que o fechamento não é apenas uma maneira de escrever, e várias situações são usadas na vida cotidiana:
function wait(message) {
setTimeout( function timer() {
console.log( message );
}, 1000 );
}
wait( "Hello, closure!" );
O escopo interno do timer não desaparece após 1000 milissegundos e, em seguida, contém uma referência à mensagem.
2. Loops e fechamentos
for (var i=1; i<=5; i++) {
setTimeout( function timer() {
console.log( i );
}, i*1000 );
}
No meu outro pequeno ponto de conhecimento no front-end, mencionei que há uma promoção variável aqui, e ela será impressa toda vez 6. Uma pequena explicação, porque após o atraso da função, irei à pesquisa RHS para a referência de i. i = 6, originalmente queríamos capturar uma cópia de i em cada iteração, mas cada iteração é um escopo compartilhado, portanto, encontramos apenas 6;
se modificarmos o código, adicionando o princípio do escopo, Vamos tentar:
for (var i = 0; i < 5; i++) {
(function () {
setTimeout( function timer() {
console.log( i );
}, i*1000 );
})();
}
Está tudo bem? Ha ha ha ha, ainda não funciona, porque nosso escopo lexical está vazio, precisamos estabelecer um atributo privado para ele.
for (var i = 0; i < 5; i++) {
(function () {
var j = i;
setTimeout( function timer() {
console.log( j );
}, j*1000 );
})();
}
Tudo bem, porque eu aponto para o escopo interno j de cada função anônima interna!
Embeleze este código:
for (var i = 0; i < 5; i++) {
(function (j) {
setTimeout( function timer() {
console.log( j );
}, j*1000 );
})(i);
}
Obviamente, se você deseja concluir a lógica de forma mais concisa, pode usar
for (let i = 0; i < 5; i++) {
setTimeout( function timer() {
console.log( i );
}, i*1000 );
}
Módulo
Depois de entender os fechamentos, vamos entender como usar os fechamentos em geral.
function Car() {
var name = "五菱宏光";
var age = "2 年";
function sayName () {
console.log(name);
}
function sayAge () {
console.log(age);
}
function drive () {
console.log('drived');
}
return {
sayName: sayName,
sayAge: sayAge,
drive: drive
}
}
var car = Car();
car.sayName();
Este é o uso de módulos.
Fonte de idéias para este blog: (NOVO) [美] -Kyle-Simpson-JavaScript que você não conhece (volume 1)