Вернемся к основам с переменными и областью видимости
(Привет! Если вы цените содержание, которое я пишу, я был бы очень признателен, если бы вы подумали о том, чтобы стать участником Medium через мою реферальную ссылку. Теперь о том, для чего вы пришли сюда…)
В предыдущем посте я обсуждал некоторые различия между var
, let
и const
.
В этом посте мы подробнее расскажем о различиях между ними. Так что держитесь за свои консоли!
Различия между let и var
Переменную var
можно повторно объявить и обновить.
Переменная let
должна быть обновлена, но не объявлена повторно.
An example of trying to redeclare a let variable: // In editor: <script> let points = 50; let points = 60; </script> // In the console I get an error: Uncaught SyntaxError: Identifier 'points' has already been declared
Однако я могу его обновить:
let points = 50; points = 60; // In console: points // Returns: 60
Сфера аренды
Если я объявлю переменную let
в глобальной области видимости, а затем повторно объявлю ее в блоке (фигурные скобки), как в приведенном ниже примере, я не получу сообщения об ошибке в консоли, но фактически повторно объявить let
не будет.
let points = 50; let winner = false; if(points > 40) { let winner = true; } // If I call: winner // It returns the first value: false
Почему это происходит?
Поскольку let winner = false
и let winner = true
на самом деле являются двумя отдельными переменными, потому что они имеют разную область видимости, даже если у них одно и то же имя. Для пояснения:
// This 'let' is scoped to the window (globally): let winner = false; if(points > 40) { // This 'let' is scoped to the block (between the curly brackets): let winner = true; }
В приведенном выше примере, если мы изменим bothlet
variables на var
, а затем вызовем winner
в консоли, он вернет true
, потому что он не внутри функции. (Помните: var имеет область видимости функции.) Переменная var
повторно объявляется в пределах своей области видимости, которой в данном случае является окно.
let points = 50; var winner = false; if(points > 40) { var winner = true; } // If I call: winner // It now returns: true
Различия между let и const
const
переменные не могут быть обновлены. let
переменные сделаны для обновления.
// If I define the const variable: const key = 'xyz123'; // Then try to redeclare it: key = 'xyz1234' // I get the following error: Uncaught TypeError: Assignment to constant variable.
Однако есть интересная оговорка. Если я создаю const
переменную, которая является объектом, атрибуты этого объекта могут быть обновлены.
// Creating my person object: const person = { name: 'Joseph', age: 33 } // Calling person in the console: person // It returns: {name: "Joseph", age: 33} // If I then redeclare the age attribute: person.age = 34 // When I call it: person // It returns: {name: "Joseph", age: 34}
Примечание. Если я хочу сделать объект неизменяемым, я могу «заморозить» его:
const joseph = Object.freeze(person);
Если я затем попытаюсь изменить атрибут объекта person
в своей консоли, изменения не будут внесены:
// If I call: person // It returns: {name: "Joseph", age: 33} // However, if the object has been 'frozen' and I try to change the age attribute: person.age = 34 // It will immediately return: 34 // But then when I call it: person.age // It returns the original age: 33
Преимущества использования let vs. var в цикле for
Я столкнулся со многими проблемами, связанными с областью видимости с циклами for при определении i
с помощью var
. Вот где использование let
может оказаться выгодным.
// Running a for loop with var: for(var i = 0; i < 10; i++){ console.log(i); } // Returns 0 through 9 in the console, but if I call: i // It returns: 10
Другими словами, i
просочился из области видимости цикла for и теперь может быть вызван в глобальной области (или любой другой родительской области)!
Другая проблема с использованием var
в цикле for - это когда вы хотите сделать что-то в рамках цикла, но после цикл запускается. i
объявляется заново каждый раз при запуске цикла.
// Do something one second after the loop runs: for(var i = 0; i < 10; i++) { console.log(i); setTimeout(function() { console.log('The number is ' + i); }, 1000); } // If we then call i in the console it returns: 10
Опять же, переменная i
перезаписывается каждый раз при запуске цикла. К моменту выполнения setTimeout
i
будет 10.
Быстрый способ исправить это - изменить var
на let
. Поскольку let
привязан к блоку (в фигурных скобках), он будет вести себя по-другому и не будет переназначать i
каждый раз при запуске цикла:
for(let i = 0; i < 10; i++) { console.log(i); setTimeout(function() { console.log('The number is ' + i); }, 1000); } // This returns 0 through 9 in the console, then after one second logs: The number is 0 The number is 1 The number is 2 The number is 3 The number is 4 The number is 5 The number is 6 The number is 7 The number is 8 The number is 9