Escopo e levantamento da função Javascript

89

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.

desenvolvedor
fonte

Respostas:

120

Elevação de função significa que as funções são movidas para o topo de seu escopo. Isso é,

function b() {  
   a = 10;  
   return;  
   function a() {} 
} 

será reescrito pelo intérprete para este

function b() {
  function a() {}
  a = 10;
  return;
}

Estranho, hein?

Além disso, neste caso,

function a() {}

comportou-se da mesma forma que

var a = function () {};

Então, em essência, é isso que o código está fazendo:

var a = 1;                 //defines "a" in global scope
function b() {  
   var a = function () {}; //defines "a" in local scope 
   a = 10;                 //overwrites local variable "a"
   return;      
}       
b();       
alert(a);                 //alerts global variable "a"
Peter Olson
fonte
2
Portanto, todas as declarações de função são eventualmente atribuídas a uma variável?
dev.e.loper
15
@ dev.e.loper Sim, em Javascript, as funções são objetos de primeira classe, assim como strings e números. Isso significa que eles são definidos como variáveis ​​e podem ser passados ​​para outras funções, armazenados em matrizes e assim por diante.
Peter Olson
4
De forma alguma o corpo da função é "reescrito". Os vários padrões ECMAScript afirmam claramente que as declarações de variáveis ​​e funções são processadas antes do início da execução do código. Ou seja, nada é movido , é sobre a ordem de execução (daí minha aversão ao termo "içamento", que infere movimento ou rearranjo). Em seu código reescrito, a declaração var adeve vir antes da declaração da função e a atribuição a = 1deve 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.
RobG
3
@RobG Claro, acho que você poderia chamar a descrição de uma pequena "mentira para as crianças" , mas no final o comportamento é o mesmo, quer o código seja literalmente reorganizado ou apenas a ordem de execução seja reorganizada. O que realmente acontece nos bastidores é mais uma preocupação acadêmica e pode até depender da implementação.
Peter Olson
7
“Além disso, neste caso, se function a() {}comportou da mesma forma que var a = function () {};  - isso está incorreto de duas maneiras: primeiro, se alguma coisa, teria sido var a = function a() {};(a função na verdade não é anônima), segundo, essas duas formas não são intercambiáveis, porque de var a = function a() {};apenas a var a;parte teria sido içada. A a = 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.
user4642212
6

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....

function a() {} 

realmente se torna

var a = function () {}

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.

kemiller2002
fonte
5

A função aé içada dentro da função b:

var a = 1; 
function b() { 
   function a() {} 
   a = 10; 
   return;
} 
b(); 
alert(a);

o que é quase como usar var:

var a = 1; 
function b() { 
   var a = function () {};
   a = 10; 
   return;
} 
b(); 
alert(a);

A função é declarada localmente e a configuração asó acontece no escopo local, não no var global.

Avião Digital
fonte
1
esta linha "var a = function () {};" torna tudo claro .. basicamente JavaScript é uma linguagem dinâmica e "função" também é um objeto em JavaScript.
refatorar
3
  1. a declaração de função function a(){}é içada primeiro e se comporta como var a = function () {};, portanto, no escopo local aé criada.
  2. Se você tiver duas variáveis ​​com o mesmo nome (uma no global e outra no local), a variável local sempre terá precedência sobre a variável global.
  3. Ao definir a=10, você está definindo a variável local a, não a global.

Portanto, o valor da variável global permanece o mesmo e você obtém, alertado 1

Jhankar Mahbub
fonte
1

function a() { }é uma instrução de função, que cria uma avariável local para a bfunção.
As variáveis ​​são criadas quando uma função é analisada, independentemente de a varinstrução da função ou ser executada.

a = 10 define esta variável local.

SLaks
fonte
na verdade, a = 10define uma variável no escopo global quando a função bé executada, a menos que você adicione "use strict"(em ambientes como o suporte a essa diretiva).
Sean Vieira
@Sean: Não, porque a instrução da função cria um identificador local.
SLaks
... e .... você está certo. Não tinha percebido essa consequência particular do içamento de função. Obrigado!
Sean Vieira
1

Qual é o pomo da discórdia neste pequeno trecho de código?

Caso 1:

Inclua a function a(){}definição dentro do corpo do function bseguinte.logs value of a = 1

var a = 1;
function b() {
  a = 10;
  return;

  function a() {}
}
b();
console.log(a); // logs a = 1

Caso 2

Exclua a function a(){}definição dentro do corpo do function bseguinte.logs value of a = 10

var a = 1;
function b() {
  a = 10;  // overwrites the value of global 'var a'
  return;
}
b();
console.log(a); // logs 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

  1. var a foi definido e declarado lexicamente no escopo global.
  2. 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 propertyum é o mesmo que o variable a. O variable ainterior do function body btorna-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

var a = 1;
function b() {
  a = 10;
  return;

  function a() {}
}
b();
console.log(a); // logs a = 1

Ele é interpretado pelo interpretador JS da seguinte maneira.

var a = 1;
function b() {
  function a() {}
  a = 10;
  return;


}
b();
console.log(a); // logs a = 1

No entanto, quando removemos o function a(){} definition, o value of 'a'declarado e definido fora da função b, esse valor é sobrescrito e muda para 10 no caso 2. O valor é sobrescrito porque a=10se refere à declaração global e se fosse para ser declarado localmente, devemos ter escrito var a = 10;.

var a = 1;
function b() {
  var a = 10; // here var a is declared and defined locally because it uses a var keyword. 
  return;
}
b();
console.log(a); // logs a = 1

Podemos esclarecer nossas dúvidas ainda mais alterando o name propertyem function a(){} definitionpara algum outro nome que não'a'

var a = 1;
function b() {
  a = 10; // here var a is declared and defined locally because it uses a var keyword. 
  return;

  function foo() {}
}
b();
console.log(a); // logs a = 1
Sagar Munjal
fonte
1

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 aentão function be dentro desse bescopo, 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 aobterá o valor 1e o a dentro function bobterá 10. quando você fizer alert(a)isso, ele chamará a variável de escopo global real. Esta pequena mudança no código o tornará mais claro

        var a = 1;

    function b() {
        a = 10;
        return a;

        function a() { }
    }

    alert(b());
    alert(a);
Buzzzzzzz
fonte
1
É curioso que tantos especialistas em um curso da codeschool.com se refiram a içamento, que nada mais é do que uma visão simplista do que acontece, na verdade, içamento não acontece de forma alguma. Ref: 1) developer.mozilla.org/en-US/docs/Glossary/Hoisting 2) Capítulo 5 de Secrets of the JavaScript Ninja 2 / e por john resig, bear bebeault, josip maras
adnan2nd
1

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.

function a(){
  function b(){
    console.log(myVar);
  }

  var myVar = 2;
  b();
}

var myVar = 1;
a();
b();
> 2
> Uncaught ReferenceError: b is not defined

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.

function a(){
  function b(){
    console.log(myVar);
  }

  b();
}

var myVar = 1;
a();
> 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.

Donato
fonte
0

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.

AugustRush
fonte
0

Aqui está minha recapitulação da resposta com mais anotações e um violino acompanhante para brincar.

// hoisting_example.js

// top of scope ie. global var a = 1
var a = 1;

// new scope due to js' functional (not block) level scope
function b() {
    a = 10; // if the function 'a' didn't exist in this scope, global a = 10
  return; // the return illustrates that function 'a' is hoisted to top
  function a(){}; // 'a' will be hoisted to top as var a = function(){};
}

// exec 'b' and you would expect to see a = 10 in subsequent alert
// but the interpreter acutally 'hoisted' the function 'a' within 'b' 
// and in doing so, created a new named variable 'a' 
// which is a function within b's scope
b();

// a will alert 1, see comment above
alert(a);

https://jsfiddle.net/adjavaherian/fffpxjx7/

4m1r
fonte
0

escopo e fechamento e içamento (var / função)

  1. escopo: o var global pode ser acessado em qualquer lugar (todo o escopo do arquivo), var local somente pode ser acessado pelo escopo local (escopo de função / bloco)!
    Nota: se uma variável local não usar palavras-chave var em uma função, ela se tornará uma variável global!
  2. encerramento: uma função dentro da outra função, que pode acessar o escopo local (função pai) e o escopo global, embora seus vars não possam ser acessados ​​por outros! a menos que seu retorno como valor de retorno!
  3. içando: mova todos declare / undeclare vars / function para o topo do escopo, depois atribua o valor ou null!
    Nota: basta mover a declaração, não mover o valor!

var a = 1;                
//"a" is global scope
function b() {  
   var a = function () {}; 
   //"a" is local scope 
   var x = 12; 
   //"x" is local scope 
   a = 10;
   //global variable "a" was overwrited by the local variable "a"  
   console.log("local a =" + a);
   return console.log("local x = " + x);
}       
b();
// local a =10
// local x = 12
console.log("global a = " + a);
// global a = 1
console.log("can't access local x = \n");
// can't access local x = 
console.log(x);
// ReferenceError: x is not defined

xgqfrms
fonte
0

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.

Vishwas SL
fonte
0

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 ().

insira a descrição da imagem aqui

É 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.

Sumit Pahuja
fonte
0

Postagem longa!

Mas vai limpar o ar!

A forma como o Java Script funciona envolve um processo de duas etapas:

  1. 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 atribuir 3a xno caso de var x =3;que nada mais seja do que a avaliação da parte RHS.)

  2. Intérprete: Esta é a parte de execução / avaliação.

Verifique o resultado do código abaixo para entender:

//b() can be called here!
//c() cannot be called.
console.log("a is " + a);
console.log("b is " + b);
console.log("c is " + c);
var a = 1;
console.log("Now, a is " + a);
var c = function() {};
console.log("Now c is " + c);

function b() {
  //cannot write the below line:
  //console.log(e); 
  //since e is not declared.
  e = 10; //Java script interpreter after traversing from this function scope chain to global scope, is unable to find this variable and eventually initialises it with value 10 in global scope.
  console.log("e is " + e) //  works!
  console.log("f is " + f);
  var f = 7;
  console.log("Now f is " + f);
  console.log("d is " + d);
  return;

  function d() {}
}
b();
console.log(a);

Vamos quebrar:

  1. 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. Dentro bdo escopo de, ' f' seria registrada como uma variável que estaria indefinida neste momento e a função ' d' seria registrada.

  2. 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:

console.log(e)
e = 3;

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:

var a = 1;
console.log("a is " + a);

function b() {
  console.log("a inside the function b is " + a); //interpreter finds                                'a' as function() in current scope. No need to go outside the scope to find 'a'.
  a = 3; //a changed
  console.log("Now a is " + a);
  return;

  function a() {}
}
var a; //treated as duplicate and ignored.
b();
console.log("a is still " + a + " in global scope"); //This is global scope a.

pragun
fonte
0

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.

 a = 5; // Assign 5 to a
 elem = document.getElementById("demo"); // Find an element 
 elem.innerHTML = a;                     // Display a in the element
 var a; // Declare a
  //output-> 5

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.

 var a = 5; // Assign and declare 5 to a
 elem = document.getElementById("demo"); // Find an element 
 elem.innerHTML = a;                     // Display a in the element
  // output -> 5

considere outro exemplo.

  function foo() {
     console.log(x)
     var x = 1;
 }

é realmente interpretado assim:

  function foo() {
     var x;
     console.log(x)
     x = 1;
  }

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.

  function foo() {
     if (false) {
         var a = 1;
     }
     return;
     var b = 1;
  }

Essa função acaba sendo assim.

  function foo() {
      var a, b;
      if (false) {
        a = 1;
     }
     return;
     b = 1;
  }

Na declaração de variável, apenas a definição de variável eleva, não a atribuição.

  1. Içamento de declaração de funçã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

 function demo() {
     foo(); // this will give error because it is variable hoisting
     bar(); // "this will run!" as it is function hoisting
     var foo = function () {
         alert("this would not run!!");
     }
     function bar() { 
         alert("this will run!!");
     }
 }
 demo();

Agora que entendemos tanto o levantamento de variável quanto de função, vamos entender este código agora.

var a = 1;
function b() {
  a = 10;
  return;
   function a() {}
}
b();
alert(a);

Este código será assim.

var a = 1;                 //defines "a" in global scope
 function b() {  
   var a = function () {}; //defines "a" in local scope 
    a = 10;                 //overwrites local variable "a"
    return;      
 }       
 b();       
 alert(a); 

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 () .

Mustkeem K
fonte
0

Pelo que sei, o içamento acontece com a declaração da variável e a declaração da função, por exemplo:

a = 7;
var a;
console.log(a) 

O que acontece dentro do motor do JavaScript:

var a;
a = 7;
console.log(a);
// 7

Ou:

console.log(square(7)); // Output: 49
function square(n) { return n * n; }

Vai se tornar:

function square(n) { return n * n; }
console.log(square(7)); // 49

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:

console.log(x);
var x = 7; // undefined

Pode ficar assim:

var x;
console.log(x); // undefined
x = 7;
Nam V. Do
fonte
0

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.

insira a descrição da imagem aqui

Presumo que você seja um iniciante, para entender o içamento de maneira adequada, primeiro entendemos a diferença entre undefined e ReferenceError

 var v;
 console.log(v);
 console.log(abc);
/*
The output of the above codes are:
undefined
ReferenceError: abc is not defined*/

agora no código abaixo o que vemos? uma variável e uma expressão de função são excluídas.

<script>
var totalAmo = 8;
var getSum = function(a, b){
      return a+b;
}
</script>

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:

console.log(totalAmo);
console.log(getSum(8,9));
var totalAmo = 8;
var getSum = function(a, b){
      return a+b;
}
console.log(totalAmo);
console.log(getSum(9,7));

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

 <script>
        var totalAmo;
        var getSum;

        console.log(totalAmo);
        console.log(getSum(8,9));
        var totalAmo = 8;
        var getSum = function(a, b){
            return a+b;
        }
        console.log(totalAmo);
        console.log(getSum(9,7));
    </script>

Mas para a declaração de funções funções inteiras içadas no topo de seu escopo.

console.log(getId());
function getId(){
   return 739373;
}
/* output: 739373, because the whole function hoisted on the top of the scope.*/

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 ;

function functionScope(){
            var totalAmo;
            var getSum;

            console.log(totalAmo);
            console.log(getSum(8,9));
            var totalAmo = 8;
            var getSum = function(a, b){
                return a+b;
            }
        }

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.

 function getTotal(){
            let total=0;
            for(var i = 0; i<10; i++){
                let valueToAdd = i;
                var multiplier = 2;
                total += valueToAdd*multiplier;
            }
            return total;
        }

Variáveis ​​no exemplo abobe serão içadas como abaixo

 function getTotal(){
            let total;
            var multiplier;
            total = 0;
            for(var i = 0; i<10; i++){
                let valueToAdd;
                valueToAdd = i;
                multiplier = 2;
                total += valueToAdd*multiplier;
            }
            return total;
        }
senhor
fonte
0

ES5: função de içamento e içamento variável

function hoistinga prioridade é greaterquevariable hoisting

"use strict";

/**
 *
 * @author xgqfrms
 * @license MIT
 * @copyright xgqfrms
 * @created 2016-06-01
 * @modified
 *
 * @description function-hoisting.js
 * @augments
 * @example
 * @link
 *
 */

(function() {
  const log = console.log;

  var a = 1;
  function b() {
    a = 10;
    log(`local a`, a)
    return;
    // function hoisting priority is greater than variable hoisting
    function a() {}
  }
  b();
  log(`global a`, a);
  // local a 10
  // global a 1
})();


que é igual a

(function() {
  const log = console.log;

  // define "a" in global scope
  var a = 1;
  function b() {
    // define "a" in local scope
    var a ;
    // assign function to a
    a = function () {};
    // overwrites local variable "a"
    a = 10;
    log(`local a`, a);
    return;
  }

  b();
  // log global variable "a"
  log(`global a`, a);

  // local a 10
  // global a 1
})();

a razão por trás do içamento

var a = 1;                
//"a" is global scope
function b() {  
   var a = function () {}; 
   //"a" is local scope 
   var x = 12; 
   //"x" is local scope 
   a = 10;
   //global variable "a" was overwrited by the local variable "a"  
   console.log("local a =" + a);
   return console.log("local x = " + x);
}       
b();
// local a =10
// local x = 12
console.log("global a = " + a);
// global a = 1
console.log("can't access local x = \n");
// can't access local x = 
console.log(x);
// ReferenceError: x is not defined

/**
 *  scpope & closure & hoisting (var/function)
 *  
 * 1. scpope : the global var can be access in any place(the whole file scope), local var only can be accessed by the local scope(function/block scope)!
 * Note: if a local variable not using var keywords in a function, it will become a global variable!
 * 
 * 2. closure : a function inner the other function, which can access local scope(parent function) & global scope, howerver it's vars can't be accessed by others! unless, your return it as return value!
 * 
 * 3. hoisting : move all declare/undeclare vars/function to the scope top, than assign the value or null!
 * Note: it just move the declare, not move the value!
 * 
 */

ES6 let, constnão existe içamento

(() => {
  const log = console.log;
  log(a)
  // Error: Uncaught ReferenceError: Cannot access 'a' before initialization
  let a = 1;
})();


(() => {
  const log = console.log;
  log(b)
  // Error: Uncaught ReferenceError: Cannot access 'b' before initialization
  const b = 1;
})();

refs

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

xgqfrms
fonte