Введение

Почему я пишу эту серию:

  1. Я отправляюсь в путешествие, чтобы прочитать весь раздел JavaScript в MDN, включая руководства и ссылки. Я хочу задокументировать то, что я узнал для себя. В то же время я хочу поделиться ею со всеми, кто может быть заинтересован в мельчайших подробностях JavaScript.
  2. Чтобы улучшить свои технические навыки письма. Я надеюсь выработать привычку часто писать. Мне всегда хотелось писать больше, но я всегда слишком критично отношусь к своим произведениям и никогда их не публикую. В этой серии все статьи будут написаны в один присест, и выпустить ее вне зависимости от того, доволен ли я качеством написания. Это означает, что качество моих статей может быть значительно улучшено. Если я не заставлю себя немедленно опубликоваться, я знаю, что перфекционисту во мне потребуется вечность, чтобы редактировать и переписывать одну и ту же статью до скончания века. Тем не менее, я приветствую любые конструктивные отзывы или исправление фактов.

В ближайшие недели я намерен прочитать MDN, а также задокументировать некоторые жемчужины, которые я нашел по пути.

Зачем читать MDN?

Я не новичок в JavaScript, я сделал множество проектов с его использованием. Тем не менее, я думаю, что стоит вернуться к основам. Чтобы быть хорошим фронтенд-инженером (по моему скромному определению), я должен быть знаком с моими торговыми инструментами, в том числе с тем, на что способен JavaScript.
Если мы не читаем MDN, мы всегда будем учиться. новый синтаксис и возможности JavaScript от копирования и вставки кода переполнения стека. Я надеюсь стать одной из легенд, которые однажды ответят на вопросы людей о stackoverflow.

Чего ждать от прочтения этой серии

Эта серия не предназначена для того, чтобы научить вас основам JavaScript. Я выделяю концепции, которые, по моему мнению, стоит записать, вещи, которые, возможно, должен знать фронтенд-инженер среднего и выше уровня. Тем не менее, я думаю, что это полезно для начинающих, чтобы углубить свои знания JavaScript, а также для опытных инженеров, чтобы вспомнить или узнать что-то необычное, с чем они, возможно, не сталкивались.

Gem 1 — var vs let vs const

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

Основная концепция

Вопрос: Будет ли это вызывать ошибку?

// example.js
foo = 1;
let foo;

Ответ: Да, если вы запускаете node example.js локально. Выдает ошибку ReferenceError: Cannot access 'a' before initialization at Object.<anonymous>. Однако, если вы попробуете это сделать в консоли разработчика, это не вызовет ошибки, но foo будет неопределенным, несмотря на то, что ранее вы присвоили foo значение 1.

Как насчет этого? Это тоже выдаст ошибку?

// example.js
foo = 1;
var foo;

Ответ: Нет, ошибки не будет. Это странно, не так ли? Причина этого в «подъеме». Для компилятора, читающего ваш код, они видят его как

// example.js
var foo;
foo = 1;

Вы можете понять подъем просто как «компилятор перемещает объявление переменной наверх».

Подъем

Круто, это легко понять. Давайте посмотрим на следующий фрагмент кода.

function eat() {
	console.log(food); // what will this output?
	var food = 'sandwich';
	console.log(food); // what will this output?
}
eat();

Что выведет первый и второй журнал консоли?

Кто-то может предположить, что ответ будет «оба выведут сэндвич со строками». Это неверно. Это вопрос с подвохом. Одно из заблуждений, которое может возникнуть у некоторых относительно подъема, заключается в том, что они не знают, что именно поднимается. Если вы посмотрите на мое объяснение подъема выше, ключевое слово заключается в том, что декларация перемещается наверх. Следовательно, фрагмент кода может быть переведен в следующее

function eat() {
	var food;
	console.log(food); // what will this output?
	food = 'sandwich';
	console.log(food); // what will this output?
}
eat();

Это означает, что первый журнал консоли выведет «undefined», а второй журнал консоли выведет «бутерброд».

Каковы последствия этого? Ну, в нашем примере выше функция eat имеет только 3 строки кода, вы можете легко визуально проверить, что console.log(food) вызывается еще до того, как food будет объявлено. Однако в реальном мире ваш код потенциально может быть намного длиннее, что может быть довольно распространенным явлением, если вы работаете над большим проектом. Это означает, что вы можете случайно использовать ее до объявления food, что может быть проблематично, поскольку вы можете ожидать, что переменная будет содержать значение, но вместо этого она содержит undefined, что приведет к неожиданному поведению. С другой стороны, если вы используете let или const, будет выдана ошибка времени выполнения, Uncaught Reference Error: foo is not defined at ....

Глобальный контекст

В консоли разработчика попробуйте следующее

var foo = 'hello';
this.foo;

Что он возвращает? Он возвращает «привет». Это связано с тем, что объявления var верхнего уровня добавляются к глобальному объекту (в данном случае к объекту окна, вы также можете попробовать window.foo, и он вернет вам тот же результат).

Обратите внимание, что в NodeJS, т. е. когда вы запускаете node someJSfile.js, вы можете включать модули, например. const foo = require('./foo'), если вы определите переменную в файле foo.js, она будет ограничена только этим файлом (или модулем), вы не сможете получить доступ к переменной в someJSfile.js. В этом случае переменная не привязана к глобальному объекту.

Каковы последствия этого? Что ж, если вы просто работаете с ванильным JavaScript, HTML и CSS, возможно, вам следует принять это к сведению. Поскольку переменные верхнего уровня var могут быть случайно добавлены в глобальную область видимости и вызвать непредвиденные ошибки.

Повторно объявить ту же переменную var без ошибок

Вопрос: Будет ли это вызывать ошибку?

var food = 'sandwich'
console.log(food);
var food = 'bread'
console.log(food);

Повторное объявление переменной, даже var, скажем, в консоли разработчика, выдаст ошибку Uncaught SyntaxError: Identifier 'food' has already been declared at <anonymous> Однако, если вы запустите ее в nodejs, она не выдаст ошибку. Это означает, что вы можете случайно переопределить ранее объявленную переменную food, что может вызвать ошибки.

С другой стороны, let и const не будут переопределены, как показано в приведенном ниже примере.

let foo = 10;
{
	let foo = 20;
	console.log(foo); // outputs 20
}
console.log(foo); // outputs 10

Тогда как для var это будет следующим образом

var foo = 10;
{
	var foo = 20;
	console.log(foo); // outputs 20
}
console.log(foo); // outputs 20

Каковы последствия этого? Ну, вы бы не хотели переопределять ранее объявленные переменные с тем же именем.

Еда на вынос

Теперь, когда вы знаете о странном поведении var, вы можете спросить себя, почему он вообще существует? Это хороший вопрос, если вы знаете, дайте мне знать в комментариях 🙂. Лично я думаю, что он существует по причинам обратной совместимости. Я думаю, что let и const делают написание кода более предсказуемым, что приводит к меньшему количеству непредвиденных ошибок. Эмпирическое правило заключается в следующем: используйте const, когда это возможно, и используйте let только в случае крайней необходимости, не используйте var, если у вас нет черного чувства юмора.

Рекомендации

Вы можете узнать больше о var в этих статьях на MDN.