Изучение области видимости в JavaScript
Подъем - это механизм JavaScript, в котором объявления переменных с использованием var
поднимаются / поднимаются в верхнюю часть своей области видимости (в верхнюю часть своей функциональной / локальной области, если они объявлены внутри function или в верхнюю часть своей глобальной области видимости, если они объявлены вне функции), как только JavaScript скомпилирует весь ваш код.
Важно отметить, что подъем перемещает только объявление. Задания остаются на месте.
Давайте рассмотрим пример, чтобы продемонстрировать влияние подъема.
console.log(hoist); var hoist = 'This variable has been hoisted.';
Как вы думаете, какой будет результат?
Uncaught ReferenceError: hoist is not defined
This variable has been hoisted.
undefined
Большинство из вас выберут первый вариант, но оказывается, что третий вариант верен, поскольку при подъеме объявление перемещается наверх, а присвоения остаются на месте.
Приведенный выше код такой же, как:
var hoist; console.log(hoist); // undefined hoist = 'This variable has been hoisted';
Давайте возьмем другой пример и посмотрим, как поднимаются переменные в области видимости функции:
function hoist() { console.log(message); var message = 'Hoisting is done.'; } hoist();
Если вы угадали undefined
, вы правы.
Вот как интерпретатор видит приведенный выше код:
function hoist() { var message; console.log(message); // undefined message = 'Hoisting is done'; } hoist(); // undefined
Объявление переменной var message
, областью действия которой является функция hoist()
, поднимается в верхнюю часть функции.
Правильный способ выглядит следующим образом:
function hoist() { var message = 'This avoids the above pitfall.'; console.log(message); } hoist(); // This avoids the above pitfall.
Подъемные функции
Подъем также перемещает объявления функций, но они идут на самый верх и, следовательно, будут располагаться над всеми объявлениями переменных.
Если вы когда-нибудь задавались вопросом, почему вы могли вызывать функции до того, как записали их в свой код, волшебство творится с помощью подъема.
hoisted(); // This function has been hoisted. function hoisted() { console.log('This function has been hoisted'); }
Однако функциональные выражения не поднимаются.
expression(); // TypeError: expression is not a function. var expression = function() { console.log('This function has been hoisted'); }
Возьмем другой пример:
function foo() { function bar() { return 'bar1'; } return bar(); function bar() { return 'bar2'; } } foo();
Угадайте результат?
Результат - bar2
. Будет поднята первая функция внутри foo
. Точно так же второе объявление функции также поднимется наверх. Поскольку обе функции имеют одинаковое имя, второе объявление функции заменит первое. Следовательно, при выполнении будет вызываться bar
, вторая функция.
Но как насчет let и const?
Они также поднимаются - фактически поднимаются объявления var
, let
, const
, function
и class
.
позволять
Переменные, объявленные с ключевым словом let
, являются блочными, а не функциональными. Это просто означает, что область видимости переменной привязана к блоку, в котором она объявлена, а не к функции, в которой она объявлена.
console.log(hoist); // ReferenceError: hoist is not defined let hoist = 'This variable has been hoisted';
Подобно ключевому слову var
, мы ожидаем, что вывод журнала будет undefined
.
Экземпляры var
и let
могут быть инициализированы без значения (и если вы попытаетесь вызвать его, он вернет undefined
).
let hoist; console.log(hoist); // undefined hoist = 'This variable has been hoisted.';
Const
Ключевое слово const
было введено в es6, чтобы разрешить неизменяемые переменные. В const
, как и в let
, переменная поднимается в верхнюю часть блока.
console.log(hoist); // ReferenceError: hoist is not defined const hoist = 'This variable has been hoisted';
Но в отличие от let
и var
, мы не можем инициализировать const
без значения. Если вы попытаетесь это сделать, он выдаст Error
.
const hoist; console.log(hoist); // SyntaxError: Missing initializer in the const declaration; hoist = 'This variable has been hoisted';
Следовательно, const
и let
должны быть объявлены и инициализированы перед использованием.
const foo = 'Hey, I'm foo!'; console.log(foo); // Hey, I'm foo! let bar = 'Hey, I'm bar!'; console.log(bar); // Hey, I'm bar!
Подъемные классы
Объявление класса
Также поднимаются объявления классов JavaScript. Однако они остаются неинициализированными до оценки.
var foo = new bar(); foo.height = 100; foo.weight = 100; console.log(foo); // Guess the output? class bar { constructor(height, weight) { this.height = height; this.weight = weight; } }
Если вы угадали undefined
, то на этот раз ошиблись. Результат - ReferenceError: foo is not defined
. Почему? bar
использовался перед объявлением, что недопустимо для переменных класса.
class bar { constructor(height, weight) { this.height = height; this.weight = weight; } } var foo = new bar(); foo.height = 100; foo.weight = 100; console.log(foo); // { height: 100, weight: 100 }
Выражения класса
Выражения класса не поднимаются.
var Square = new Polygon();
Square.height = 10;
Square.width = 10;
console.log(Square); // TypeError: Polygon is not a constructor
var Polygon = class Polygon {
constructor(height, width) {
this.height = height;
this.width = width;
}
};
Правильный способ сделать это:
var Polygon = class Polygon {
constructor(height, width) {
this.height = height;
this.width = width;
}
};
var Square = new Polygon();
Square.height = 10;
Square.width = 10;
console.log(Square);
Заключение
Мы должны сделать привычкой объявлять и инициализировать переменные, классы и функции JavaScript перед использованием.
Ссылка: https://scotch.io/tutorials/understanding-hoisting-in-javascript