Qual é a diferença entre usar "let" e "var"?

4544

O ECMAScript 6 apresentou a letdeclaração .

Ouvi dizer que é descrita como uma variável "local", mas ainda não tenho certeza de como ela se comporta de maneira diferente da varpalavra - chave.

Quais são as diferenças? Quando deve letser usado var?

TM.
fonte
105
O ECMAScript é o padrão e letestá incluído no rascunho da 6ª edição e provavelmente estará na especificação final.
Richard Ayotte 31/03
5
Consulte kangax.github.io/es5-compat-table/es6 para obter uma matriz de suporte atualizada dos recursos do ES6 (incluindo let). No momento da redação do Firefox, o Chrome e o IE11 todos o suportam (embora eu acredite que a implementação do FF não seja muito padrão).
Nico Burns
22
Durante muito tempo, eu não sabia que os vars em um loop for tinham o escopo definido para a função em que estavam envolvidos. Lembro-me de descobrir isso pela primeira vez e achei muito estúpido. Eu vejo algum poder, sabendo agora como os dois podem ser usados ​​por motivos diferentes e como, em alguns casos, você pode realmente querer usar um var em um loop for e não tê-lo no escopo do bloco.
Eric Bishard
1
Esta é uma leitura muito boa wesbos.com/javascript-scoping
onmyway133
1
Resposta bem explicada aqui stackoverflow.com/a/43994458/5043867
Pardeep Jain

Respostas:

6101

Regras de escopo

A principal diferença está nas regras de escopo. As variáveis ​​declaradas por varpalavra-chave têm o escopo definido para o corpo da função imediata (daí o escopo da função) enquanto as letvariáveis ​​têm o escopo definido para o bloco envolvente imediato indicado por { }(daí o escopo do bloco).

function run() {
  var foo = "Foo";
  let bar = "Bar";

  console.log(foo, bar);

  {
    let baz = "Bazz";
    console.log(baz);
  }

  console.log(baz); // ReferenceError
}

run();

A razão pela qual a letpalavra-chave foi introduzida na linguagem foi o escopo da função é confuso e foi uma das principais fontes de erros no JavaScript.

Dê uma olhada neste exemplo de outra pergunta do stackoverflow :

var funcs = [];
// let's create 3 functions
for (var i = 0; i < 3; i++) {
  // and store them in funcs
  funcs[i] = function() {
    // each should log its value.
    console.log("My value: " + i);
  };
}
for (var j = 0; j < 3; j++) {
  // and now let's run each one to see
  funcs[j]();
}

My value: 3foi emitido para o console toda vez que funcs[j]();foi chamado, pois funções anônimas estavam ligadas à mesma variável.

As pessoas tinham que criar funções imediatamente invocadas para capturar o valor correto dos loops, mas isso também era complicado.

Elevação

Enquanto as variáveis ​​declaradas com a varpalavra - chave são hasteadas (inicializadas com undefinedantes da execução do código), isso significa que elas são acessíveis em seu escopo incluso antes mesmo de serem declaradas:

function run() {
  console.log(foo); // undefined
  var foo = "Foo";
  console.log(foo); // Foo
}

run();

letvariáveis ​​não são inicializadas até que sua definição seja avaliada. Acessá-los antes da inicialização resulta em a ReferenceError. Variável que se diz estar na "zona morta temporal" desde o início do bloco até a inicialização ser processada.

function checkHoisting() {
  console.log(foo); // ReferenceError
  let foo = "Foo";
  console.log(foo); // Foo
}

checkHoisting();

Criando propriedade de objeto global

No nível superior let, ao contrário var, não cria uma propriedade no objeto global:

var foo = "Foo";  // globally scoped
let bar = "Bar"; // globally scoped

console.log(window.foo); // Foo
console.log(window.bar); // undefined

Redeclaração

No modo estrito, varvocê poderá declarar novamente a mesma variável no mesmo escopo enquanto letgera um SyntaxError.

'use strict';
var foo = "foo1";
var foo = "foo2"; // No problem, 'foo' is replaced.

let bar = "bar1";
let bar = "bar2"; // SyntaxError: Identifier 'bar' has already been declared
ThinkingStiff
fonte
23
Lembre-se de que você pode criar um bloco quando quiser. function () {código; {letBloco = 5; código; };
média, Joe
177
Então, o objetivo das instruções let é apenas liberar memória quando não é necessário em um determinado bloco?
NoBugs
219
@NoBugs, Sim, e é recomendável que as variáveis ​​existam apenas onde forem necessárias.
batman
67
leta expressão de bloco let (variable declaration) statementnão é padrão e será removida no futuro, bugzilla.mozilla.org/show_bug.cgi?id=1023609 .
Gajus
19
Portanto, não consigo pensar em nenhum caso em que o uso de var seja útil. Alguém poderia me dar um exemplo de uma situação em que é preferível usar var?
Luis Sieira
622

lettambém pode ser usado para evitar problemas com fechamentos. Ele vincula um novo valor ao invés de manter uma referência antiga, como mostrado nos exemplos abaixo.

for(var i=1; i<6; i++) {
  $("#div" + i).click(function () { console.log(i); });
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<p>Clicking on each number will log to console:</p> 
<div id="div1">1</div>
<div id="div2">2</div>
<div id="div3">3</div>
<div id="div4">4</div>
<div id="div5">5</div>

O código acima demonstra um problema clássico de fechamento do JavaScript. Referência aoi variável está sendo armazenada no fechamento do manipulador de cliques, em vez do valor real de i.

Cada manipulador de cliques se refere ao mesmo objeto, porque há apenas um contador que contém 6, para que você obtenha seis em cada clique.

Uma solução geral é agrupar isso em uma função anônima e passar icomo argumento. Essas questões também podem ser evitados agora usando letem vez varcomo mostrado no código abaixo.

(Testado no Chrome e Firefox 50)

for(let i=1; i<6; i++) {
  $("#div" + i).click(function () { console.log(i); });
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<p>Clicking on each number will log to console:</p> 
<div id="div1">1</div>
<div id="div2">2</div>
<div id="div3">3</div>
<div id="div4">4</div>
<div id="div5">5</div>

Gurpreet Singh
fonte
54
Isso é realmente legal. Eu esperaria que "i" seja definido fora do corpo do loop entre colchetes e NÃO forme um "fechamento" em torno de "i". É claro que seu exemplo prova o contrário. Eu acho que é um pouco confuso do ponto de vista da sintaxe, mas esse cenário é tão comum que faz sentido apoiá-lo dessa maneira. Muito obrigado por trazer isso à tona.
Karol Kolenda
9
O IE 11 suporta let, mas alerta "6" para todos os botões. Você tem alguma fonte dizendo como letdeve se comportar?
Jim Hunziker
10
Parece que sua resposta está com o comportamento correto: developer.mozilla.org/pt-BR/docs/Web/JavaScript/Reference/…
Jim Hunziker
11
Na verdade, esta é uma armadilha comum em Javascript e agora posso ver por letque seria realmente útil. A configuração de listeners de eventos em um loop não requer mais uma expressão de função imediatamente chamada para escopo local iem cada iteração.
Adrian Moisa
19
O uso de "let" apenas adia esse problema. Portanto, cada iteração cria um escopo de bloco independente privado, mas a variável "i" ainda pode ser corrompida por alterações subseqüentes dentro do bloco (desde que a variável iteradora não seja alterada normalmente dentro do bloco, mas outras variáveis ​​declaradas no bloco podem muito bem ser) e qualquer função declarada dentro da lata bloco, quando invocado, corromper o valor de "i" para outras funções declaradas dentro do bloco, porque eles fazem compartilham o mesmo escopo de bloco privado, portanto, a mesma referência ao "i".
Gary
199

Qual é a diferença entre lete var?

  • Uma variável definida usando uma varinstrução é conhecida em toda a função em que é definida, desde o início da função. (*)
  • Uma variável definida usando uma letinstrução é conhecida apenas no bloco em que é definida, a partir do momento em que é definida em diante. (**)

Para entender a diferença, considere o seguinte código:

// i IS NOT known here
// j IS NOT known here
// k IS known here, but undefined
// l IS NOT known here

function loop(arr) {
    // i IS known here, but undefined
    // j IS NOT known here
    // k IS known here, but has a value only the second time loop is called
    // l IS NOT known here

    for( var i = 0; i < arr.length; i++ ) {
        // i IS known here, and has a value
        // j IS NOT known here
        // k IS known here, but has a value only the second time loop is called
        // l IS NOT known here
    };

    // i IS known here, and has a value
    // j IS NOT known here
    // k IS known here, but has a value only the second time loop is called
    // l IS NOT known here

    for( let j = 0; j < arr.length; j++ ) {
        // i IS known here, and has a value
        // j IS known here, and has a value
        // k IS known here, but has a value only the second time loop is called
        // l IS NOT known here
    };

    // i IS known here, and has a value
    // j IS NOT known here
    // k IS known here, but has a value only the second time loop is called
    // l IS NOT known here
}

loop([1,2,3,4]);

for( var k = 0; k < arr.length; k++ ) {
    // i IS NOT known here
    // j IS NOT known here
    // k IS known here, and has a value
    // l IS NOT known here
};

for( let l = 0; l < arr.length; l++ ) {
    // i IS NOT known here
    // j IS NOT known here
    // k IS known here, and has a value
    // l IS known here, and has a value
};

loop([1,2,3,4]);

// i IS NOT known here
// j IS NOT known here
// k IS known here, and has a value
// l IS NOT known here

Aqui, podemos ver que nossa variável jé conhecida apenas no primeiro loop for, mas não antes e depois. No entanto, nossa variável ié conhecida em toda a função.

Além disso, considere que as variáveis ​​com escopo de bloco não são conhecidas antes de serem declaradas porque não são içadas. Também não é permitido redefinir a mesma variável com escopo de bloco dentro do mesmo bloco. Isso torna as variáveis ​​com escopo do bloco menos propensas a erros do que as variáveis ​​com escopo global ou funcional, que são içadas e que não produzem erros no caso de várias declarações.


É seguro usar lethoje?

Algumas pessoas argumentam que, no futuro, usaremos SOMENTE declarações let e essas declarações var se tornarão obsoletas. O guru do JavaScript Kyle Simpson escreveu um artigo muito elaborado sobre por que ele acredita que não será esse o caso .

Hoje, no entanto, esse definitivamente não é o caso. De fato, precisamos nos perguntar se é seguro usar a letdeclaração. A resposta para essa pergunta depende do seu ambiente:

  • Se você estiver escrevendo o código JavaScript do servidor ( Node.js ), poderá usar a letinstrução com segurança .

  • Se você estiver escrevendo código JavaScript do lado do cliente e usar um transpiler baseado em navegador (como Traceur ou babel-standalone ), poderá usar a letinstrução com segurança , no entanto, é provável que seu código seja qualquer coisa, menos ideal em relação ao desempenho.

  • Se você estiver escrevendo código JavaScript do lado do cliente e usar um transpiler baseado em Nó (como o script shell de rastreamento ou Babel ), poderá usar a letinstrução com segurança . E como o seu navegador só conhece o código transpilado, as desvantagens do desempenho devem ser limitadas.

  • Se você estiver escrevendo um código JavaScript do lado do cliente e não usa um transpiler, considere o suporte ao navegador.

    Ainda existem alguns navegadores que não oferecem suporte let:

insira a descrição da imagem aqui


Como acompanhar o suporte ao navegador

Para uma visão geral atualizada de quais navegadores suportam a letdeclaração no momento da leitura desta resposta, consulte esta Can I Usepágina .


(*) Variáveis ​​com escopo global e funcional podem ser inicializadas e usadas antes de serem declaradas porque as variáveis ​​JavaScript são hasteadas . Isso significa que as declarações sempre estão no topo do escopo.

(**) As variáveis ​​do escopo do bloco não são içadas

John Slegers
fonte
14
em relação à resposta v4: iÉ conhecido em todo o bloco de funções! Começa como undefined(devido à elevação) até você atribuir um valor! O ps: lettambém é içado (na parte superior do bloco que contém), mas fornece um ReferenceErrorquando referenciado no bloco antes da primeira atribuição. (ps2: Eu sou um tipo de ponto e vírgula, mas você realmente não precisa de ponto e vírgula depois de um bloco). Dito isto, obrigado por adicionar a verificação da realidade em relação ao suporte!
GitaarLAB
@GitaarLAB: De acordo com a Mozilla Developer Network : "No ECMAScript 2015, as ligações não estão sujeitas ao levantamento variável, o que significa que as declarações não se movem para o topo do atual contexto de execução". - De qualquer forma, fiz algumas melhorias na minha resposta que devem esclarecer a diferença no comportamento de içar entre lete var!
John Slegers
1
Sua resposta melhorou muito (verifiquei minuciosamente). Observe que o mesmo link que você referenciou no seu comentário também diz: "A variável (let) está em uma" zona morta temporal "desde o início do bloco até que a inicialização seja processada." Isso significa que o 'identificador' (a string de texto 'reservada' para apontar para 'algo') já está reservada no escopo relevante, caso contrário, ele se tornaria parte do escopo raiz / host / janela. Para mim, pessoalmente, 'içar' significa nada mais do que reservar / vincular 'identificadores' declarados ao seu escopo relevante; excluindo sua inicialização / atribuição / modificabilidade!
GitaarLAB
E .. + 1. Esse artigo de Kyle Simpson que você vinculou é uma excelente leitura, obrigado por isso! Também é claro sobre a "zona morta temporal", também conhecida como "TDZ". Uma coisa interessante que eu gostaria de acrescentar: Eu li sobre MDN que lete constforam recomendado para uso apenas quando você realmente precisa de sua funcionalidade adicional , porque aplicação / verificando esses recursos extras (como somente gravação const) resultam em 'mais trabalho '(e nós de escopo adicionais na árvore de escopo) para o (s) mecanismo (s) atual (is) para aplicar / verificar / verificar / configurar.
GitaarLAB
1
Observe que o MDN diz que o IE interpreta a permissão corretamente. Qual é? developer.mozilla.org/pt-BR/docs/Web/JavaScript/Reference/…
Katinka Hesselink 06/02/19
146

Aqui está uma explicação da letpalavra - chave com alguns exemplos.

letfunciona muito parecido var. A principal diferença é que o escopo de uma varvariável é toda a função envolvente

Esta tabela na Wikipedia mostra quais navegadores suportam Javascript 1.7.

Observe que apenas os navegadores Mozilla e Chrome são compatíveis. IE, Safari e potencialmente outros não.

Ben S
fonte
5
A parte principal do texto do documento vinculado parece ser "deixe funcionar muito parecido com var. A principal diferença é que o escopo de uma variável var é toda a função anexa".
22711 Michael Burr
50
Embora seja tecnicamente correto dizer que o IE não o suporta, é mais correto dizer que é uma extensão apenas do mozilla.
olliej
55
@olliej, na verdade a Mozilla está logo à frente do jogo. Veja a página 19 de ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf
Tyler Crompton
@TylerCrompton, esse é apenas o conjunto de palavras que estão reservadas há anos. Quando o mozilla adicionou, era apenas uma extensão do mozilla, sem especificações relacionadas. O ES6 deve definir o comportamento das instruções let, mas isso ocorreu depois que o mozilla introduziu a sintaxe. Lembre-se de que o moz também possui o E4X, que está totalmente morto e apenas o moz.
olliej
9
O IE11 adicionou suporte para let msdn.microsoft.com/en-us/library/ie/dn342892%28v=vs.85%29.aspx
eloyesp
112

A resposta aceita está faltando um ponto:

{
  let a = 123;
};

console.log(a); // ReferenceError: a is not defined
Lcf.vs
fonte
19
A resposta aceita NÃO explica esse ponto em seu exemplo. A resposta aceita apenas o demonstrou em um forinicializador de loop, estreitando drasticamente o escopo de aplicação das limitações de let. Votado.
Jon Davis
37
@ stimpy77 Indica explicitamente "let está no escopo do bloco anexo mais próximo"; é necessário incluir todas as formas de manifestação?
Dave Newton
6
havia muitos exemplos e nenhum deles demonstrou adequadamente o assunto. Eu poderia ter votado positivamente na resposta aceita e nesta?
Jon Davis
5
Essa contribuição demonstra que um "bloco" pode ser simplesmente um conjunto de linhas entre colchetes; ou seja, não precisa ser associado a nenhum tipo de fluxo de controle, loop, etc. #
webelo 22/11/17
81

let

Escopo do bloco

As variáveis ​​declaradas usando a letpalavra-chave têm escopo de bloco, o que significa que elas estão disponíveis apenas no bloco em que foram declaradas.

No nível superior (fora de uma função)

No nível superior, as variáveis ​​declaradas usando letnão criam propriedades no objeto global.

var globalVariable = 42;
let blockScopedVariable = 43;

console.log(globalVariable); // 42
console.log(blockScopedVariable); // 43

console.log(this.globalVariable); // 42
console.log(this.blockScopedVariable); // undefined

Dentro de uma função

Dentro de uma função (mas fora de um bloco), lettem o mesmo escopo que var.

(() => {
  var functionScopedVariable = 42;
  let blockScopedVariable = 43;

  console.log(functionScopedVariable); // 42
  console.log(blockScopedVariable); // 43
})();

console.log(functionScopedVariable); // ReferenceError: functionScopedVariable is not defined
console.log(blockScopedVariable); // ReferenceError: blockScopedVariable is not defined

Dentro de um bloco

Variáveis ​​declaradas usando letdentro de um bloco não podem ser acessadas fora desse bloco.

{
  var globalVariable = 42;
  let blockScopedVariable = 43;
  console.log(globalVariable); // 42
  console.log(blockScopedVariable); // 43
}

console.log(globalVariable); // 42
console.log(blockScopedVariable); // ReferenceError: blockScopedVariable is not defined

Dentro de um loop

Variáveis ​​declaradas com letloops podem ser referenciadas apenas dentro desse loop.

for (var i = 0; i < 3; i++) {
  var j = i * 2;
}
console.log(i); // 3
console.log(j); // 4

for (let k = 0; k < 3; k++) {
  let l = k * 2;
}
console.log(typeof k); // undefined
console.log(typeof l); // undefined
// Trying to do console.log(k) or console.log(l) here would throw a ReferenceError.

Loops com tampas

Se você usar em letvez de varem um loop, a cada iteração você obtém uma nova variável. Isso significa que você pode usar com segurança um fechamento dentro de um loop.

// Logs 3 thrice, not what we meant.
for (var i = 0; i < 3; i++) {
  setTimeout(() => console.log(i), 0);
}

// Logs 0, 1 and 2, as expected.
for (let j = 0; j < 3; j++) {
  setTimeout(() => console.log(j), 0);
}

Zona morta temporal

Por causa da zona morta temporal , as variáveis ​​declaradas usando letnão podem ser acessadas antes de serem declaradas. Tentar fazer isso gera um erro.

console.log(noTDZ); // undefined
var noTDZ = 43;
console.log(hasTDZ); // ReferenceError: hasTDZ is not defined
let hasTDZ = 42;

Sem declarar novamente

Você não pode declarar a mesma variável várias vezes usando let. Você também não pode declarar uma variável usando leto mesmo identificador que outra variável que foi declarada usando var.

var a;
var a; // Works fine.

let b;
let b; // SyntaxError: Identifier 'b' has already been declared

var c;
let c; // SyntaxError: Identifier 'c' has already been declared

const

consté bem parecido com leto escopo do bloco e possui TDZ. Existem, no entanto, duas coisas que são diferentes.

Sem reatribuição

A variável declarada usando constnão pode ser reatribuída.

const a = 42;
a = 43; // TypeError: Assignment to constant variable.

Observe que isso não significa que o valor seja imutável. Suas propriedades ainda podem ser alteradas.

const obj = {};
obj.a = 42;
console.log(obj.a); // 42

Se você deseja ter um objeto imutável, use Object.freeze().

O inicializador é necessário

Você sempre deve especificar um valor ao declarar uma variável usando const.

const a; // SyntaxError: Missing initializer in const declaration
Michał Perłakowski
fonte
51

Aqui está um exemplo da diferença entre os dois (o suporte foi iniciado para o chrome):
insira a descrição da imagem aqui

Como você pode ver, a var jvariável ainda está tendo um valor fora do escopo do loop for (escopo do bloco), mas a let ivariável é indefinida fora do escopo do loop for.

"use strict";
console.log("var:");
for (var j = 0; j < 2; j++) {
  console.log(j);
}

console.log(j);

console.log("let:");
for (let i = 0; i < 2; i++) {
  console.log(i);
}

console.log(i);

vlio20
fonte
2
Que ferramenta eu estou vendo aqui?
Barton
20
Chrome devtools
vlio20
Como desenvolvedor de applets de mesa para o Cinnamon, não fui exposto a essas ferramentas brilhantes.
Barton
48

Existem algumas diferenças sutis - o letescopo se comporta mais como o escopo variável em mais ou menos qualquer outro idioma.

por exemplo, ele escopo para o bloco anexo, eles não existem antes de serem declarados, etc.

No entanto, vale a pena notar que isso leté apenas uma parte das implementações mais recentes do Javascript e tem vários graus de suporte ao navegador .

olliej
fonte
11
Também é importante notar que o ECMAScript é o padrão e letestá incluído no rascunho da 6ª edição e provavelmente estará na especificação final.
Richard Ayotte 31/03
23
Essa é a diferença 3 anos marcas: D
olliej
4
Acabei de publicar essa questão e, em 2012, ainda é o caso que apenas os navegadores Mozilla suportam let. Safari, IE e Chome, todos não.
Pseudosavant
2
A idéia de criar acidentalmente o escopo parcial do bloco em caso de acidente é um bom ponto, cuidado, letnão aumenta, para usar uma variável definida por uma letdefinida na parte superior do seu bloco. Se você tiver uma ifinstrução que seja mais do que apenas algumas linhas de código, poderá esquecer que não poderá usar essa variável até que ela seja definida. GRANDE PONTO !!!
Eric Bishard
2
@EricB: yes e no: "No ECMAScript 2015, let elevará a variável ao topo do bloco. No entanto, referenciar a variável no bloco antes da declaração da variável resulta em um ReferenceError (minha nota: em vez de boa e velha undefined). A variável está em uma 'zona morta temporal' desde o início do bloco até a declaração ser processada. " O mesmo vale para "instruções de opção porque há apenas um bloco subjacente". Fonte: developer.mozilla.org/pt-BR/docs/Web/JavaScript/Reference/…
GitaarLAB
29

A principal diferença é a diferença de escopo , enquanto let só pode estar disponível dentro do escopo declarado, como no loop for, var pode ser acessado fora do loop, por exemplo. Na documentação do MDN (exemplos também do MDN):

let permite declarar variáveis que são limitados em escopo para o bloco, declaração ou expressão em que ela é usada. Isso é diferente da palavra-chave var , que define uma variável globalmente ou localmente para uma função inteira, independentemente do escopo do bloco.

As variáveis ​​declaradas por let têm como escopo o bloco em que são definidas, bem como em qualquer sub-bloco contido. Dessa forma, vamos funcionar como var . A principal diferença é que o escopo de uma variável var é toda a função envolvente:

function varTest() {
  var x = 1;
  if (true) {
    var x = 2;  // same variable!
    console.log(x);  // 2
  }
  console.log(x);  // 2
}

function letTest() {
  let x = 1;
  if (true) {
    let x = 2;  // different variable
    console.log(x);  // 2
  }
  console.log(x);  // 1
}`

No nível superior de programas e funções, deixe , ao contrário de var , não criar uma propriedade no objeto global. Por exemplo:

var x = 'global';
let y = 'global';
console.log(this.x); // "global"
console.log(this.y); // undefined

Quando usado dentro de um bloco, vamos limitar o escopo da variável a esse bloco. Observe a diferença entre var cujo escopo está dentro da função em que é declarado.

var a = 1;
var b = 2;

if (a === 1) {
  var a = 11; // the scope is global
  let b = 22; // the scope is inside the if-block

  console.log(a);  // 11
  console.log(b);  // 22
} 

console.log(a); // 11
console.log(b); // 2

Além disso, não se esqueça do seu recurso ECMA6, por isso ainda não é totalmente suportado, por isso é melhor sempre transpilar para o ECMA5 usando Babel etc ... para obter mais informações sobre a visita ao site da babel

Alireza
fonte
24
  • Variável não içada

    letvai não guincho para todo o escopo do bloco são apresentados. Por outro lado, varpoderia içar como abaixo.

    {
       console.log(cc); // undefined. Caused by hoisting
       var cc = 23;
    }
    
    {
       console.log(bb); // ReferenceError: bb is not defined
       let bb = 23;
    }

    Na verdade, Per @Bergi, Both vare letsão içadas .

  • Coleta de lixo

    O escopo do bloco leté útil refere-se a fechamentos e coleta de lixo para recuperar a memória. Considerar,

    function process(data) {
        //...
    }
    
    var hugeData = { .. };
    
    process(hugeData);
    
    var btn = document.getElementById("mybutton");
    btn.addEventListener( "click", function click(evt){
        //....
    });

    O clickretorno de chamada do manipulador não precisa da hugeDatavariável. Teoricamente, após as process(..)execuções, a enorme estrutura de dados hugeDatapode ser coletada como lixo. No entanto, é possível que algum mecanismo JS ainda tenha que manter essa estrutura enorme, pois oclick função tem um fechamento em todo o escopo.

    No entanto, o escopo do bloco pode transformar essa enorme estrutura de dados em lixo coletado.

    function process(data) {
        //...
    }
    
    { // anything declared inside this block can be garbage collected
        let hugeData = { .. };
        process(hugeData);
    }
    
    var btn = document.getElementById("mybutton");
    btn.addEventListener( "click", function click(evt){
        //....
    });
  • let rotações

    letno loop pode vinculá-lo novamente a cada iteração do loop, certificando-se de atribuir novamente o valor a partir do final da iteração anterior do loop. Considerar,

    // print '5' 5 times
    for (var i = 0; i < 5; ++i) {
        setTimeout(function () {
            console.log(i);
        }, 1000);  
    }

    No entanto, substitua varporlet

    // print 1, 2, 3, 4, 5. now
    for (let i = 0; i < 5; ++i) {
        setTimeout(function () {
            console.log(i);
        }, 1000);  
    }

    Como letcrie um novo ambiente lexical com esses nomes para a) a expressão inicializadora b) cada iteração (antes de avaliar a expressão de incremento), mais detalhes estão aqui .

zangw
fonte
4
Sim, eles são içados, mas se comportam como se não fossem içados por causa da Zona Morta Temporal (do rolo de tambor) - um nome muito dramático para um identificador que não está acessível até que seja declarado :-)
Drenai
Então, deixe é içada, mas indisponível? Como isso é diferente de 'não içado'?
N-ate
Espero que Brian ou Bergi voltem para responder a isso. A declaração de let é içada, mas não a atribuição? Obrigado!
N-ate
1
@ N-ate, aqui está um post de Bergi, talvez você possa encontrar respostas nele.
zangw
É interessante que até é chamado de içamento quando se trata de locação. Entendo que tecnicamente o mecanismo de análise está pré-capturando-o, mas para todos os efeitos, um programador deve tratá-lo como se ele não existisse. A elevação de var, por outro lado, tem implicações para um programador.
N-ate
19

Aqui está um exemplo para adicionar ao que outros já escreveram. Suponha que você queira criar uma matriz de funções, em adderFunctionsque cada função use um único argumento Number e retorne a soma do argumento e o índice da função na matriz. Tentar gerar adderFunctionscom um loop usando a varpalavra - chave não funcionará da maneira que alguém poderia esperar:

// An array of adder functions.
var adderFunctions = [];

for (var i = 0; i < 1000; i++) {
  // We want the function at index i to add the index to its argument.
  adderFunctions[i] = function(x) {
    // What is i bound to here?
    return x + i;
  };
}

var add12 = adderFunctions[12];

// Uh oh. The function is bound to i in the outer scope, which is currently 1000.
console.log(add12(8) === 20); // => false
console.log(add12(8) === 1008); // => true
console.log(i); // => 1000

// It gets worse.
i = -8;
console.log(add12(8) === 0); // => true

O processo acima não gera a matriz de funções desejada porque io escopo se estende além da iteração do forbloco no qual cada função foi criada. Em vez disso, no final do loop, o ifechamento de cada função refere-se ao ivalor de no final do loop (1000) para cada função anônima em adderFunctions. Não é isso que queríamos: agora temos uma matriz de 1000 funções diferentes na memória com exatamente o mesmo comportamento. E se atualizarmos posteriormente o valor de i, a mutação afetará todos osadderFunctions .

No entanto, podemos tentar novamente usando a letpalavra-chave:

// Let's try this again.
// NOTE: We're using another ES6 keyword, const, for values that won't
// be reassigned. const and let have similar scoping behavior.
const adderFunctions = [];

for (let i = 0; i < 1000; i++) {
  // NOTE: We're using the newer arrow function syntax this time, but 
  // using the "function(x) { ..." syntax from the previous example 
  // here would not change the behavior shown.
  adderFunctions[i] = x => x + i;
}

const add12 = adderFunctions[12];

// Yay! The behavior is as expected. 
console.log(add12(8) === 20); // => true

// i's scope doesn't extend outside the for loop.
console.log(i); // => ReferenceError: i is not defined

Desta vez, ié recuperado em cada iteração do forloop. Cada função agora mantém o valor de ino momento da criação da função e adderFunctionsse comporta conforme o esperado.

Agora, a imagem combina os dois comportamentos e você provavelmente verá por que não é recomendável misturar o mais novo lete consto mais antigo varno mesmo script. Fazer isso pode resultar em um código espetacularmente confuso.

const doubleAdderFunctions = [];

for (var i = 0; i < 1000; i++) {
    const j = i;
    doubleAdderFunctions[i] = x => x + i + j;
}

const add18 = doubleAdderFunctions[9];
const add24 = doubleAdderFunctions[12];

// It's not fun debugging situations like this, especially when the
// code is more complex than in this example.
console.log(add18(24) === 42); // => false
console.log(add24(18) === 42); // => false
console.log(add18(24) === add24(18)); // => false
console.log(add18(24) === 2018); // => false
console.log(add24(18) === 2018); // => false
console.log(add18(24) === 1033); // => true
console.log(add24(18) === 1030); // => true

Não deixe isso acontecer com você. Use um linter.

NOTA: Este é um exemplo de ensino destinado a demonstrar o var/ letcomportamento em loops e com fechamentos de funções que também seriam fáceis de entender. Essa seria uma maneira terrível de adicionar números. Mas a técnica geral de capturar dados em fechamentos de funções anônimas pode ser encontrada no mundo real em outros contextos. YMMV.

abroz
fonte
2
@aborz: Também sintaxe de função anônima muito legal no segundo exemplo. É exatamente com o que estou acostumado em C #. Eu aprendi algo hoje.
Barton
Correção: Tecnicamente, a sintaxe da função Seta descrita aqui => developer.mozilla.org/pt-BR/docs/Web/JavaScript/Reference/…
Barton
3
Na verdade, você não precisa let value = i;. A forinstrução cria um bloco lexical.
Escova de dentes
17

A diferença está no escopo das variáveis ​​declaradas com cada uma.

Na prática, há várias consequências úteis da diferença de escopo:

  1. letvariáveis ​​são visíveis apenas no bloco envolvente mais próximo ( { ... }).
  2. letvariáveis ​​são utilizáveis ​​apenas em linhas de código que ocorrem após a declaração da variável (mesmo que sejam içadas !).
  3. letvariáveis ​​não podem ser redeclaradas por um subseqüente varou let.
  4. letVariáveis globais não são adicionadas ao windowobjeto global .
  5. letAs variáveis ​​são fáceis de usar nos fechamentos (elas não causam condições de corrida ).

As restrições impostas letreduzem a visibilidade das variáveis ​​e aumentam a probabilidade de colisões inesperadas de nomes serem encontradas com antecedência. Isso facilita o rastreamento e o raciocínio sobre as variáveis, incluindo sua acessibilidade (ajudando na recuperação de memória não utilizada).

Consequentemente, leté menos provável que as variáveis ​​causem problemas quando usadas em programas grandes ou quando estruturas desenvolvidas independentemente são combinadas de maneiras novas e inesperadas.

varainda pode ser útil se você tiver certeza de que deseja o efeito de ligação única ao usar um fechamento em um loop (nº 5) ou para declarar variáveis ​​globais visíveis externamente em seu código (nº 4). O uso de varpara exportações pode ser substituído se exportmigrar do espaço do transpiler para o idioma principal.

Exemplos

1. Não usar fora do bloco anexo mais próximo: Este bloco de código gerará um erro de referência porque o segundo uso de xocorre fora do bloco em que é declarado com let:

{
    let x = 1;
}
console.log(`x is ${x}`);  // ReferenceError during parsing: "x is not defined".

Por outro lado, o mesmo exemplo com var obras.

2. Sem uso antes da declaração:
Este bloco de código lançará um ReferenceErrorantes que o código possa ser executado porque xé usado antes de ser declarado:

{
    x = x + 1;  // ReferenceError during parsing: "x is not defined".
    let x;
    console.log(`x is ${x}`);  // Never runs.
}

Por outro lado, o mesmo exemplo varanalisa e é executado sem gerar nenhuma exceção.

3. Sem redeclaração: O código a seguir demonstra que uma variável declarada com letnão pode ser redeclarada posteriormente:

let x = 1;
let x = 2;  // SyntaxError: Identifier 'x' has already been declared

4. Globais não ligados a window:

var button = "I cause accidents because my name is too common.";
let link = "Though my name is common, I am harder to access from other JS files.";
console.log(link);  // OK
console.log(window.link);  // undefined (GOOD!)
console.log(window.button);  // OK

5. Fácil utilização com fechamentos: Variáveis ​​declaradas com varnão funcionam bem com fechamentos dentro de loops. Aqui está um loop simples que gera a sequência de valores que a variável ipossui em diferentes pontos no tempo:

for (let i = 0; i < 5; i++) {
    console.log(`i is ${i}`), 125/*ms*/);
}

Especificamente, isso gera:

i is 0
i is 1
i is 2
i is 3
i is 4

No JavaScript, geralmente usamos variáveis ​​em um período significativamente posterior ao quando elas são criadas. Quando demonstramos isso, adiando a saída com um fechamento passado para setTimeout:

for (let i = 0; i < 5; i++) {
    setTimeout(_ => console.log(`i is ${i}`), 125/*ms*/);
}

... a saída permanece inalterada enquanto permanecermos let. Por outro lado, se tivéssemos usado var i:

for (var i = 0; i < 5; i++) {
    setTimeout(_ => console.log(`i is ${i}`), 125/*ms*/);
}

... o loop gera inesperadamente "i is 5" cinco vezes:

i is 5
i is 5
i is 5
i is 5
i is 5
mormegil
fonte
5
# 5 não é causado por uma condição de corrida. Ao usar em varvez de let, o código é equivalente a: var i = 0; while (i < 5) { doSomethingLater(); i++; } iestá fora do fechamento e, no momento em que doSomethingLater()é executado, ijá foi incrementado 5 vezes, portanto, a saída é i is 5cinco vezes. Ao usar let, a variável iestá dentro do fechamento, portanto, cada chamada assíncrona obtém sua própria cópia, em ivez de usar a 'global' criada com ela var.
Daniel T.
@ Daniel: Eu não acho que a transformação de retirar a definição de variável do inicializador de loop explique alguma coisa. Essa é simplesmente a definição normal da semântica de for. Uma transformação mais precisa, embora mais complicada, é o clássico for (var i = 0; i < 5; i++) { (function(j) { setTimeout(_ => console.log(i é $ {j}, ), 125/*ms*/); })(i); }que introduz um "registro de ativação da função" para salvar cada valor icom o nome de jdentro da função.
Mormegil
14

Que as duas funções a seguir mostrem a diferença:

function varTest() {
    var x = 31;
    if (true) {
        var x = 71;  // Same variable!
        console.log(x);  // 71
    }
    console.log(x);  // 71
}

function letTest() {
    let x = 31;
    if (true) {
        let x = 71;  // Different variable
        console.log(x);  // 71
    }
    console.log(x);  // 31
}
Abdennour TOUMI
fonte
13

let é interessante, porque nos permite fazer algo assim:

(() => {
    var count = 0;

    for (let i = 0; i < 2; ++i) {
        for (let i = 0; i < 2; ++i) {
            for (let i = 0; i < 2; ++i) {
                console.log(count++);
            }
        }
    }
})();

O que resulta na contagem de [0, 7].

Enquanto que

(() => {
    var count = 0;

    for (var i = 0; i < 2; ++i) {
        for (var i = 0; i < 2; ++i) {
            for (var i = 0; i < 2; ++i) {
                console.log(count++);
            }
        }
    }
})();

Conta apenas [0, 1].

Dmitry
fonte
2
esta é a primeira vez que eu vi alguém agir como sombreamento variável era desejável. não, o propósito de deixar não é para permitir o sombreamento
John Haugeland
1
objetivo? é uma construção, você pode usá-lo como quiser, uma das maneiras interessantes é assim.
Dmitry
13

Função VS escopo do bloco:

A principal diferença entre vare leté que as variáveis ​​declaradas com vartêm escopo de função . Enquanto as funções declaradas com lettêm escopo de bloco . Por exemplo:

function testVar () {
  if(true) {
    var foo = 'foo';
  }

  console.log(foo);
}

testVar();  
// logs 'foo'


function testLet () {
  if(true) {
    let bar = 'bar';
  }

  console.log(bar);
}

testLet(); 
// reference error
// bar is scoped to the block of the if statement 

variáveis ​​com var :

Quando a primeira função testVaré chamada, a variável foo, declarada com var, ainda está acessível fora da ifinstrução. Essa variável fooestaria disponível em qualquer lugar dentro do escopo da testVar função .

variáveis ​​com let :

Quando a segunda função testLeté chamada de variável bar, declarada com let, só é acessível dentro da ifinstrução. Como as variáveis com declarado letsão bloco escopo (onde um bloco é o código entre chavetas, por exemplo if{}, for{}, function{}).

let variáveis ​​não são içadas:

Outra diferença entre vare leté as variáveis ​​declaradas com let não são içadas . Um exemplo é a melhor maneira de ilustrar esse comportamento:

variáveis ​​com let não são içadas:

console.log(letVar);

let letVar = 10;
// referenceError, the variable doesn't get hoisted

variáveis com var afazeres get içada:

console.log(varVar);

var varVar = 10;
// logs undefined, the variable gets hoisted

Global letnão se apega a window:

Uma variável declarada com letno escopo global (que é um código que não está em uma função) não é adicionada como uma propriedade no windowobjeto global . Por exemplo (este código está no escopo global):

var bar = 5;
let foo  = 10;

console.log(bar); // logs 5
console.log(foo); // logs 10

console.log(window.bar);  
// logs 5, variable added to window object

console.log(window.foo);
// logs undefined, variable not added to window object


Quando deve letser usado var?

Use letmais varsempre que você pode, porque é simplesmente escopo mais específico. Isso reduz possíveis conflitos de nomes que podem ocorrer ao lidar com um grande número de variáveis. varpode ser usado quando você deseja que uma variável global esteja explicitamente no windowobjeto (sempre considere com cuidado se isso é realmente necessário).

Willem van der Veen
fonte
9

Parece também que, pelo menos no Visual Studio 2015, o TypeScript 1.5, "var" permite várias declarações com o mesmo nome de variável em um bloco e "let" não.

Isso não gerará um erro de compilação:

var x = 1;
var x = 2;

Isso vai:

let x = 1;
let x = 2;
RDoc
fonte
9

var é uma variável de escopo global (passível de elevação).

lete consté escopo de bloco.

test.js

{
    let l = 'let';
    const c = 'const';
    var v = 'var';
    v2 = 'var 2';
}

console.log(v, this.v);
console.log(v2, this.v2);
console.log(l); // ReferenceError: l is not defined
console.log(c); // ReferenceError: c is not defined

Shahsavan muçulmano
fonte
8

Ao usar let

A letpalavra-chave anexa a declaração da variável ao escopo de qualquer bloco (geralmente um { .. }par) em que está contido. Em outras palavras, letseqüestra implicitamente o escopo de qualquer bloco para sua declaração de variável.

letvariáveis ​​não podem ser acessadas no windowobjeto porque não podem ser acessadas globalmente.

function a(){
    { // this is the Max Scope for let variable
        let x = 12;
    }
    console.log(x);
}
a(); // Uncaught ReferenceError: x is not defined

Ao usar var

var e as variáveis ​​no ES5 têm escopos em funções, o que significa que as variáveis ​​são válidas dentro da função e não fora da própria função.

varvariáveis ​​podem ser acessadas no windowobjeto porque não podem ser acessadas globalmente.

function a(){ // this is the Max Scope for var variable
    { 
        var x = 12;
    }
    console.log(x);
}
a(); // 12

Se você quiser saber mais, continue lendo abaixo

uma das perguntas de entrevista mais famosas sobre o escopo também pode ser suficiente para o uso exato lete varabaixo;

Ao usar let

for (let i = 0; i < 10 ; i++) {
    setTimeout(
        function a() {
            console.log(i); //print 0 to 9, that is literally AWW!!!
        }, 
        100 * i);
}

Isso ocorre porque ao usar let , para cada iteração de loop, a variável tem escopo definido e possui sua própria cópia.

Ao usar var

for (var i = 0; i < 10 ; i++) {
    setTimeout(
        function a() {
            console.log(i); //print 10 times 10
        }, 
        100 * i);
}

Isso ocorre porque, ao usar var, para cada iteração de loop, a variável tem escopo definido e possui cópia compartilhada.

Ankur Soni
fonte
8

Na maioria dos termos básicos,

for (let i = 0; i < 5; i++) {
  // i accessible ✔️
}
// i not accessible ❌

for (var i = 0; i < 5; i++) {
  // i accessible ✔️
}
// i accessible ✔️

⚡️ Sandbox para brincar ↓

Editar let vs var

Hasan Sefa Ozalp
fonte
7

Se eu li as especificações corretamente, let felizmente também pode ser aproveitado para evitar funções auto-chamadas usadas para simular membros particulares - um padrão de design popular que diminui a legibilidade do código, complica a depuração, que não adiciona proteção real ao código ou outros benefícios - exceto, talvez, a satisfação de alguém. desejo de semântica, então pare de usá-lo. / discurso retórico

var SomeConstructor;

{
    let privateScope = {};

    SomeConstructor = function SomeConstructor () {
        this.someProperty = "foo";
        privateScope.hiddenProperty = "bar";
    }

    SomeConstructor.prototype.showPublic = function () {
        console.log(this.someProperty); // foo
    }

    SomeConstructor.prototype.showPrivate = function () {
        console.log(privateScope.hiddenProperty); // bar
    }

}

var myInstance = new SomeConstructor();

myInstance.showPublic();
myInstance.showPrivate();

console.log(privateScope.hiddenProperty); // error

Consulte ' Emulando interfaces privadas '

Daniel Sokolowski
fonte
Você pode explicar como as Expressões de Função Invocadas Imediatamente não fornecem "proteção de código" e fornecem let? (Suponho que você queira dizer IIFE com "função de auto-invocação".)
Robert Siemer
E por que você define hiddenPropertyno construtor? Existe apenas um hiddenPropertypara todas as instâncias da sua "classe".
Robert Siemer
4

Alguns hacks com let:

1

    let statistics = [16, 170, 10];
    let [age, height, grade] = statistics;

    console.log(height)

2)

    let x = 120,
    y = 12;
    [x, y] = [y, x];
    console.log(`x: ${x} y: ${y}`);

3)

    let node = {
                   type: "Identifier",
                   name: "foo"
               };

    let { type, name, value } = node;

    console.log(type);      // "Identifier"
    console.log(name);      // "foo"
    console.log(value);     // undefined

    let node = {
        type: "Identifier"
    };

    let { type: localType, name: localName = "bar" } = node;

    console.log(localType);     // "Identifier"
    console.log(localName);     // "bar"

Getter e setter com let:

let jar = {
    numberOfCookies: 10,
    get cookies() {
        return this.numberOfCookies;
    },
    set cookies(value) {
        this.numberOfCookies = value;
    }
};

console.log(jar.cookies)
jar.cookies = 7;

console.log(jar.cookies)
zloctb
fonte
por favor, o que isso significa let { type, name, value } = node;? você cria um novo objeto com 3 propriedades, digite / nome / valor e inicializa-os com os valores de propriedades do nó?
AlainIb
No exemplo 3, você está declarando novamente o nó que causa exceção. Todos esses exemplos também funcionam perfeitamente vartambém.
Rehan Haider
4

let vs var. É tudo sobre escopo .

variáveis ​​var são globais e podem ser acessadas basicamente em qualquer lugar, enquanto variáveis ​​variáveis ​​não são globais e só existem até que um parêntese de fechamento as mate.

Veja meu exemplo abaixo e observe como a variável lion (let) age de maneira diferente nos dois console.logs; fica fora do escopo no segundo console.log.

var cat = "cat";
let dog = "dog";

var animals = () => {
    var giraffe = "giraffe";
    let lion = "lion";

    console.log(cat);  //will print 'cat'.
    console.log(dog);  //will print 'dog', because dog was declared outside this function (like var cat).

    console.log(giraffe); //will print 'giraffe'.
    console.log(lion); //will print 'lion', as lion is within scope.
}

console.log(giraffe); //will print 'giraffe', as giraffe is a global variable (var).
console.log(lion); //will print UNDEFINED, as lion is a 'let' variable and is now out of scope.
daCoda
fonte
4

O ES6 introduziu duas novas palavras-chave ( let e const ) alternadas para var .

Quando você precisa de uma desaceleração no nível do bloco, pode usar let e const em vez de var.

A tabela abaixo resume a diferença entre var, let e const

insira a descrição da imagem aqui

Srikrushna
fonte
3

let faz parte de es6. Essas funções explicam a diferença de maneira fácil.

function varTest() {
  var x = 1;
  if (true) {
    var x = 2;  // same variable!
    console.log(x);  // 2
  }
  console.log(x);  // 2
}

function letTest() {
  let x = 1;
  if (true) {
    let x = 2;  // different variable
    console.log(x);  // 2
  }
  console.log(x);  // 1
}
vipul jain
fonte
3

A seguir, mostramos como 'let' e 'var' são diferentes no escopo:

let gfoo = 123;
if (true) {
    let gfoo = 456;
}
console.log(gfoo); // 123

var hfoo = 123;
if (true) {
    var hfoo = 456;
}
console.log(hfoo); // 456

A gfoo, definida por let, inicialmente, está no escopo global , e quando nós declaramos gfoonovamente dentro do if clauseseu escopo mudou e quando um novo valor é atribuído à variável dentro desse âmbito que não afeta o escopo global.

Considerando que hfoo, definido por varé inicialmente no escopo global , mas novamente quando o declaramos dentro do if clause, ele considera o escopo global hfoo, embora var tenha sido usado novamente para declará-lo. E quando atribuímos novamente seu valor, vemos que o escopo global hfoo também é afetado. Essa é a principal diferença.

Piklu Dey
fonte
2

Como acima mencionado:

A diferença está no escopo. vartem o escopo definido para o bloco de funções mais próximo e o letescopo do bloco anexo mais próximo , que pode ser menor que um bloco de funções. Ambos são globais se estiverem fora de qualquer bloco. Vamos ver um exemplo:

Exemplo 1:

Nos meus dois exemplos, tenho uma função myfunc. myfunccontém uma variável myvarigual a 10. No meu primeiro exemplo, verifico se myvaré igual a 10 ( myvar==10). Se sim, declaro uma variável myvar(agora tenho duas variáveis ​​myvar) usando a varpalavra-chave e atribuo um novo valor (20). Na próxima linha, imprimo seu valor no meu console. Após o bloco condicional, imprimo novamente o valor de myvarno meu console. Se você olhar para a saída de myfunc, myvartem valor igual a 20.

deixe a palavra-chave

Exemplo2: No meu segundo exemplo, em vez de usar a varpalavra-chave no meu bloco condicional, declaro myvarusar a letpalavra-chave. Agora, quando ligo myfunc , recebo duas saídas diferentes: myvar=20e myvar=10.

Portanto, a diferença é muito simples, ou seja, seu escopo.

N Randhawa
fonte
3
Não poste imagens de código, isso é considerado uma prática ruim no SO, pois não pode ser pesquisado por usuários futuros (nem por questões de acessibilidade). Além disso, essa resposta não adiciona nada que outras respostas ainda não tenham abordado.
Inostia
2

Quero vincular essas palavras-chave ao contexto de execução, porque o contexto de execução é importante em tudo isso. O contexto de execução possui duas fases: uma fase de criação e uma fase de execução. Além disso, cada contexto de execução possui um ambiente variável e um ambiente externo (seu ambiente lexical).

Durante a fase de criação de um contexto de execução, var, let e const ainda armazenam sua variável na memória com um valor indefinido no ambiente variável do contexto de execução especificado. A diferença está na fase de execução. Se você usar como referência uma variável definida com var antes de atribuir um valor, ela será indefinida. Nenhuma exceção será gerada.

No entanto, você não pode fazer referência à variável declarada com let ou const até que seja declarada. Se você tentar usá-lo antes de ser declarado, uma exceção será gerada durante a fase de execução do contexto de execução. Agora a variável ainda estará na memória, cortesia da fase de criação do contexto de execução, mas o mecanismo não permitirá que você a use:

function a(){
    b;
    let b;
}
a();
> Uncaught ReferenceError: b is not defined

Com uma variável definida com var, se o Mecanismo não puder encontrar a variável no Ambiente Variável do Contexto de Execução atual, ele subirá a cadeia de escopo (o Ambiente Externo) e verificará a variável no Ambiente Variável do Ambiente Externo. Se não conseguir encontrá-lo, continuará pesquisando a cadeia de escopo. Este não é o caso de let e const.

A segunda característica do let é que ela introduz o escopo do bloco. Os blocos são definidos por chaves. Os exemplos incluem blocos funcionais, se blocos, para blocos, etc. Quando você declara uma variável com deixar entrar um bloco, a variável está disponível apenas dentro do bloco. De fato, toda vez que o bloco é executado, como dentro de um loop for, ele cria uma nova variável na memória.

O ES6 também introduz a palavra-chave const para declarar variáveis. const também tem escopo definido no bloco. A diferença entre let e const é que as variáveis ​​const precisam ser declaradas usando um inicializador, ou isso gerará um erro.

E, finalmente, quando se trata do Contexto de Execução, as variáveis ​​definidas com var serão anexadas ao objeto 'this'. No contexto de execução global, esse será o objeto de janela nos navegadores. Este não é o caso de let ou const.

Donato
fonte
2

Eu acho que os termos e a maioria dos exemplos são um pouco esmagadores. O principal problema que tive pessoalmente com a diferença é entender o que é um "bloco". Em algum momento, percebi que um bloco seria qualquer colchete, exceto a IFdeclaração. um colchete {de abertura de uma função ou loop definirá um novo bloco, qualquer coisa definida letdentro dele, não estará disponível após o colchete }de fechamento da mesma coisa (função ou loop); Com isso em mente, era mais fácil entender:

let msg = "Hello World";

function doWork() { // msg will be available since it was defined above this opening bracket!
  let friends = 0;
  console.log(msg);

  // with VAR though:
  for (var iCount2 = 0; iCount2 < 5; iCount2++) {} // iCount2 will be available after this closing bracket!
  console.log(iCount2);
  
    for (let iCount1 = 0; iCount1 < 5; iCount1++) {} // iCount1 will not be available behind this closing bracket, it will return undefined
  console.log(iCount1);
  
} // friends will no be available after this closing bracket!
doWork();
console.log(friends);

Dementic
fonte
1

Agora, acho que há melhor escopo de variáveis ​​para um bloco de instruções usando let:

function printnums()
{
    // i is not accessible here
    for(let i = 0; i <10; i+=)
    {
       console.log(i);
    }
    // i is not accessible here

    // j is accessible here
    for(var j = 0; j <10; j++)
    {
       console.log(j);
    }
    // j is accessible here
}

Acho que as pessoas começarão a usar let aqui depois para que tenham escopo semelhante em JavaScript, como outras linguagens, Java, C # etc.

Pessoas sem um entendimento claro sobre o escopo no JavaScript costumavam cometer o erro anteriormente.

O içamento não é suportado usando let.

Com essa abordagem, os erros presentes no JavaScript estão sendo removidos.

Consulte ES6 em profundidade: deixe e const para entendê-lo melhor.

swaraj patil
fonte
Para em profundidade compreensão sobre ele se referem ligação - davidwalsh.name/for-and-against-let
swaraj Patil
1

Este artigo define claramente a diferença entre var, let e const

const é um sinal de que o identificador não será reatribuído.

let, é um sinal de que a variável pode ser reatribuída, como um contador em um loop ou uma troca de valor em um algoritmo. Também sinaliza que a variável será usada apenas no bloco em que está definida, que nem sempre é a função inteira.

varagora é o sinal mais fraco disponível quando você define uma variável em JavaScript. A variável pode ou não ser reatribuída, e a variável pode ou não ser usada para uma função inteira, ou apenas para o propósito de um bloco ou loop.

https://medium.com/javascript-scene/javascript-es6-var-let-or-const-ba58b8dcde75#.esmkpbg9b

anandharshan
fonte