Вступление
Подъем - это поведение JavaScript, обычно известное тем, что делает переменные и функции доступными для использования до того, как переменной будет присвоено значение или определена функция. Фактически, он помещает объявления переменных, функций и классов в верхнюю часть их области видимости (глобальной области или функции) перед выполнением.
На самом деле JavaScript не перемещает и не добавляет код в объявления подъема. Эти объявления помещаются в память на этапе компиляции интерпретатора, делая их доступными до выполнения кода.
В этой статье мы узнаем о подъеме и о том, как он влияет на переменные, функции и классы.
Подъемные переменные
Одним из ключевых аспектов подъема является то, что объявление помещается в память, а не значение.
Посмотрим на пример:
console.log(name); // Prints undefined, as only declaration was hoisted
var name = "John";
console.log(name); // Prints "John"
Это происходит потому, что JavaScript видит, что у нас есть name
переменной в области видимости, и помещает его в память. Переменным,
объявленным с помощью var
, присваивается значение undefined
пока им
не будет присвоено другое значение.
Переменный подъем с помощью let и const
Разработчики JavaScript редко используют var
в пользу let
и const
представленных в ECMAScript 2015 (обычно называемых ES6). Поднимаются
переменные, объявленные с помощью let
и const
. Однако они не
инициализируются undefined
значением или каким-либо другим значением.
Следовательно, если они используются до инициализации, мы получим
ReferenceError
.
Давайте повторно воспользуемся тем же примером, но let
использовать
let вместо var
:
console.log(name); // Uncaught ReferenceError: Cannot access 'name' before initialization
let name = "John";
console.log(name);
Приведенный выше код вызывает ошибку ReferenceError
в первой строке и
завершает выполнение.
const
было добавлено для введения неизменяемых значений в JavaScript -
значений, которые нельзя изменить после его инициализации. Таким
образом, при использовании const
мы должны объявить и присвоить
значение переменной. Если мы этого не сделаем, мы получим SyntaxError
:
console.log(name); // Uncaught SyntaxError: Missing initializer in const declaration
const name;
И, как и let
, мы получаем ReferenceError
когда пытаемся
использовать константу до ее инициализации:
console.log(name); // Uncaught ReferenceError: Cannot access 'name' before initialization
const name = "John";
console.log(name);
Подъемные функции
Объявления функций подняты в JavaScript. Объявление функции начинается с
ключевого слова function
, за которым следует ее имя и аргументы в
скобках, а затем ее тело. Рассмотрим следующий код:
let first_name = "Stack";
let last_name = "Abuse";
let result = concat(first_name, last_name);
console.log(result); // StackAbuse
function concat(x, y) {
return x + y;
}
Как и в случае с переменными, JavaScript помещает функцию в память перед
выполнением кода в этой области. Следовательно, подъем позволяет нам
вызывать concat()
до того, как она будет определена позже в коде.
Пока объявления функций поднимаются, функциональные выражения работают иначе. Выражение функции - это когда мы назначаем переменную функции. Например, приведенный ниже код вернет ошибку:
func_express(); // TypeError: func_express is not a function
var func_express = function () {
console.log('This the function expression is not a function');
};
JavaScript возвращает TypeError
потому что, в отличие от объявления
функции, была поднята только переменная. Когда переменные, объявленные с
помощью var
, поднимаются, им присваивается значение по умолчанию
undefined
. Затем JavaScript выдает ошибку, потому что значение
переменной в этот момент времени не является функцией.
Подъем функций с помощью стрелочных функций
ECMA2015 представил новый способ создания анонимных функций, стрелочные
функции. Они определяются парой скобок, содержащей 0 или более
аргументов, стрелкой =>
и телом функции в фигурных скобках. Что
касается подъема, они действуют как другие функции. Например:
arrow_func_express(); // TypeError: arrow_func_express is not a function
var arrow_func_express = () => {
console.log('This the arrow function is not a function');
};
При использовании стрелочных функций или любого другого функционального выражения мы всегда должны определять функцию, прежде чем использовать ее в нашем коде. Это правильный способ использования выражения функции:
let arrow_func_express = () => {
console.log('This function expression will work');
};
arrow_func_express(); // This function expression will work
Подъемные классы
Объявления классов подняты в JavaScript. Объявление класса не инициализируется при поднятии. Это означает, что хотя JavaScript может найти ссылку на созданный нами класс, он не может использовать этот класс до того, как он будет определен в коде.
Возьмем следующий пример, который вызывает ошибку при попытке доступа к классу до его определения:
var person = new Person();
person.name = "Jane";
person.age = 25;
console.log(person); // Uncaught ReferenceError: Cannot access 'Person' before initialization"
class Person {
constructor(name, age) {
this.name = name; this.age = age;
}
}
ReferenceError
аналогична тому, что происходит, когда мы пытаемся
получить доступ к переменной, объявленной с помощью let
или const
до
ее инициализации в нашем скрипте.
Выражения класса, в которых мы назначаем определение класса переменной, ведут себя аналогично выражениям функций. Поднимаются их объявления, но не их присвоенное значение.
Давайте возьмем наш предыдущий пример и вместо этого воспользуемся выражением класса:
var person = new Person();
person.name = "Jane";
person.age = 25;
console.log(person); // Uncaught TypeError: Person is not a constructor"
var Person = class {
constructor(name, age) {
this.name = name;
this.age = age;
}
}
Когда переменная Person
поднимается, ей присваивается значение
undefined
. Поскольку мы не можем использовать undefined
значение в
качестве класса, JavaScript выдает TypeError
.
При работе с объявлениями классов или выражениями классов мы всегда должны определять класс раньше в нашем коде, чтобы использовать его. Правильный способ использования класса следующий:
class Person {
constructor(name, age) {
this.name = name; this.age = age;
}
}
var person = new Person();
person.name = "Jane";
person.age = 25;
console.log(stack); // Person { name: 'Jane', age: 25 }
Заключение
Подъемы JavaScript, объявления переменных, функций и классов. В этой статье показано влияние подъема на то, как мы пишем код JavaScript.
Объявления функций могут использоваться до их определения из-за подъема.
Однако, чтобы свести к минимуму наши шансы получить undefined
значения, а также ошибки ссылок или типов, безопаснее использовать
переменные, выражения функций и классы после того, как они определены в
нашем коде.