Acabei de ler um ótimo artigo sobre JavaScript Scoping and Hoisting por Ben Cherry, no qual ele dá o seguinte exemplo:
var a = 1;
function b() {
a = 10;
return;
function a() {}
}
b();
alert(a);
Usando o código acima, o navegador alertará "1".
Ainda não sei por que retorna "1". Algumas das coisas que ele diz vêm à mente, como: Todas as declarações de função são içadas para cima. Você pode definir o escopo de uma variável usando a função. Ainda não clica para mim.
javascript
scope
scoping
hoisting
desenvolvedor
fonte
fonte
var a
deve vir antes da declaração da função e a atribuiçãoa = 1
deve vir depois. Mas observe que isso não é especificado para acontecer de fato pelo analisador, tokenizador, interpretador, compilador, seja o que for, é apenas um equivalente.function a() {}
comportou da mesma forma quevar a = function () {};
” - isso está incorreto de duas maneiras: primeiro, se alguma coisa, teria sidovar a = function a() {};
(a função na verdade não é anônima), segundo, essas duas formas não são intercambiáveis, porque devar a = function a() {};
apenas avar a;
parte teria sido içada. Aa = function a() {};
parte ainda estaria por trás da declaração de retorno. Como a forma original é uma declaração de função e não uma expressão de função, ela realmente é levantada como um todo.O que você deve lembrar é que ele analisa toda a função e resolve todas as declarações de variáveis antes de executá-la. Assim....
realmente se torna
var a
força-o em um escopo local, e o escopo da variável é através de toda a função, então a variável global a ainda é 1 porque você declarou a em um escopo local ao torná-la uma função.fonte
A função
a
é içada dentro da funçãob
:o que é quase como usar
var
:A função é declarada localmente e a configuração
a
só acontece no escopo local, não no var global.fonte
function a(){}
é içada primeiro e se comporta comovar a = function () {};
, portanto, no escopo locala
é criada.a=10
, você está definindo a variável locala
, não a global.Portanto, o valor da variável global permanece o mesmo e você obtém, alertado 1
fonte
function a() { }
é uma instrução de função, que cria umaa
variável local para ab
função.As variáveis são criadas quando uma função é analisada, independentemente de a
var
instrução da função ou ser executada.a = 10
define esta variável local.fonte
a = 10
define uma variável no escopo global quando a funçãob
é executada, a menos que você adicione"use strict"
(em ambientes como o suporte a essa diretiva).Qual é o pomo da discórdia neste pequeno trecho de código?
Caso 1:
Inclua a
function a(){}
definição dentro do corpo dofunction b
seguinte.logs value of a = 1
Caso 2
Exclua a
function a(){}
definição dentro do corpo dofunction b
seguinte.logs value of a = 10
A observação o ajudará a perceber que a instrução
console.log(a)
registra os seguintes valores.Caso 1: a = 1
Caso 2: a = 10
Posições
var a
foi definido e declarado lexicamente no escopo global.a=10
Esta instrução está reatribuindo o valor para 10, que fica lexicamente dentro da função b.Explicação de ambos os casos
Por causa de
function definition with name property
um é o mesmo que ovariable a
. Ovariable a
interior dofunction body b
torna-se uma variável local. A linha anterior implica que o valor global de a permanece intacto e o valor local de a é atualizado para 10.Então, o que pretendemos dizer é que o código abaixo
Ele é interpretado pelo interpretador JS da seguinte maneira.
No entanto, quando removemos o
function a(){} definition
, ovalue of 'a'
declarado e definido fora da função b, esse valor é sobrescrito e muda para 10 no caso 2. O valor é sobrescrito porquea=10
se refere à declaração global e se fosse para ser declarado localmente, devemos ter escritovar a = 10;
.Podemos esclarecer nossas dúvidas ainda mais alterando o
name property
emfunction a(){} definition
para algum outro nome que não'a'
fonte
O içamento é um conceito feito para que seja mais fácil de entender. O que realmente acontece é que as declarações são feitas primeiro em relação aos seus escopos e as atribuições acontecerão depois disso (não ao mesmo tempo).
Quando as declarações acontecem,,
var a
entãofunction b
e dentro desseb
escopo,function a
é declarado.Esta função a irá sombrear a variável a vinda do escopo global.
Depois de feitas as declarações, os valores atribuídos começarão, o global
a
obterá o valor1
e o a dentrofunction b
obterá10
. quando você fizeralert(a)
isso, ele chamará a variável de escopo global real. Esta pequena mudança no código o tornará mais clarofonte
Surpreendentemente, nenhuma das respostas aqui menciona a relevância do contexto de execução na cadeia de escopo.
O JavaScript Engine envolve o código atualmente em execução em um contexto de execução. O contexto de execução básico é o contexto de execução global. Cada vez que uma nova função é chamada, um novo contexto de execução é criado e colocado na pilha de execução. Pense em um Stack Frame sentado em um Invocation Stack em outras linguagens de programação. Ultimo a entrar primeiro a sair. Agora, cada contexto de execução tem seu próprio ambiente variável e ambiente externo em JavaScript.
Vou usar o exemplo abaixo como uma demonstração.
1) Primeiro, entramos na Fase de Criação do Contexto de Execução global. Tanto o ambiente externo quanto o ambiente variável do ambiente lexical são criados. O Global Object é configurado e colocado na memória com a variável especial 'this' apontando para ele. A função a e seu código e a variável myVar com um valor indefinido são colocados na memória no ambiente de variável global. é importante notar que o código da função a não é executado. Ele é apenas colocado na memória com a função a.
2) Em segundo lugar, é a Fase de Execução do Contexto de Execução. myVar não é mais um valor indefinido. Ele é inicializado com o valor 1, que é armazenado no ambiente variável global. A função a é chamada e um novo contexto de execução é criado.
3) No Contexto de Execução da função a, ela passa pela Fase de Criação e Execução do seu próprio Contexto de Execução. Possui Ambiente Externo e Ambiente Variável próprios, portanto, seu Ambiente Lexical próprio. A função be a variável myVar são armazenadas em seu ambiente de variáveis. Este ambiente variável é diferente do ambiente variável global. Uma vez que a função a está lexicamente (fisicamente no código) no mesmo nível que o Contexto de Execução global, seu Ambiente Externo é o Contexto de Execução global. Assim, se a função a fosse referir-se a uma variável que não está em seu Ambiente de Variável, ela pesquisará a Cadeia de Escopo e tentará encontrar a variável no Ambiente de Variável do Contexto de Execução global.
4) A função b é invocada na função a. Um novo contexto de execução é criado. Uma vez que se senta lexicamente na função a, seu Ambiente Externo é a. Portanto, quando faz referência a myVar, uma vez que myVar não está no Ambiente de Variável da função b, ele irá olhar no Ambiente de Variável da função a. Ele o encontra lá e o console.log imprime 2. Mas se a variável não estava no Ambiente de Variável da função a, então, como o Ambiente Externo da função a é o Contexto de Execução global, a Cadeia de Escopo continuará pesquisando lá.
5) Depois que as funções be a terminam a execução, elas são retiradas da pilha de execução. O mecanismo JavaScript de thread único continua a execução no contexto de execução global. Ele invoca a função b. Mas não há função b no ambiente variável global e não há outro ambiente externo para pesquisar no contexto de execução global. Portanto, uma exceção é levantada pelo JavaScript Engine.
O exemplo abaixo mostra a Cadeia de Escopo em ação. No Ambiente de Variáveis do Contexto de Execução da função b, não há myVar. Portanto, ele pesquisa seu Ambiente Externo, que é a função a. A função a também não tem myVar em seu ambiente variável. Portanto, o mecanismo procura a função Outer Environment, que é o ambiente externo do Execution Context e myVar é definido lá. Portanto, o console.log imprime 1.
Quanto ao Contexto de Execução e ao Ambiente Lexical a ele associado, incluindo Ambiente Externo e Ambiente Variável, permite o escopo de variáveis em JavaScript. Mesmo se você chamar a mesma função várias vezes, para cada chamada, ela criará seu próprio contexto de execução. Portanto, cada contexto de execução terá sua própria cópia das variáveis em seu ambiente de variável. Não há compartilhamento de variáveis.
fonte
Isso está acontecendo porque o nome da variável é o mesmo que o nome da função significa "a". Assim, devido ao içamento do Javascript, ele tenta resolver o conflito de nomenclatura e retornará a = 1.
Eu também estava confuso sobre isso até ler esta postagem sobre "JavaScript Hoisting" http://www.ufthelp.com/2014/11/JavaScript-Hoisting.html
Espero que ajude.
fonte
Aqui está minha recapitulação da resposta com mais anotações e um violino acompanhante para brincar.
https://jsfiddle.net/adjavaherian/fffpxjx7/
fonte
escopo e fechamento e içamento (var / função)
fonte
Içar em JavaScript significa que as declarações de variáveis são executadas por todo o programa antes que qualquer código seja executado. Portanto, declarar uma variável em qualquer lugar do código é equivalente a declará-la no início.
fonte
Tudo depende do escopo da variável 'a'. Deixe-me explicar criando escopos como imagens.
Aqui, o JavaScript criará 3 escopos.
i) Escopo global. ii) Escopo da função b (). iii) Escopo da função a ().
É claro quando você chama o escopo do método 'alert' pertence ao Global naquele momento, então ele selecionará o valor da variável 'a' do escopo Global apenas que seja 1.
fonte
Postagem longa!
Mas vai limpar o ar!
A forma como o Java Script funciona envolve um processo de duas etapas:
Compilação (por assim dizer) - Esta etapa registra variáveis e declarações de funções e seus respectivos escopos. Não envolve a avaliação de expressão de função:
var a = function(){}
ou expressão de variável (como atribuir3
ax
no caso devar x =3;
que nada mais seja do que a avaliação da parte RHS.)Intérprete: Esta é a parte de execução / avaliação.
Verifique o resultado do código abaixo para entender:
Vamos quebrar:
Na fase de compilação, 'a' seria registrado no escopo global com o valor '
undefined
'. O mesmo vale para 'c
', seu valor neste momento seria 'undefined
' e não o 'function()
'. 'b
' seria registrado como uma função no escopo global. Dentrob
do escopo de, 'f
' seria registrada como uma variável que estaria indefinida neste momento e a função 'd
' seria registrada.Quando o interpretador é executado, as variáveis declaradas e
function()
(e não as expressões) podem ser acessadas antes que o interpretador alcance a linha de expressão real. Portanto, as variáveis seriam impressas 'undefined
' e a função anônima declarada pode ser chamada anteriormente. No entanto, tentar acessar uma variável não declarada antes da inicialização de sua expressão resultaria em um erro como:Agora, o que acontece quando você tem uma declaração de variável e função com o mesmo nome.
A resposta é - as funções são sempre içadas antes e se a mesma variável de nome for declarada, ela será tratada como duplicada e ignorada. Lembre-se de que a ordem não importa. As funções sempre têm precedência. Mas durante a fase de avaliação, você pode alterar a referência da variável para qualquer coisa (ela armazena o que quer que seja a última atribuição). Dê uma olhada no código abaixo:
fonte
O içamento é o conceito comportamental do JavaScript. Elevação (digamos, movimentação) é o conceito que explica como e onde as variáveis devem ser declaradas.
Em JavaScript, uma variável pode ser declarada depois de ter sido usada porque as declarações de Função e as declarações de variável são sempre movidas (“içadas”) invisivelmente para o topo de seu escopo contido pelo interpretador JavaScript.
Encontramos dois tipos de içamento na maioria dos casos.
1. Içamento de declaração variável
Vamos entender isso por este trecho de código.
Aqui, a declaração da variável a será hospedada de forma invisível pelo interpretador javascript no momento da compilação. Portanto, conseguimos obter o valor de a. Mas esta abordagem de declaração de variáveis não é recomendada, já que deveríamos declarar variáveis no topo já desta forma.
considere outro exemplo.
é realmente interpretado assim:
Neste caso, x será indefinido
Não importa se foi executado o código que contém a declaração da variável. Considere este exemplo.
Essa função acaba sendo assim.
Na declaração de variável, apenas a definição de variável eleva, não a atribuição.
Ao contrário da variável de içamento, o corpo da função ou valor atribuído também será içado. Considere este código
Agora que entendemos tanto o levantamento de variável quanto de função, vamos entender este código agora.
Este código será assim.
A função a () terá escopo local dentro de b (). a () será movido para o topo ao interpretar o código com sua definição (apenas no caso de elevação de função), portanto, a agora terá escopo local e, portanto, não afetará o escopo global de a ao mesmo tempo em que tem seu próprio escopo dentro da função b () .
fonte
Pelo que sei, o içamento acontece com a declaração da variável e a declaração da função, por exemplo:
O que acontece dentro do motor do JavaScript:
Ou:
Vai se tornar:
Mas atribuições como atribuição de variável, atribuição de expressão de função não serão içadas: Por exemplo:
Pode ficar assim:
fonte
Para descrever a hospedagem em javascript em uma frase, as variáveis e funções são colocadas no topo do escopo em que são declaradas.
Presumo que você seja um iniciante, para entender o içamento de maneira adequada, primeiro entendemos a diferença entre undefined e ReferenceError
agora no código abaixo o que vemos? uma variável e uma expressão de função são excluídas.
mas a imagem real com a prova de que a variável e a função são içadas no topo de seu escopo:
Saída dos primeiros dois registros são indefinido e TypeError: getSum não é uma função porque ambos var totalAmo e getSum são içada no topo do seu alcance como abaixo
Mas para a declaração de funções funções inteiras içadas no topo de seu escopo.
Agora, a mesma lógica vale para aqueles varibale, experiências de funções e declaratoins de função declarados dentro do escopo funcional. Ponto principal: não serão içados na parte superior da lima ;
Portanto, quando você usa var palavra-chave, variável e função içada no topo de seu escopo (escopo global e escopo de função). E quanto a let e const , const e let ainda estão cientes do escopo global e do escopo da função, assim como var, mas as variáveis const e let também estão cientes de outro escopo chamado escopo bloqueado. um escopo de bloco está presente sempre que houver um bloco de código, como for loop, instrução if else, loop while etc.
Quando usamos const e let para declarar uma variável neste escopo de bloco, a declaração da variável somente será içada no topo do bloco em que ela está, e não será içada no topo da função pai ou no topo do âmbito global que é içado.
Variáveis no exemplo abobe serão içadas como abaixo
fonte
ES5: função de içamento e içamento variável
que é igual a
a razão por trás do içamento
ES6
let
,const
não existe içamentorefs
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/var
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/const
fonte