Pergunta

ECMAScript 6 introduzido a declaração let .

Eu ouvi que ele é descrito como uma variável "local", mas eu ainda não tenho certeza de como ele se comporta de forma diferente do que a palavra-chave var.

Quais são as diferenças? Quando deve let ser usado sobre var?

Foi útil?

Solução

Escopo governa

principal diferença é o escopo regras. Variáveis ??declaradas por palavra-chave var tem como escopo o corpo da função imediata (daí o escopo de função), enquanto variáveis ??let são escopo para o imediato delimitador bloco indicado por { } (daí o escopo de 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 palavra-chave let foi introduzida à linguagem foi escopo de função é confuso e foi uma das principais fontes de erro em javascript.

Dê uma olhada neste exemplo de outra pergunta 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: 3 estava de saída para consolar cada funcs[j](); tempo foi invocado uma vez funções anônimas foram ligados ao mesmo mesma variável.

As pessoas tinham que criar criar funções imediatamente invocadas para capturar valor correto dos laços, mas que também era cabeludo.

Içamento

Enquanto variáveis ??declaradas com var palavra-chave são "içada" ao topo do bloco que significa que eles são acessíveis em seu escopo delimitador antes mesmo de serem declarados:

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

run();

deixe variáveis ??não são inicializados até sua definição é avaliada. Acessá-los antes de os resultados de inicialização em um ReferenceError. Variável a ser dito na "zona morta temporal," a partir do início do bloco até que a inicialização é processado.

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

checkHoisting();

Criando propriedade 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

Redeclaration

No modo estrito, var vai deixar você voltar a declarar a mesma variável no mesmo escopo, enquanto let levanta uma 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

Outras dicas

let também pode ser usado para evitar problemas com encerramentos. Liga-se o valor fresco, em vez de manter uma referência de idade como se mostra 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>
<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>

código acima demonstra um problema clássico fechamento JavaScript. Referência para a variável i está sendo armazenado no fechamento manipulador de clique, em vez do valor real de i.

Cada manipulador de clique único irá se referir ao mesmo objeto, porque há apenas um objeto de contador que detém 6 de modo a obter seis em cada clique.

A solução geral é envolver isso em uma função anônima e passar i como um argumento. Essas questões também podem ser evitados agora usando let vez var como mostrado no código abaixo.

(Testado em cromo 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>
<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>

Qual é a diferença entre let e var?

  • Uma variável definida usando uma instrução var é conhecida em todo a função é definido em, desde o início da função. *
  • Uma variável definida usando uma instrução let só é conhecido na < strong> no bloco é definido em, a partir do momento em que é definido 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 a nossa j variável só é conhecido no primeiro loop, mas não antes e depois. No entanto, o nosso i variável é conhecido em toda a função.

Além disso, consideram que as variáveis ??do bloco escopo não são conhecidos antes de serem declarados, porque eles não são içadas. Você também não está autorizado a redeclare o mesmo bloco de escopo variável dentro do mesmo bloco. Isso faz com que bloqueiam variáveis ??com escopo menos propenso a erros do que variáveis ??globalmente ou funcionalmente escopo, que são içadas e que não produzem quaisquer erros em caso de múltiplas declarações.


É seguro usar let hoje?

Algumas pessoas argumentam que, no futuro, só vai usar deixe declarações e que as declarações var se tornará obsoleto. JavaScript guru Kyle Simpson escreveu um artigo muito elaborada sobre por que ele acredita que não será o caso .

Hoje, no entanto, que definitivamente não é o caso. Na verdade, precisamos realmente de nos perguntar se é seguro usar a instrução let. A resposta a essa pergunta depende do ambiente:

  • Se você é um código JavaScript do lado do servidor escrito ( Node.js ), você pode usar com segurança a declaração let.

  • Se você é código JavaScript do lado cliente escrito e usar um transpiler baseado em navegador (como < strong> Traceur ou babel-autônomo ), você pode usar com segurança a declaração let, no entanto o seu código é susceptível de ser qualquer coisa, mas ótima em relação ao desempenho.

  • Se você é código JavaScript do lado cliente escrito e usar um transpiler baseado Node (como o traceur shell script ou Babel ), você pode usar com segurança a declaração let. E porque o navegador só vai saber sobre o código transpiled, desvantagens de desempenho deve ser limitado.

  • Se você é código JavaScript do lado cliente escrito e não usar um transpiler, você precisa considerar o suporte ao navegador.

    Existem ainda alguns navegadores que não suportam let em tudo:

 mesa de apoio


Como manter o controle de suporte ao navegador

Para uma visão geral up-to-date do que os navegadores suportam a afirmação let no momento da sua leitura esta resposta, consulte desta página Can I Use .


* Globalmente e funcionalmente escopo vaVariáveis ??podem ser inicializados e usados ??antes de serem declarados porque as variáveis ??JavaScript são içada . Isto significa que as declarações são sempre muito a parte superior do escopo.

** Bloquear escopo variáveis ??não são içada

Aqui está um explicação do let chave com alguns exemplos.

let funciona muito bem como var. A principal diferença é que o âmbito de aplicação de uma variável var é toda a função de envolvente

Este mesa em shows Wikipédia que os navegadores suportam Javascript 1.7.

Note que apenas Mozilla e Chrome navegadores apoiá-lo. IE, Safari e, potencialmente, outros não.

A resposta aceita está faltando um ponto:

{
  let a = 123;
};

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

let

escopo de bloco

As variáveis ??declaradas usando a palavra-chave let são de escopo de bloco, o que significa que eles só estão disponíveis na bloco em que foram declarados.

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

No nível superior, as variáveis ??declaradas usando let não criar 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 do lado de fora de um bloco), let tem o mesmo alcance como 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 let dentro de um bloco não pode ser acessado 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 let em loops pode ser referenciado somente dentro desse circuito.

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 fechos

Se você usar let vez de var em um loop, a cada iteração você começa 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);
}

Temporal zona morta

Por causa temporal zona morta , variáveis ??declaradas usando let não pode ser acessado antes de serem declarados. Tentativa de fazer isso gera um erro.

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

Sem re-declarar

Você não pode declarar as mesmas variáveis ??várias vezes usando let. Você também não pode declarar uma variável usando let com o 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 é bastante semelhante ao let-lo de e tem escopo de bloco de TDZ. Há, no entanto, duas coisas que são diferentes.

Sem re-atribuição

variável declarada usando const não pode ser atribuída-re.

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

Note que isso não significa que o valor é imutável. Suas propriedades ainda pode ser alterado.

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

Se você quiser ter um objeto imutável, você deve usar Object.freeze() .

Initializer é necessária

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

const a; // SyntaxError: Missing initializer in const declaration

Aqui está um exemplo para a diferença entre os dois (suporte apenas começou para o Chrome):
enter descrição da imagem aqui

Como você pode ver a variável var j ainda está tendo um valor fora do alcance de loop (bloco Scope), mas a variável let i está fora indefinida do âmbito de loop.

"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);

Existem algumas diferenças sutis - let escopo se comporta mais como escopo de variáveis ??faz em mais ou menos quaisquer outras línguas.

por exemplo. Ele escopos para o bloco envolvendo, eles não existem antes de serem declarados, etc.

No entanto, é importante notar que let é apenas uma parte da mais recentes implementações de JavaScript e tem vários graus de suporte ao navegador .

  • Variável Não Elevação

    let não guincho para todo o escopo do bloco são apresentados. Por outro lado, var poderia 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, Ambos var e let são içadas .

  • Garbage Collection

    Bloco âmbito da let é útil se relaciona com encerramentos e coleta de lixo na memória recuperação. Considere-se,

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

    O manipulador de retorno click não precisa a variável hugeData em tudo. Teoricamente, após corridas process(..), a enorme estrutura de dados hugeData poderia ser lixo coletado. No entanto, é possível que algum mecanismo JS ainda terá que manter esta estrutura enorme, já que a função click tem um fecho ao longo de todo o escopo.

    No entanto, o escopo do bloco pode fazer essa estrutura de dados enorme de 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 laços

    let no circuito pode re liga-it para cada iteração do loop, certificando-se de re-atribuir-lhe o valor a partir do final da iteração do loop anterior. Considere-se,

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

    No entanto, substituir var com let

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

    Porque let criar um novo ambiente lexical com esses nomes para um) a initialiser expressão b) cada iteração (previosly para avaliar a expressão de incremento), mais detalhes são aqui .

A principal diferença é o espaço diferença, enquanto deixe pode ser só está disponível dentro do espaço é declarada, como no loop for, < strong> var pode ser acessado fora do loop, por exemplo. A partir da documentação em MDN (exemplos também de MDN):

deixe permite que você declare variáveis ??que são limitados em escopo para o bloco, declaração ou expressão em que ela é usada. Isso é diferente da var palavra-chave, que define uma variável global ou localmente para uma função inteira, independentemente do escopo de bloco.

As variáveis ??declarado pelo deixe têm como escopo o bloco em que são definidos, bem como em qualquer sub-blocos contidos. Desta forma, deixe funciona muito bem como var . A principal diferença é que o âmbito de um var variável é toda a função de inclusão:

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 cria 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 limites de escopo da variável para esse bloco. Observe a diferença entre var , cujo âmbito está dentro da função onde ela é declarada.

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 que é característica ECMA6, por isso não é totalmente suportado ainda, por isso é melhor sempre transpiles-lo para ECMA5 usando Babel etc ... para mais informações sobre a visita site babel

Aqui está um exemplo para adicionar ao que outros já escrito. Suponha que você queira fazer uma série de funções, adderFunctions, onde cada função recebe um único argumento Número e retorna a soma do argumento e do índice da função na matriz. Tentando gerar adderFunctions com um loop usando a palavra-chave var não vai funcionar da maneira que alguém poderia ser esperado:

// 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 gerar a matriz desejada de funções, pois o escopo da i se estende para além da iteração do bloco for em que cada função foi criado. Em vez disso, no final do ciclo, o i no fecho de cada uma das funções refere-se ao valor de i no final do circuito (1000) para cada função anónimo em adderFunctions. Este não é o que queríamos em tudo: agora temos um array de 1000 funções diferentes na memória com exatamente o mesmo comportamento. E se posteriormente atualizar o valor do i, a mutação irá afectar toda a adderFunctions.

No entanto, podemos tentar novamente usando a palavra-chave let:

// 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 é recuperar em cada iteração do loop for. Cada função agora mantém o valor de i no momento da criação da função, e se comporta adderFunctions como esperado.

Agora, imagem misturando os dois comportamentos e você provavelmente vai ver porque ele não é recomendado para misturar a mais recente let e const com o var mais velho no mesmo script. Fazer isso pode resultar é algum 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 que isso aconteça com você. Use um linter.

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

A diferença está no escopo das variáveis ??declaradas com cada um.

Na prática, há uma série de consequências úteis da diferença no escopo:

  1. variáveis ??let só são visíveis em sua envolvente mais próxima bloco ({ ... }).
  2. variáveis ??let só podem ser usados ??em linhas de código que ocorrem após a variável é declarada (embora eles são içadas !).
  3. variáveis ??let não pode ser declarado novamente por um var ou let posterior.
  4. variáveis ??let globais não são adicionados ao objeto window global.
  5. variáveis ??let são fácil de usar com fechos (eles não causam condições de corrida ).

As restrições impostas pelo let reduzir a visibilidade das variáveis ??e aumentar a probabilidade de colisões de nomes inesperados será encontrado mais cedo. Isto torna mais fácil de controlar e raciocinar sobre variáveis, incluindo a sua acessibilidade (ajudando com recuperação de memória não utilizado) .

Assim, variáveis ??let são menos propensos a causar problemas quando usado em grandes programas ou quando os quadros independentemente desenvolvidos são combinados em maneiras novas e inesperadas.

var ainda pode ser útil se você tiver certeza que deseja o único vinculativo efeito quando usar um fechamento em um loop (# 5) ou para declarar variáveis ??globais externamente visíveis em seu código (# 4). Uso de var para as exportações podem ser suplantados se export migra para fora do espaço transpiler e para a língua principal.

Exemplos

1. No uso fora mais próximo bloco de inclusão: Este bloco de código irá lançar um erro de referência porque o segundo uso de x ocorre fora do bloco onde ele é declarado com let:

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

Em contraste, o mesmo exemplo com obras var.

2. Não adianta antes de declaração:
Este bloco de código irá lançar um ReferenceError antes que o código pode 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.
}

Em contraste, o mesmo exemplo com parses var e corre sem lançar qualquer exceção.

3. Sem redeclaração: O código a seguir demonstra que uma variável declarada com let não pode ser declarado novamente mais tarde:

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

4. Globals não ligado à 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. o uso fácil com fechos: Variáveis ??declaradas com var não funcionam bem com fechos dentro loops. Aqui é um circuito simples que saídas a seqüência de valores que o i variável tem em diferentes pontos no tempo:

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

Especificamente, esta saídas:

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

Em JavaScript muitas vezes usamos variáveis ??em um tempo significativamente mais tarde do que quando eles são criados. Quando demonstrar isso atrasando a saída com um fecho passado para setTimeout:

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

... a saída permanece inalterada, enquanto nós ficar com let. Em contraste, se tivéssemos usado var i vez:

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

... o loop saídas inesperadamente "i é de 5" cinco vezes:

i is 5
i is 5
i is 5
i is 5
i is 5

Maio as duas funções a seguir mostram 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
}

let é interessante, porque nos permite fazer algo parecido com isto:

(() => {
    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 em contagem [0, 7].

Considerando

(() => {
    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++);
            }
        }
    }
})();

Somente as contagens [0, 1].

Função escopo de bloco VS:

A principal diferença entre var e let é que as variáveis ??declaradas com var são Função escopo . Considerando funções declaradas com let são bloco de escopo . 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 é chamado a variável foo, declarado com var, ainda é acessível fora a declaração if. Este foo variável estaria disponível em todos os lugares no âmbito do testVar Função .

variáveis ??com let:

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

variáveis ??let não se içou:

Outra diferença entre var e let é variáveis ??com declarada com let não recebem içada . Um exemplo é a melhor maneira de ilustrar esse comportamento:

variáveis ??com let não se içou:

console.log(letVar);

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

variáveis ??com var não se içou:

console.log(varVar);

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

Global não se apegue a window:

Uma variável declarada com let no escopo global (que é o código que não está em uma função) não são adicionados como uma propriedade no objeto window 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 let ser usado sobre var?

Use let sobre var sempre que você pode, porque é simplesmente escopo mais específico. Isso reduz os conflitos de nomes potenciais que podem ocorrer quando se lida com um grande número de variáveis. var pode ser usado quando você quiser uma variável global explicitamente para estar no objeto window (sempre considerar cuidadosamente se isso é realmente necessário).

Parece também que, pelo menos em Visual Studio 2015, typescript 1.5, "var" permite múltiplas declarações do mesmo nome de variável em um bloco, e "deixar" não.

Isto não irá gerar um erro de compilação:

var x = 1;
var x = 2;

Esta vontade:

let x = 1;
let x = 2;

var é escopo global variável (grua-able).

let e 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

ao usar let

A palavra-chave let atribui a declaração de variável para o alcance de qualquer bloco (geralmente um par { .. }) que está contido no. Em outras palavras, let seqüestra implicitamente âmbito de qualquer bloco para a sua declaração de variável.

variáveis ??let não podem ser acessados ??no objeto window porque eles não podem ser acessados ??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 variáveis ??em ES5 tem escopos em funções ou seja, as variáveis ??são válidas dentro da função e não fora a própria função.

variáveis ??var podem ser acessados ??no objeto window porque eles não podem ser acessados ??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 mais perguntas famosa entrevista no escopo também pode ser suficiente o uso exato da let e var como abaixo;

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 quando utilizar let, para cada iteração do loop a variável tem como escopo e tem 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 quando utilizar var, para cada iteração do loop a variável tem como escopo e compartilhou cópia.

Se eu ler as especificações para a direita então let felizmente também pode ser aproveitado para evitar funções auto invocando usado para simular apenas os membros privados - um padrão de design popular que diminui a legibilidade do código, complica a depuração, que acrescenta não real proteção de código ou outro benefício - exceto, talvez, satisfazendo o desejo de alguém para a semântica, então pare de usá-lo. / Rant

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

Veja ' Emulando interfaces privadas '

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)

deixe vs var. É tudo sobre espaço .

variáveis ??var são globais e pode ser acessado basicamente em todos os lugares, enquanto permitem variáveis ??não são globais e só existe até que um parêntese de fechamento mata-los.

Veja o meu exemplo abaixo, e observe como o leão (vamos) variável age de forma diferente nos dois console.logs; torna-se fora do escopo no 2º 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.

let é uma parte da ES6. Essas funções irão explicar a diferença de forma 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
}

Anteriormente, havia apenas dois escopos em JavaScript, ou seja, funcionais e globais. Com 'let' palavra-chave JavaScript introduziu agora variáveis ??block-level.

Para ter uma compreensão completa da palavra-chave 'let', ES6:. ‘Let’ palavra-chave para variável declarar em JavaScript irá ajudar

Agora eu acho que é melhor do escopo de variáveis ??a um bloco de declaraçõ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
}

Eu acho que as pessoas vão começar a usar deixar aqui depois de tanto que eles terão de escopo similar em JavaScript como outras línguas, Java, C #, etc.

As pessoas com não uma compreensão clara sobre o escopo em JavaScript usado para cometer o erro anterior.

Içamento não é suportado usando let.

Com este erros abordagem presente em JavaScript estão sendo removidos.

Consulte ES6 Em Profundidade :. deixá e const para compreendê-lo melhor

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

const é um sinal de que o identificador não será transferido.

let, é um sinal de que a variável pode ser transferido, tal como um contador em um loop, ou uma troca de valor em um algoritmo. Ela também sinaliza que a variável será utilizada apenas no bloco que está definido em, que nem sempre é toda a função que contém.

var agora é o sinal mais fraco disponível quando você definir uma variável em JavaScript. A variável podem ou não podem ser transferidos, e o variável pode ou não pode ser utilizado para uma função de todo, ou apenas para o propósito de um bloco ou loop.

https: // médio. com / javascript-scene / javascript-ES6-var-deixou-ou-const-ba58b8dcde75 # .esmkpbg9b

Como mencionado acima:

A diferença é o escopo. var tem como escopo a função mais próxima bloco e let tem como escopo o bloco mais próximo delimitador , que pode ser menor do que um bloco de função. Ambos são globais se fora de qualquer block.Lets ver um exemplo:

Exemplo 1:

Em meus dois exemplos Eu tenho uma função myfunc. myfunc contém uma myvar variável é igual a 10. No meu primeiro exemplo, eu verificar se myvar é igual a 10 (myvar==10). Se sim, eu AGIAN declarar uma myvar variável (agora eu tenho duas variáveis ??MYVAR) usando a palavra chave var e atribuir-lhe um novo valor (20). Na próxima linha I imprimir o seu valor no meu console. Depois que o bloco condicional I novamente imprimir o valor de myvar no meu console. Se você olhar para a saída do myfunc, myvar tem é igual ao valor a 20.

vamos palavra-chave

Exemplo 2: No meu segundo exemplo em vez de usar palavra-chave var no meu bloco condicional Declaro myvar usando palavra-chave let. Agora, quando eu chamo myfunc eu recebo duas saídas diferentes:. myvar=20 e myvar=10

Assim, a diferença é muito simples ou seja o seu alcance.

enter descrição da imagem aqui

Dê uma olhada esta imagem, eu criei um exemplo muito simples para demonstração de variáveis ??const e let. Como você pode ver, quando você tenta variável mudança const, você receberá o erro ( A tentativa de override 'name' que é constante "), mas dê uma olhada variável let ...

Primeiramente nós declaramos let age = 33 e, posteriormente, atribuir algum outro age = 34; valor, que é ok, nós não temos quaisquer erros quando tentamos variável mudança let

Eu acho que os termos ea maioria dos exemplos são um pouco esmagadora, O principal problema que tive pessoalmente com a diferença é entender o que é um "bloco" é. Em algum momento eu percebi, um bloco seria quaisquer chaves, exceto para declaração IF. um { suporte de abertura de uma função ou ciclo irá definir um novo bloco, algo definido com let no seu interior, não estará disponível após a } suporte de fechamento da mesma coisa (função ou circular); Com isso em mente, era mais fácil de 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);

Como eu estou atualmente tentando obter uma compreensão detalhada de JavaScript vou compartilhar minha pesquisa breve, que contém algumas das grandes peças já discutidas, além de alguns outros detalhes em uma perspectiva diferente.

Compreender a diferença entre var e deixe pode ser mais fácil se entender a diferença entre função e escopo de bloco .

Vamos considerar os seguintes casos:

(function timer() {
    for(var i = 0; i <= 5; i++) {
        setTimeout(function notime() { console.log(i); }, i * 1000);
    }
})();


   Stack            VariableEnvironment //one VariablEnvironment for timer();
                                       // when the timer is out - the value will be the same value for each call
5. [setTimeout, i]  [i=5] 
4. [setTimeout, i]  
3. [setTimeout, i]
2. [setTimeout, i]
1. [setTimeout, i]
0. [setTimeout, i]

####################    

(function timer() {
    for (let i = 0; i <= 5; i++) {
        setTimeout(function notime() { console.log(i); }, i * 1000);
    }
})();

   Stack           LexicalEnvironment - each iteration has a new lexical environment
5. [setTimeout, i]  [i=5]       
                      LexicalEnvironment 
4. [setTimeout, i]    [i=4]     
                        LexicalEnvironment 
3. [setTimeout, i]      [i=3]       
                         LexicalEnvironment 
2. [setTimeout, i]       [i=2]
                           LexicalEnvironment 
1. [setTimeout, i]         [i=1]
                             LexicalEnvironment 
0. [setTimeout, i]           [i=0]

quando timer() é chamado um ExecutionContext é criado, que conterá tanto o VariableEnvironment e todo o LexicalEnvironments correspondente a cada iteração.

E um exemplo mais simples

Função Âmbito

function test() {
    for(var z = 0; z < 69; z++) {
        //todo
    }
    //z is visible outside the loop
}

Bloco Âmbito

function test() {
    for(let z = 0; z < 69; z++) {
        //todo
    }
    //z is not defined :(
}

Eu quero vincular essas palavras-chave para o contexto de execução, porque o contexto de execução é importante em tudo isso. O contexto de execução tem duas fases: uma fase de criação e de execução de fase. Além disso, cada um contexto de execução tem uma variável de ambiente exterior e do Ambiente (seu ambiente léxico).

Durante a fase de criação de um contexto de execução, var, vamos e const ainda irá armazenar sua variável na memória com um valor indefinido no ambiente Variável do dado contexto de execução. A diferença está em fase de execução. Se você usar referenciar uma variável definida com var antes de ser atribuído um valor, ela só vai ser indefinido. Nenhuma exceção será levantada.

No entanto, você não pode fazer referência a variável declarada com let ou const até que seja declarado. Se você tentar usá-lo antes de ser declarada, em seguida, uma exceção será levantada 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 motor não irá permitir que você usá-lo:

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

Com uma variável definida com var, se o motor não consegue encontrar a variável no variável de ambiente do contexto de execução atual, em seguida, ele vai até a cadeia de escopo (o ambiente externo) e verificar Variável do Meio Ambiente do Meio Ambiente do exterior para a variável. Se não puder encontrá-lo lá, ele vai continuar a procurar a cadeia de escopo. Este não é o caso com let e const.

A segunda característica de deixar é que introduz escopo de bloco. Os blocos são definidos por chaves. Exemplos incluem blocos de funções, se os blocos, para os blocos, etc. Quando você declarar uma variável com let dentro de um bloco, a variável está disponível apenas dentro do bloco. Na verdade, cada vez que o bloco é executado, como dentro de um laço for, ele irá criar uma nova variável na memória.

ES6 também introduz a palavra-chave const para declarar variáveis. const também é o bloco escopo. A diferença entre let e const é que const variáveis ??precisam ser declaradas usando um inicializador, ou ele irá gerar um erro.

E, finalmente, quando se trata do contexto de execução, as variáveis ??definidas com var será anexado ao 'isto' objeto. No contexto de execução global, que será o objeto da janela em navegadores. Este não é o caso para let ou const.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top