What's the difference between using "let" and "var" to declare a variable in JavaScript?

javascript scope ecmascript-6 var let

962134 просмотра

30 ответа

ECMAScript 6 introduced the let statement. I've heard it described as a "local" variable, but I'm still not quite sure how it behaves differently than the var keyword.

What are the differences? When should let be used over var?

Автор: TM. Источник Размещён: 17.05.2019 02:48

Ответы (30)


5112 плюса

Решение

The difference is scoping. var is scoped to the nearest function block and let is scoped to the nearest enclosing block, which can be smaller than a function block. Both are global if outside any block.

Кроме того, переменные, объявленные с помощью let, не доступны, прежде чем они будут объявлены в своем блоке. Как видно из демонстрации, это вызовет исключение ReferenceError.

Демо :

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>

Глобальный:

Они очень похожи, когда используются как это вне функционального блока.

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

Однако глобальные переменные, определенные с помощью let, не будут добавлены в свойства глобального windowобъекта, как те, которые определены с var.

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

Функция:

Они идентичны при использовании таким образом в функциональном блоке.

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

Блок:

Здесь есть разница. letвиден только в for()цикле и varвиден всей функции.

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
}

переопределение:

Предполагая строгий режим, varвы сможете повторно объявить одну и ту же переменную в той же области видимости. С другой стороны, letне будет

'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.
Автор: ThinkingStiff Размещён: 12.07.2012 02:53

507 плюса

letможет также использоваться, чтобы избежать проблем с закрытием. Он связывает свежую ценность, а не сохраняет старую ссылку, как показано в примерах ниже.

DEMO

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

Код выше демонстрирует классическую проблему закрытия JavaScript. Ссылка на iпеременную сохраняется в закрытии обработчика щелчка, а не на фактическое значение i.

Каждый обработчик одного клика будет ссылаться на один и тот же объект, потому что есть только один встречный объект, который содержит 6, так что вы получаете шесть на каждый клик.

Общий обходной путь - обернуть это в анонимную функцию и передать в iкачестве аргумента. Таких проблем можно также избежать, используя letвместо этого, varкак показано в коде ниже.

ДЕМО (протестировано в Chrome и Firefox 50)

'use strict';

for(let i = 1; i < 6; i++) {
  document.getElementById('my-element' + i)
    .addEventListener('click', function() { alert(i) })
}
Автор: Gurpreet Singh Размещён: 27.05.2015 10:16

138 плюса

Вот объяснение letключевого слова с некоторыми примерами.

пусть работает очень похоже на вар. Основное различие заключается в том, что область действия переменной var - это вся включающая функция

Эта таблица в Википедии показывает, какие браузеры поддерживают Javascript 1.7.

Обратите внимание, что только браузеры Mozilla и Chrome поддерживают его. IE, Safari и, возможно, другие нет.

Автор: Ben S Размещён: 17.04.2009 08:11

135 плюса

Какая разница между letа var?

  • Переменная, определенная с помощью varоператора, известна во всей функции, в которой она определена, с самого начала функции. (*)
  • Переменная, определенная с помощью letоператора, известна только в том блоке, в котором она определена, с момента ее определения. (**)

Чтобы понять разницу, рассмотрим следующий код:

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

Здесь мы видим, что наша переменная jизвестна только в первом цикле for, но не до и после. Тем не менее, наша переменная iизвестна во всей функции.

Кроме того, учтите, что переменные в области блока не известны до того, как они объявлены, потому что они не подняты. Вам также не разрешается повторно объявлять одну и ту же переменную области действия блока в одном и том же блоке. Это делает переменные области блока менее подверженными ошибкам, чем переменные глобальной или функциональной области, которые перемещаются и которые не выдают никаких ошибок в случае нескольких объявлений.


Безопасно ли использовать letсегодня?

Некоторые люди утверждают, что в будущем мы будем использовать ТОЛЬКО операторы let, а операторы var станут устаревшими. Гуру JavaScript Кайл Симпсон написал очень сложную статью о том, почему это не так .

Сегодня, однако, это определенно не так. На самом деле, нам нужно спросить себя, безопасно ли использовать это letутверждение. Ответ на этот вопрос зависит от вашей среды:

  • Если вы пишете код JavaScript на стороне сервера ( Node.js ), вы можете смело использовать это letутверждение.

  • Если вы пишете код JavaScript на стороне клиента и используете транспортер (например, Traceur ), вы можете безопасно использовать это letутверждение, однако ваш код, вероятно, будет не оптимальным с точки зрения производительности.

  • Если вы пишете код JavaScript на стороне клиента и не используете транспортер, вам следует подумать о поддержке браузера.

Сегодня, 8 июня 2018 года, все еще есть некоторые браузеры, которые не поддерживают let!

введите описание изображения здесь


Как отслеживать поддержку браузера

Актуальный обзор того, какие браузеры поддерживают letоператор на момент прочтения этого ответа, см. На этой Can I Useстранице .


(*) Глобальные и функциональные переменные могут быть инициализированы и использованы до того, как объявлены, потому что переменные JavaScript подняты . Это означает, что объявления всегда находятся на вершине области видимости.

(**) Переменные области видимости не подняты

Автор: John Slegers Размещён: 23.02.2016 06:35

104 плюса

В принятом ответе отсутствует точка:

{
  let a = 123;
};

console.log(a); // ReferenceError: a is not defined
Автор: Lcf.vs Размещён: 02.06.2015 08:59

59 плюса

let

Блок область

Переменные, объявленные с использованием letключевого слова, имеют вид блока, что означает, что они доступны только в блоке, в котором они были объявлены.

На верхнем уровне (вне функции)

На верхнем уровне переменные, объявленные с использованием let, не создают свойств для глобального объекта.

var globalVariable = 42;
let blockScopedVariable = 43;

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

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

Внутри функции

Внутри функции (но вне блока) letимеет такую ​​же область, как 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

Внутри блока

Переменные, объявленные с использованием letвнутри блока, не могут быть доступны вне этого блока.

{
  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

Внутри петли

На переменные, объявленные с помощью letциклов in, можно ссылаться только внутри этого цикла.

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.

Петли с крышками

Если вы используете letвместо varцикла, с каждой итерацией вы получите новую переменную. Это означает, что вы можете безопасно использовать замыкание внутри цикла.

// 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);
}

Временная мертвая зона

Из-за временной мертвой зоны переменные, объявленные с использованием, letне могут быть доступны до их объявления. Попытка сделать это выдает ошибку.

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

Нет повторного объявления

Вы не можете объявить одну и ту же переменную несколько раз, используя let. Вы также не можете объявить переменную, используя letтот же идентификатор, что и другая переменная, которая была объявлена ​​с помощью 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очень похож на letблок-область и имеет TDZ. Однако есть две разные вещи.

Нет переназначения

Переменная, объявленная с использованием, constне может быть переназначена.

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

Обратите внимание, что это не означает, что значение является неизменным. Его свойства еще можно изменить.

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

Если вы хотите иметь неизменный объект, вы должны использовать Object.freeze().

Требуется инициализатор

Вы всегда должны указывать значение при объявлении переменной с помощью const.

const a; // SyntaxError: Missing initializer in const declaration
Автор: Michał Perłakowski Размещён: 23.11.2016 10:52

42 плюса

Есть некоторые тонкие различия - область letвидимости ведет себя больше как переменная область видимости в более или менее любых других языках.

Например, он распространяется на вмещающий блок, они не существуют до их объявления и т. д.

Однако стоит отметить, что letэто только часть более новых реализаций Javascript и имеет различную степень поддержки браузера .

Автор: olliej Размещён: 17.04.2009 09:38

42 плюса

Вот пример различия между этими двумя (поддержка только началась для Chrome): введите описание изображения здесь

Как вы можете видеть, var jпеременная все еще имеет значение за пределами области действия цикла for (Block Scope), но let iпеременная не определена вне области действия цикла 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 Размещён: 06.03.2015 10:41

20 плюса

  • Переменная не поднимается

    letне будет поднимать всю область блока, в котором они появляются. В отличие от этого, varможет подниматься, как показано ниже.

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

    На самом деле, Per @Bergi, оба varи letподняты .

  • Вывоз мусора

    letПолезный блок блока относится к замыканиям и сборке мусора для восстановления памяти. Рассматривать,

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

    clickОбратный вызов обработчика не нуждается в hugeDataпеременном вообще. Теоретически, после process(..)прогонов огромная структура данных hugeDataможет быть собрана мусором. Тем не менее, возможно, что некоторый движок JS все еще должен будет сохранять эту огромную структуру, так как clickфункция имеет замыкание по всей области видимости.

    Однако область видимости блока может превратить эту огромную структуру данных в сборщик мусора.

    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 петли

    letв цикле можно повторно привязать его к каждой итерации цикла, убедившись, что заново присвоить ему значение с конца предыдущей итерации цикла. Рассматривать,

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

    Однако заменить varнаlet

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

    Поскольку letсоздайте новую лексическую среду с этими именами для a) выражения инициализатора b) каждой итерации (прежде всего для вычисления выражения приращения), здесь есть больше деталей .

Автор: zangw Размещён: 17.01.2016 03:11

18 плюса

Основным отличием является различие в области видимости , в то время как let может быть доступен только внутри объявленной области видимости , как, например, в цикле for, к var можно получить доступ, например, вне цикла. Из документации в MDN (примеры также из MDN):

пусть позволяет объявлять переменные, которые ограничены в объеме на блок, заявления или выражения , на котором она используется. Это отличается от ключевого слова var , которое определяет переменную глобально или локально для всей функции независимо от области видимости блока.

Переменные, объявленные с помощью let, имеют в качестве области действия блок, в котором они определены, а также в любых вложенных субблоках. Таким образом, пусть работает очень похоже на var . Основное отличие состоит в том, что областью действия переменной var является вся включающая функция:

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

На верхнем уровне программ и функций пусть , в отличие от var , не создается свойство глобального объекта. Например:

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

При использовании внутри блока let ограничивает область действия переменной этим блоком. Обратите внимание на разницу между var , область действия которого находится внутри функции, в которой она объявлена.

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

Также не забывайте, что это функция ECMA6, поэтому она еще не полностью поддерживается, поэтому лучше всегда переносить ее на ECMA5 с помощью Babel и т. Д. ... для получения дополнительной информации о посещении веб-сайта babel

Автор: Alireza Размещён: 22.03.2017 02:39

14 плюса

Вот пример, чтобы добавить к тому, что уже написали другие. Предположим, вы хотите создать массив функций, adderFunctionsгде каждая функция принимает один аргумент Number и возвращает сумму аргумента и индекс функции в массиве. Попытка создания adderFunctionsцикла с использованием varключевого слова не будет работать так, как кто-то может наивно ожидать:

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

The process above doesn't generate the desired array of functions because i's scope extends beyond the iteration of the for block in which each function was created. Instead, at the end of the loop, the i in each function's closure refers to i's value at the end of the loop (1000) for every anonymous function in adderFunctions. This isn't what we wanted at all: we now have an array of 1000 different functions in memory with exactly the same behavior. And if we subsequently update the value of i, the mutation will affect all the adderFunctions.

However, we can try again using the let keyword:

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

This time, i is rebound on each iteration of the for loop. Each function now keeps the value of i at the time of the function's creation, and adderFunctions behaves as expected.

Now, image mixing the two behaviors and you'll probably see why it's not recommended to mix the newer let and const with the older var in the same script. Doing so can result is some spectacularly confusing code.

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

Don't let this happen to you. Use a linter.

NOTE: This is a teaching example intended to demonstrate the var/let behavior in loops and with function closures that would also be easy to understand. This would be a terrible way to add numbers. But the general technique of capturing data in anonymous function closures might be encountered in the real world in other contexts. YMMV.

Автор: abroz Размещён: 18.08.2014 12:58

11 плюса

The difference is in the scope of the variables declared with each.

In practice, there are a number of useful consequences of the difference in scope:

  1. let variables are only visible in their nearest enclosing block ({ ... }).
  2. let variables are only usable in lines of code that occur after the variable is declared (even though they are hoisted!).
  3. let variables may not be redeclared by a subsequent var or let.
  4. Global let variables are not added to the global window object.
  5. let variables are easy to use with closures (they do not cause race conditions).

The restrictions imposed by let reduce the visibility of the variables and increase the likelihood that unexpected name collisions will be found early. This makes it easier to track and reason about variables, including their reachability(helping with reclaiming unused memory).

Consequently, let variables are less likely to cause problems when used in large programs or when independently-developed frameworks are combined in new and unexpected ways.

var may still be useful if you are sure you want the single-binding effect when using a closure in a loop (#5) or for declaring externally-visible global variables in your code (#4). Use of var for exports may be supplanted if export migrates out of transpiler space and into the core language.

Examples

1. No use outside nearest enclosing block: This block of code will throw a reference error because the second use of x occurs outside of the block where it is declared with let:

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

In contrast, the same example with var works.

2. No use before declaration:
This block of code will throw a ReferenceError before the code can be run because x is used before it is declared:

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

In contrast, the same example with var parses and runs without throwing any exceptions.

3. No redeclaration: The following code demonstrates that a variable declared with let may not be redeclared later:

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

4. Globals not attached to 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. Easy use with closures: Variables declared with var do not work well with closures inside loops. Here is a simple loop that outputs the sequence of values that the variable i has at different points in time:

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

Specifically, this outputs:

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

In JavaScript we often use variables at a significantly later time than when they are created. When we demonstrate this by delaying the output with a closure passed to setTimeout:

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

... the output remains unchanged as long as we stick with let. In contrast, if we had used var i instead:

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

... the loop unexpectedly outputs "i is 5" five times:

i is 5
i is 5
i is 5
i is 5
i is 5
Автор: mormegil Размещён: 22.05.2017 01:09

10 плюса

May the following two functions show the difference:

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 Размещён: 17.12.2015 03:22

10 плюса

let is interesting, because it allows us to do something like this:

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

Which results in counting [0, 7].

Whereas

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

Only counts [0, 1].

Автор: Dmitry Размещён: 08.07.2016 12:21

8 плюса

Function VS block scope:

The main difference between var and let is that variables declared with var are function scoped. Whereas functions declared with let are block scoped. For example:

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 

variables with var:

When the first function testVar gets called the variable foo, declared with var, is still accessible outside the if statement. This variable foo would be available everywhere within the scope of the testVar function.

variables with let:

When the second function testLet gets called the variable bar, declared with let, is only accessible inside the if statement. Because variables declared with let are block scoped (where a block is the code between curly brackets e.g if{} , for{}, function{}).

let variables don't get hoisted:

Another difference between var and let is variables with declared with let don't get hoisted. An example is the best way to illustrate this behavior:

variables with let don't get hoisted:

console.log(letVar);

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

variables with var do get hoisted:

console.log(varVar);

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

Global let doesn't get attached to window:

A variable declared with let in the global scope (which is code that is not in a function) doesn't get added as a property on the global window object. For example (this code is in global scope):

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


When should let be used over var?

Use let over var whenever you can because it is simply scoped more specific. This reduces potential naming conflicts which can occur when dealing with a large number of variables. var can be used when you want a global variable explicitly to be on the window object (always consider carefully if this is really necessary).

Автор: Willem van der Veen Размещён: 09.09.2018 01:08

6 плюса

It also appears that, at least in Visual Studio 2015, TypeScript 1.5, "var" allows multiple declarations of the same variable name in a block, and "let" doesn't.

This won't generate a compile error:

var x = 1;
var x = 2;

This will:

let x = 1;
let x = 2;
Автор: RDoc Размещён: 11.08.2015 12:35

5 плюса

var is global scope (hoist-able) variable.

let and const is block scope.

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

Автор: Moslem Shahsavan Размещён: 28.10.2017 12:42

5 плюса

When Using let

The let keyword attaches the variable declaration to the scope of whatever block (commonly a { .. } pair) it's contained in. In other words,let implicitly hijacks any block's scope for its variable declaration.

let variables cannot be accessed in the window object because they cannot be globally accessed.

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

When Using var

var and variables in ES5 has scopes in functions meaning the variables are valid within the function and not outside the function itself.

var variables can be accessed in the window object because they cannot be globally accessed.

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

If you want to know more continue reading below

one of the most famous interview questions on scope also can suffice the exact use of let and var as below;

When using let

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

This is because when using let, for every loop iteration the variable is scoped and has its own copy.

When using var

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

This is because when using var, for every loop iteration the variable is scoped and has shared copy.

Автор: Ankur Soni Размещён: 22.05.2018 01:12

4 плюса

If I read the specs right then let thankfully can also be leveraged to avoid self invoking functions used to simulate private only members - a popular design pattern that decreases code readability, complicates debugging, that adds no real code protection or other benefit - except maybe satisfying someone's desire for semantics, so stop using it. /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

See 'Emulating private interfaces'

Автор: Daniel Sokolowski Размещён: 14.10.2016 05:01

3 плюса

Some hacks with 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 and setter with 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 Размещён: 21.07.2016 05:42

2 плюса

let is a part of es6. These functions will explain the difference in easy way.

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 Размещён: 17.12.2017 10:47

1 плюс

Previously there were only two scopes in JavaScript, i.e. functional and global. With 'let' keyword JavaScript has now introduced block-level variables.

To have a complete understanding of the 'let' keyword, ES6: ‘let’ keyword to declare variable in JavaScript will help.

Автор: Hitesh Garg Размещён: 08.02.2016 03:03

1 плюс

Now I think there is better scoping of variables to a block of statements using 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
}

I think people will start using let here after so that they will have similar scoping in JavaScript like other languages, Java, C#, etc.

People with not a clear understanding about scoping in JavaScript used to make the mistake earlier.

Hoisting is not supported using let.

With this approach errors present in JavaScript are getting removed.

Refer to ES6 In Depth: let and const to understand it better.

Автор: swaraj patil Размещён: 01.07.2016 08:22

1 плюс

This article clearly defines the difference between var, let and const

const is a signal that the identifier won’t be reassigned.

let, is a signal that the variable may be reassigned, such as a counter in a loop, or a value swap in an algorithm. It also signals that the variable will be used only in the block it’s defined in, which is not always the entire containing function.

var is now the weakest signal available when you define a variable in JavaScript. The variable may or may not be reassigned, and the variable may or may not be used for an entire function, or just for the purpose of a block or loop.

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

Автор: anandharshan Размещён: 27.12.2016 09:44

1 плюс

As mentioned above:

The difference is scoping. var is scoped to the nearest function block and let is scoped to the nearest enclosing block, which can be smaller than a function block. Both are global if outside any block.Lets see an example:

Example1:

In my both examples I have a function myfunc. myfunc contains a variable myvar equals to 10. In my first example I check if myvar equals to 10 (myvar==10) . If yes, I agian declare a variable myvar (now I have two myvar variables)using var keyword and assign it a new value (20). In next line I print its value on my console. After the conditional block I again print the value of myvar on my console. If you look at the output of myfunc, myvar has value equals to 20.

пусть ключевое слово

Example2: In my second example instead of using var keyword in my conditional block I declare myvar using let keyword . Now when I call myfunc I get two different outputs: myvar=20 and myvar=10.

So the difference is very simple i.e its scope.

Автор: N Randhawa Размещён: 07.08.2018 10:25

0 плюса

введите описание изображения здесь

Посмотрите на это изображение, я создал один очень простой пример для демонстрации constи letпеременных. Как вы можете видеть, когда вы пытаетесь изменить constпеременную, вы получите ошибку ( Попытка переопределить «имя», которая является константой ), но посмотрите на letпеременную ...

Сначала мы объявляем let age = 33, а затем присваиваем какое-то другое значение age = 34;, что нормально, у нас нет никаких ошибок, когда мы пытаемся изменить letпеременную

Автор: Mile Mijatovic Размещён: 16.02.2019 05:17

0 плюса

Поскольку в настоящее время я пытаюсь получить глубокое понимание JavaScript, я поделюсь своим кратким исследованием, в котором содержатся некоторые из замечательных частей, которые уже обсуждались, а также некоторые другие детали в другой перспективе.

Понимание разницы между var и let может быть проще, если мы понимаем разницу между функцией и областью действия блока .

Давайте рассмотрим следующие случаи:

(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]

когда timer()получает называется ExecutionContext создан , который будет содержать как VariableEnvironment и все LexicalEnvironments , соответствующие каждой итерации.

И простой пример

Область действия функции

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

Блок Сфера

function test() {
    for(var z = 0; z < 69; z++) {
        //todo
    }
    //z is not defined :(
}
Автор: Lucian Nut Размещён: 11.03.2019 04:52

-1 плюса

ECMAScript 6 добавил еще одно ключевое слово для объявления переменных, отличных от «const», кроме «let».

Основная цель введения «let» и «const» вместо «var» состоит в том, чтобы иметь блок-область видимости вместо традиционной лексической области видимости. Эта статья очень кратко объясняет разницу между «var» и «let», а также обсуждает «const» .

Автор: Gurucharan M K Размещён: 19.05.2016 11:41

-1 плюса

Проверить эту ссылку в MDN

let x = 1;

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

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

console.log(x);
// expected output: 1
Автор: Nurlan Размещён: 18.05.2018 07:27

-1 плюса

Я хочу связать эти ключевые слова с контекстом выполнения, потому что контекст выполнения важен во всем этом. Контекст выполнения имеет две фазы: фаза создания и фаза выполнения. Кроме того, каждый контекст выполнения имеет переменную среду и внешнюю среду (свою лексическую среду).

На этапе создания контекста выполнения var, let и const будут по-прежнему сохранять свою переменную в памяти с неопределенным значением в среде переменных данного контекста выполнения. Разница заключается в фазе исполнения. Если вы используете ссылку на переменную, определенную с помощью var, прежде чем ей будет присвоено значение, она будет просто неопределенной. Никаких исключений не будет.

Однако вы не можете ссылаться на объявленную переменную с помощью let или const, пока она не будет объявлена. Если вы попытаетесь использовать его до того, как он будет объявлен, тогда будет возникать исключительная ситуация на этапе выполнения контекста выполнения. Теперь переменная по-прежнему будет в памяти, благодаря фазе создания контекста выполнения, но механизм не позволит вам использовать ее:

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

Если переменная определена с помощью var, Engine не сможет найти переменную в переменной среде текущего контекста выполнения, то он пойдет вверх по цепочке областей действия (внешняя среда) и проверит переменную среду внешней среды. Если он не может найти его там, он продолжит поиск в Scope Chain. Это не относится к let и const.

Вторая особенность let - это ввод области блока. Блоки определяются фигурными скобками. Примеры включают функциональные блоки, блоки if, для блоков и т. Д. Когда вы объявляете переменную с помощью let inside блока, переменная доступна только внутри блока. Фактически, каждый раз, когда блок запускается, например, в цикле for, он создает новую переменную в памяти.

ES6 также вводит ключевое слово const для объявления переменных. const также является областью действия блока. Разница между let и const заключается в том, что переменные const должны быть объявлены с использованием инициализатора, иначе это вызовет ошибку.

И, наконец, когда дело доходит до контекста выполнения, переменные, определенные с помощью var, будут присоединены к объекту 'this'. В глобальном контексте выполнения это будет объект окна в браузерах. Это не относится к let или const.

Автор: Donato Размещён: 13.02.2019 04:07
Вопросы из категории :
32x32