Какая разница между использованием "let" и "var"?

ECMAScript 6 представил оператор let.

Я слышал, что она описывается как "локальная" переменная, но я все еще не совсем уверен, как она ведет себя иначе, чем ключевое слово var.

Какие есть отличия? Когда следует let использовать над var?

Ответ 1

Общие правила

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

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

  console.log(foo, bar);

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

  console.log(baz); // ReferenceError
}

run();

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

Взгляните на этот пример из fooobar.com/questions/166/...:

var funcs = [];
// let 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 run each one to see
  funcs[j]();
}

My value: 3 выводился на консоль каждый раз, когда вызывался funcs[j]();, поскольку анонимные функции были связаны с одной и той же переменной.

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

Подъемно

В то время как переменные, объявленные с ключевым словом var, "подняты" в верхнюю часть блока, что означает, что они доступны в своей области охвата даже до того, как они объявлены:

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

run();

пусть переменные не инициализируются, пока их определение не будет оценено. Доступ к ним до инициализации приводит к ReferenceError. Считается, что переменная находится в "временной мертвой зоне" от начала блока до обработки инициализации.

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

checkHoisting();

Создание глобального свойства объекта

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

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

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

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

В строгом режиме var позволит вам повторно объявить одну и ту же переменную в той же области, в то время как let вызывает ошибку 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

Ответ 2

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

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>

Ответ 3

В чем разница между 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 или babel-standalone), вы можете смело использовать оператор let, однако ваш код скорее всего будет не оптимальным с точки зрения производительности.

  • Если вы пишете код JavaScript на стороне клиента и используете транспортер на основе Node (например, скрипт оболочки traceur или Babel), вы можете смело использовать оператор let. А поскольку ваш браузер будет знать только о переданном коде, недостатки производительности должны быть ограничены.

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

    Есть еще некоторые браузеры, которые вообще не поддерживают let:

Support table


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

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


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

** Переменные области видимости не отображаются

Ответ 4

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

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

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

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

Ответ 5

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

{
  let a = 123;
};

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

Ответ 6

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 -it в блочном пространстве и имеет 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

Ответ 7

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

Как вы можете видеть, переменная 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);

Ответ 8

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

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

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

Ответ 9

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

let позволяет вам объявлять переменные, ограниченные по объему блоком, оператором или выражением, в котором он используется. Это отличается от ключевого слова 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
}'

На верхнем уровне программ и функций let, в отличие от 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

Ответ 10

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

    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) каждая итерация (предшествующая оценке выражения инкремента), более подробная информация здесь.

Ответ 11

Вот пример, чтобы добавить к тому, что уже написаны другие. Предположим, вы хотите создать массив функций 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

Вышеописанный процесс не генерирует желаемый массив функций, поскольку область i выходит за пределы итерации блока for, в котором каждая функция была создана. Вместо этого в конце цикла i в каждом закрытии функции ссылается на значение i в конце цикла (1000) для каждой анонимной функции в adderFunctions. Это совсем не то, чего мы хотели: теперь у нас есть массив из 1000 различных функций в памяти с точно таким же поведением. И если мы впоследствии обновим значение i, мутация повлияет на все adderFunctions.

Однако мы можем попробовать снова с помощью ключевого слова let:

// Let 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 scope doesn't extend outside the for loop.
console.log(i); // => ReferenceError: i is not defined

На этот раз i восстанавливается на каждой итерации цикла for. Каждая функция теперь сохраняет значение i во время создания функции, а adderFunctions ведет себя как ожидалось.

Теперь изображение смешивает два поведения, и вы, вероятно, увидите, почему не рекомендуется смешивать новые let и const со старыми var в том же script. Это может привести к некоторому эффектно запутанному коду.

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

Не позволяйте этому случиться с вами. Используйте linter.

ПРИМЕЧАНИЕ.. Это пример обучения, призванный продемонстрировать поведение var/let в циклах и закрытие функций, которые также будут легко понятны. Это был бы ужасный способ добавить числа. Но общая техника захвата данных при закрытии анонимных функций может встречаться в реальном мире в других контекстах. YMMV.

Ответ 12

Разница заключается в scope переменных, объявленных с каждым.

На практике существует ряд полезных последствий разницы в области:

  • let переменные видны только в ближайшем закрывающем блоке ({ ... }).
  • let переменные используются только в строках кода, которые появляются после объявления переменной (даже если они подняты!).
  • let переменные не могут быть переопределены с помощью следующих var или let.
  • Глобальные переменные let не добавляются к глобальному объекту window.
  • let переменные просты в использовании с закрытием (они не вызывают условия гонки).

Ограничения, налагаемые let, уменьшают видимость переменных и увеличивают вероятность того, что неожиданные столкновения имен будут найдены раньше. Это облегчает отслеживание и использование переменных, в том числе достижимость (помогая восстановить неиспользуемую память).

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

var может по-прежнему быть полезным, если вы уверены, что хотите использовать односвязную функцию при использовании замыкания в цикле (# 5) или для объявления внешне видимых глобальных переменных в вашем коде (# 4). Использование var для экспорта может быть вытеснено, если export мигрирует из пространства транспилера и на основной язык.

Примеры

1. Не использовать внешний ближайший закрывающий блок: Этот блок кода выдает опорную ошибку, потому что второе использование x происходит за пределами блока, где объявлено с помощью let:

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

Напротив, работает тот же пример с var.

2. Не использовать до объявления:
Этот блок кода выдаст ReferenceError до того, как код будет запущен, поскольку x используется до его объявления:

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

В отличие от этого, тот же пример с var анализирует и работает без каких-либо исключений.

3. Нет переоформления: Следующий код демонстрирует, что переменная, объявленная с помощью let, не может быть повторно описана позже:

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

4. Глобалы, не привязанные к 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. Простое использование с затворами: Переменные, объявленные с помощью var, не работают хорошо с замыканиями внутри циклов. Вот простой цикл, который выводит последовательность значений, которые переменная i имеет в разные моменты времени:

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

В частности, это выдает:

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

В JavaScript мы часто используем переменные значительно позже, чем когда они созданы. Когда мы это продемонстрируем, задерживая выход с замыканием, переданным на setTimeout:

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

... выход остается неизменным, пока мы придерживаемся let. Напротив, если бы мы использовали var i:

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

... цикл неожиданно выводит "i 5" пять раз:

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

Ответ 13

Могут отображаться следующие две функции:

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
}

Ответ 14

let интересен, поскольку он позволяет нам сделать что-то вроде этого:

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

Это приводит к подсчету [0, 7].

В то время как

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

Учитывается только [0, 1].

Ответ 15

Область действия VS-блока:

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

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 

переменные с var :

Когда первая функция testVar получает testVar переменную foo, объявленную с помощью var, все еще доступна вне оператора if. Эта переменная foo будет доступна везде в рамках функции testVar.

переменные с let :

Когда вторая функция testLet переменная bar, объявленная с let, доступна только внутри оператора if. Поскольку переменные, объявленные с let являются блочными (где блок является кодом между фигурными скобками, например if{}, for{}, function{}).

let переменные не поднимаются:

Другое различие между var и let - переменные с объявленными, и let их не поднимают. Пример - лучший способ проиллюстрировать это поведение:

переменные с let not let hoisted:

console.log(letVar);

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

переменные с var do get hoist:

console.log(varVar);

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

Global let не привязывается к window:

Переменная, объявленная с let в глобальной области (которая является кодом, который не находится в функции), не добавляется как свойство в глобальном объекте window. Например (этот код находится в глобальной области):

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


Когда следует let использовать над var?

Используйте let over var всякий раз, когда вы можете, потому что он просто ограничен более конкретным. Это уменьшает потенциальные конфликты именования, которые могут возникать при работе с большим количеством переменных. var можно использовать, если вы хотите, чтобы глобальная переменная явно была на объекте window (всегда внимательно изучите, если это действительно необходимо).

Ответ 16

Также представляется, что, по крайней мере, в Visual Studio 2015, TypeScript 1.5, "var" допускает несколько объявлений с одним и тем же именем переменной в блоке, а "let" - нет.

Это не приведет к ошибке компиляции:

var x = 1;
var x = 2;

Это будет:

let x = 1;
let x = 2;

Ответ 17

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

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

Смотрите " Эмуляция частных интерфейсов ".

Ответ 18

var - глобальная переменная (возможность подъема).

let и const - область действия блока.

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

Ответ 19

При использовании let

Ключевое слово let присоединяет объявление переменной к какому-либо блоку (обычно a { .. }), в котором он содержится. Другими словами, let неявно захватывает любую область блока для объявления переменной.

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

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

При использовании var

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

var можно получить доступ к объектам window, потому что они не могут быть доступны по всему миру.

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

Если вы хотите узнать больше, продолжайте читать ниже

один из самых известных вопросов интервью по области также может быть достаточным для точного использования let и var, как показано ниже:

При использовании let

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

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

При использовании var

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

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

Ответ 20

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

Я знаю, что не тот ответ, который вы искали, но это, вероятно, самое важное. Если у вас ограниченное развертывание, где вы знаете, что каждый получает 1,7, то вы счастливый парень.

Ответ 21

Некоторые хаки с 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 и setter с 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)

Ответ 22

пусть против вар. Все дело в сфере.

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

Посмотрите мой пример ниже и обратите внимание, как переменная lion (let) действует по-разному в двух console.logs; это выходит из области видимости во втором 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.

Ответ 23

let является частью es6. Эти функции объяснят разницу легким способом.

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
}

Ответ 25

Теперь я думаю, что лучше использовать область видимости переменных для блока операторов с помощью 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
}

Я думаю, что люди начнут использовать let here after, чтобы они имели аналогичную область видимости в JavaScript, как и другие языки, Java, С# и т.д.

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

Подъем не поддерживается с помощью let.

При таком подходе ошибки, возникающие в JavaScript, удаляются.

Обратитесь к ES6 In Depth: let и const, чтобы лучше понять его.

Ответ 26

В этой статье четко определена разница между var, let и const

const - это сигнал, что идентификатор не будет переназначен.

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

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

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

Ответ 27

Как уже упоминалось выше:

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

Example1:

В обоих моих примерах у меня есть функция myfunc. myfunc содержит переменную myvar 10. В моем первом примере я проверяю, равен ли myvar 10 (myvar==10). Если да, я agian объявляю переменную myvar (теперь у меня есть две переменные myvar), используя ключевое слово var и присваиваю ему новое значение (20). В следующей строке я напечатаю его значение на моей консоли. После условного блока я снова распечатываю значение myvar на моей консоли. Если вы посмотрите на выход myfunc, myvar имеет значение равное 20.

let keyword

Пример2: В моем втором примере вместо использования ключевого слова var в моем условном блоке объявляю myvar используя ключевое слово let. Теперь, когда я вызываю myfunc я получаю два разных выхода: myvar=20 и myvar=10.

Таким образом, разница очень проста, т.е. ее объем.

Ответ 28

enter image description here

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

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

Ответ 29

Поскольку в настоящее время я пытаюсь получить глубокое понимание 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(let z = 0; z < 69; z++) {
        //todo
    }
    //z is not defined :(
}

Ответ 30

Я думаю, что термины и большинство примеров немного ошеломляют. Основная проблема, с которой я столкнулся лично, - это понимание, что такое "Блок". В какой-то момент я понял, что блоком будут любые фигурные скобки, кроме оператора IF. открывающая скобка { функции или цикла определит новый блок, все, что определено с помощью let внутри него, не будет доступно после закрывающей скобки } того же самого элемента (функции или цикла); Имея это в виду, было легче понять:

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