w3schools - var let const javascript




Qual é a diferença entre usar "let" e "var" para declarar uma variável em JavaScript? (18)

O ECMAScript 6 introduziu a instrução let . Eu ouvi isso descrito como uma variável "local", mas ainda não tenho certeza de como ela se comporta de maneira diferente da palavra-chave var .

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


let

Espaço do bloco

As variáveis ​​declaradas usando a palavra-chave let têm escopo de bloco, o que significa que 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 let nã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), let tem 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 let dentro 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 loops de entrada 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 fechamentos

Se você usar let vez de var em 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 let nã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;

Não é necessário 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 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 a let - é escopo de bloco e tem TDZ. Existem, no entanto, duas coisas diferentes.

Nenhuma reatribuição

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

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

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

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

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

O inicializador é obrigatório

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

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

Função Escopo do Bloco VS:

A principal diferença entre vare leté que as variáveis ​​declaradas com funçãovar têm escopo . Considerando que as funções declaradas com letsão 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 é acessível fora da ifinstrução. Essa variável fooestaria disponível em todos os lugares dentro do escopo da testVar função .

variáveis ​​com let:

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

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

Outra diferença entre vare leté variável com declarado com let não seja içada . 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 que se içou:

console.log(varVar);

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

Global letnão se apega a window:

Uma variável declarada 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 os possíveis conflitos de nomenclatura 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 cuidadosamente se isso é realmente necessário).


A diferença é o escopo. var tem o escopo definido para o bloco de funções mais próximo e let tem o escopo definido para o 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.

Além disso, as variáveis ​​declaradas com let não são acessíveis antes de serem declaradas em seu bloco delimitador. Como visto na demonstração, isso lançará uma exceção ReferenceError.

Demo :

var html = '';

write('#### global ####\n');
write('globalVar: ' + globalVar); //undefined, but visible

try {
  write('globalLet: ' + globalLet); //undefined, *not* visible
} catch (exception) {
  write('globalLet: exception');
}

write('\nset variables');

var globalVar = 'globalVar';
let globalLet = 'globalLet';

write('\nglobalVar: ' + globalVar);
write('globalLet: ' + globalLet);

function functionScoped() {
  write('\n#### function ####');
  write('\nfunctionVar: ' + functionVar); //undefined, but visible

  try {
    write('functionLet: ' + functionLet); //undefined, *not* visible
  } catch (exception) {
    write('functionLet: exception');
  }

  write('\nset variables');

  var functionVar = 'functionVar';
  let functionLet = 'functionLet';

  write('\nfunctionVar: ' + functionVar);
  write('functionLet: ' + functionLet);
}

function blockScoped() {
  write('\n#### block ####');
  write('\nblockVar: ' + blockVar); //undefined, but visible

  try {
    write('blockLet: ' + blockLet); //undefined, *not* visible
  } catch (exception) {
    write('blockLet: exception');
  }

  for (var blockVar = 'blockVar', blockIndex = 0; blockIndex < 1; blockIndex++) {
    write('\nblockVar: ' + blockVar); // visible here and whole function
  };

  for (let blockLet = 'blockLet', letIndex = 0; letIndex < 1; letIndex++) {
    write('blockLet: ' + blockLet); // visible only here
  };

  write('\nblockVar: ' + blockVar);

  try {
    write('blockLet: ' + blockLet); //undefined, *not* visible
  } catch (exception) {
    write('blockLet: exception');
  }
}

function write(line) {
  html += (line ? line : '') + '<br />';
}

functionScoped();
blockScoped();

document.getElementById('results').innerHTML = html;
<pre id="results"></pre>

Global:

Eles são muito semelhantes quando usados ​​assim fora de um bloco funcional.

let me = 'go';  // globally scoped
var i = 'able'; // globally scoped

No entanto, as variáveis ​​globais definidas com let não serão adicionadas como propriedades no objeto de window global window como aquelas definidas com var .

console.log(window.me); // undefined
console.log(window.i); // 'able'

Função:

Eles são idênticos quando usados ​​assim em um bloco de funções.

function ingWithinEstablishedParameters() {
    let terOfRecommendation = 'awesome worker!'; //function block scoped
    var sityCheerleading = 'go!'; //function block scoped
}

Quadra:

Aqui está a diferença. let é visível apenas no loop for() e var é visível para toda a função.

function allyIlliterate() {
    //tuce is *not* visible out here

    for( let tuce = 0; tuce < 5; tuce++ ) {
        //tuce is only visible in here (and in the for() parentheses)
        //and there is a separate tuce variable for each iteration of the loop
    }

    //tuce is *not* visible out here
}

function byE40() {
    //nish *is* visible out here

    for( var nish = 0; nish < 5; nish++ ) {
        //nish is visible to the whole function
    }

    //nish *is* visible out here
}

Redeclaração:

Assumindo o modo estrito, o var permitirá que você reconfirme a mesma variável no mesmo escopo. Por outro lado, let vamos:

'use strict';
let me = 'foo';
let me = 'bar'; // SyntaxError: Identifier 'me' has already been declared
'use strict';
var me = 'foo';
var me = 'bar'; // No problem, `me` is replaced.

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

permite que você declare variáveis ​​limitadas no escopo para o bloco, declaração ou expressão na qual ele é usado. 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 no qual estão definidas, bem como em quaisquer sub-blocos contidos. Desta forma, vamos trabalhar muito como var . A principal diferença é que o escopo de uma variável var é 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, vamos , 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 para aquele bloco. Observe a diferença entre var cujo escopo 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

Também não se esqueça que é o recurso ECMA6, por isso ainda não é totalmente suportado, por isso é melhor que o transpile para o ECMA5 usando o Babel, etc ... para obter mais informações sobre a visita ao site da babel


Aqui está um exemplo para a diferença entre os dois (suporte iniciado apenas para chrome):

Como você pode ver, a variável var j ainda possui um valor fora do escopo do loop for (Escopo do Bloco), mas a variável let i é 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);


Aqui está um exemplo para adicionar ao que os outros já escreveram. Suponha que você queira criar uma matriz de funções, adderFunctions , onde cada função recebe um único argumento Number e retorna a soma do argumento e o índice da função na matriz. Tentar gerar adderFunctions com um loop usando a palavra-chave var não funcionará da maneira que alguém pode esperar ingenuamente:

// 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 desejada de funções porque o escopo do i se estende além da iteração do bloco for no qual cada função foi criada. Em vez disso, no final do loop, o i em cada fechamento da função se refere ao valor de i no final do loop (1000) para cada função anônima em adderFunctions . Isso não é o que nós queríamos: temos agora uma matriz de 1000 funções diferentes na memória com exatamente o mesmo comportamento. E se subseqüentemente atualizarmos o valor de i , a mutação afetará todas as 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 é rebote 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 adderFunctions se comporta conforme o esperado.

Agora, imagem misturando os dois comportamentos e você provavelmente verá porque não é recomendado misturar o let e o const mais novos com o var mais antigo no mesmo script. Fazer isso pode resultar em 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 isso acontecer com você. Use um linter.

NOTA: Este é um exemplo de ensino destinado a demonstrar a var/ letcomportamento 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 encerramentos de funções anônimas pode ser encontrada no mundo real em outros contextos. YMMV.


Existem algumas diferenças sutis - let escopo se comportar mais como o escopo variável faz em mais ou menos outras línguas.

Por exemplo, escopos para o bloco envolvente, eles não existem antes de serem declarados, etc.

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



let também pode ser usado para evitar problemas com encerramentos. Ele vincula o valor novo em vez de manter uma referência antiga, conforme mostrado nos exemplos abaixo.

DEMO

for(var i = 1; i < 6; i++) {
  document.getElementById('my-element' + i)
    .addEventListener('click', function() { alert(i) })
}

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

Cada manipulador de um único clique se referirá ao mesmo objeto, porque há apenas um objeto contador que contém 6, de modo que você obtém seis em cada clique.

A solução geral é envolvê-lo em uma função anônima e passar i como argumento. Esses problemas também podem ser evitados agora usando let vez de var como mostrado no código abaixo.

DEMO (testado no Chrome e Firefox 50)

'use strict';

for(let i = 1; i < 6; i++) {
  document.getElementById('my-element' + i)
    .addEventListener('click', function() { alert(i) })
}

var é uma variável global (capaz de elevar).

lete consté o escopo do 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


Como acima mencionado:

A diferença é o escopo. vartem o escopo definido para o bloco de funções mais próximo e lettem o escopo definido para o 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 eu verifico se myvaré igual a 10 ( myvar==10). Se sim, eu declaro uma variável myvar(agora tenho duas variáveis ​​myvar) usando uma varpalavra-chave e atribuo a ela 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.

Example2: No meu segundo exemplo, em vez de usar a varpalavra-chave em meu bloco condicional, declaro myvarusando letkeyword. Agora, quando eu ligar myfunc, recebo duas saídas diferentes: myvar=20e myvar=10.

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


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, o que nem sempre é toda a função de contenção.

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


Também parece que, pelo menos no Visual Studio 2015, o TypeScript 1.5, "var" permite várias declarações do 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;

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

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

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

As restrições impostas letreduzem a visibilidade das variáveis ​​e aumentam a probabilidade de que colisões inesperadas de nomes sejam encontradas antecipadamente. Isso torna mais fácil rastrear e raciocinar sobre as variáveis, incluindo sua reachability (ajudando com a 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 as estruturas desenvolvidas de forma independente 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 encerramento em um loop (# 5) ou para declarar variáveis ​​globais visíveis externamente em seu código (# 4). O uso de varexportações pode ser suplantado se exportmigrar do espaço do transpilador para a linguagem principal.

Exemplos

1. Não use fora do bloco anexo mais próximo: Este bloco de código lançará um erro de referência porque o segundo uso xocorre fora do bloco onde é declarado com let:

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

Em contraste, o mesmo exemplo com varobras.

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

Em contraste, o mesmo exemplo com varparses e executa sem lançar exceções.

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

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

4. Globals não anexados 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 de usar com fechamentos: Variáveis ​​declaradas com varnão funcionam bem com fechamentos dentro de loops. Aqui está um loop simples que gera a seqüência de valores que a variável ipossui em diferentes momentos:

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

Em JavaScript, muitas vezes usamos variáveis ​​em um tempo significativamente posterior do que quando elas são criadas. Quando demonstramos isso, atrasando 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. Em contraste, se tivéssemos usado em var ivez disso:

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

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

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

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)


Verifique este link no MDN

let x = 1;

if (x === 1) {
let x = 2;

console.log(x);
// expected output: 2
}

console.log(x);
// expected output: 1

vamos fazer parte do es6. Essas funções explicarão 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
}




let