Вопрос

Представлен ECMAScript 6 в let заявление.

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

В чем заключаются различия?Когда следует let быть использованным более var?

Это было полезно?

Решение

Правила определения области действия

Главное отличие - это правила определения области действия.Переменные , объявленные 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.

Взгляните на этот пример из еще один вопрос stackoverflow:

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

My value: 3 каждый раз выводился на консоль 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 вызывает ошибку синтаксиса.

'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

Другие советы

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>

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

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

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

(Протестировано в Chrome и Firefox 50)

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

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

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

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

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

Support table


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

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


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

** Переменные, ограниченные областью блока, не поднимаются

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

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

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

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

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

{
  let a = 123;
};

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

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

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

Как вы можете видеть, var j переменная по-прежнему имеет значение за пределами области действия цикла for (область действия блока), но 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);

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

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

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

  • Переменная Не Подъемная

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

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

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

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

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

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

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

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

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

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

Не позволяй этому случиться с тобой.Используйте линтер.

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

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

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

  1. let переменные видны только в их ближайшее ограждающее блок ({ ... }).
  2. let переменные можно использовать только в строках кода , которые встречаются после переменная объявлена (даже если они подняты!).
  3. let переменные не могут быть повторно объявлены последующим var или let.
  4. Глобальный let переменные не добавляются в глобальную window объект.
  5. 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

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

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

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

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

(() => {
    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].

Функция ПРОТИВ области действия блока:

Основное различие между 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 вызывается переменная foo, объявленная с var, по - прежнему доступен за пределами if заявление.Эта переменная foo были бы доступны повсюду в рамках testVar функция.

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

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

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

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

переменные с let не надо поднимись на руки:

console.log(letVar);

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

переменные с var делай поднимись на руки:

console.log(varVar);

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

Глобальный 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 закончился var всякий раз, когда вы можете, потому что это просто более конкретная область.Это уменьшает потенциальные конфликты именования, которые могут возникнуть при работе с большим количеством переменных. var может быть использован, когда вы хотите, чтобы глобальная переменная явно находилась на window возражайте (всегда тщательно обдумывайте, действительно ли это необходимо).

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

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

var x = 1;
var x = 2;

Это будет:

let x = 1;
let x = 2;

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

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

В let ключевое слово привязывает объявление переменной к области действия любого блока (обычно это { .. } пара), в которой он содержится.Другими словами,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, для каждой итерации цикла переменная ограничена и имеет общую копию.

Если я правильно прочитаю спецификации, то 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

Видишь 'Эмуляция частных интерфейсов'

Несколько взломов с 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"

Добытчик и установщик с 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)

let против var.Это все о область применения.

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

Смотрите мой пример ниже и обратите внимание, как переменная lion (let) действует по-разному в двух console.logs;это выходит за рамки 2-го console.log.

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

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

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

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

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

let является частью 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
}

Ранее в JavaScript было только две области, т. е.функциональный и глобальный.С помощью 'let' ключевое слово JavaScript теперь введено block-level переменные.

Чтобы иметь полное представление о ключевом слове 'let', ES6:ключевое слово ‘let’ для объявления переменной в JavaScript поможет.

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

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

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

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

Обратитесь к ES6 В Глубину:пусть и const чтобы лучше это понять.

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

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

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

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

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

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

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

Пример 1:

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

let keyword

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

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

enter image description here

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

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

Я думаю, что термины и большинство примеров немного ошеломляют, Основная проблема, с которой я столкнулся лично в связи с различием, заключается в понимании того, что такое "Блок".В какой-то момент я понял, что блоком будут любые фигурные скобки, за исключением 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);

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

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

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

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

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

Область применения функции

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 :(
}

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

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

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

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

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

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top