Автор оригинала: FreeCodeCamp Community Member.
Tiago Romero Garcia
Могу поспорить, что любой JavaScript разработчик захочет лучшего понимания концепций охвата и подъема. Они могут молча создавать эти страшные необъяснимые проблемы, также известные как побочные эффекты.
В двух словах, охватившихся и подъемное влияние, как код, который мы пишете, будут иметь дело с нашими объявлениями (например, var, Пусть , Const и Функция ).
Давайте начнем наш реконструкцию с первым из них: var Отказ
Работа с Вар
При использовании var Чтобы объявить вашим переменным, родительскую функцию, где вы объявляете ваши варианты внутри, является вашим единственным де-факто разделитель области. Таким образом, родительская функция создает и удерживает объем для всех локальных переменных, объявленных внутри себя.
Другими словами, внутри родительской функции рождаются локальные переменные, они выполняют свою работу, и когда заканчивается выполнение функции, они также выделяют (если они не передаются какой-либо другой функции, которая переносит родительскую функцию).
Это определение Локальный объем. А против Глобальный спектр , когда переменные объявлены вне вашей функции. Они доступны всеми и везде. Они всеможены, как воздух, который мы дышим, или как окно объект в браузере.
Следовательно, другие кодовые блоки как условные и петли (такие как если , для , в то время как , выключатель и попробуйте ) Не разделить объем, в отличие от большинства других языков.
Тогда любой var Внутри этих блоков будет выделен в пределах их родительской функции, которая содержит этот блок.
Не только это, но во время выполнения, каждый var Декларация, находящаяся внутри таких блоков кода, получает перемещение в начало своей родительской функции (его объем). Это определение Подъем Отказ
Это так, ты не должен объявить var В блоке и подумайте это var не протекает снаружи, потому что это может быть!
Вот пример:
function stepSum() { var total = 0; for (var i = 0; i < arguments.length; i++) { var parameter = arguments[i]; total += parameter; console.log(`${i}) adding ${parameter}`); } // outside the loop, we can still access vars i and parameter // even though the were declared within the for loop console.log(`i=${i}, parameter=${parameter}`); return total;}console.log(`total=${stepSum(3, 2, 1)}`);Вывод:
0) adding 31) adding 22) adding 1i=3, parameter=1total=6
Здесь мы можем наблюдать, что варс i и параметр утечка, так как они оба могут быть доступны из родительской функции. Это потому, что они были подняты там, просто если бы они были объявлены, как это:
function stepSum() { var total = 0; var i; var parameter; for (i = 0; i < arguments.length; i++) { parameter = arguments[i]; total += parameter; console.log(`${i}) adding ${parameter}`); } console.log(`i=${i}, parameter=${parameter}`); return total;}console.log(`total=${stepSum(3, 2, 1)}`);Чтобы избежать каких-либо путаницы, это обычная практика для объявления VARS в первых строчках родительской функции. Это сделано, чтобы избежать ложных ожиданий для любого var Что может быть объявлено где-то вниз по функции, но оказалось, что придерживалось ценности до этого.
Это источник путаницы для программистов, исходящих из языков с помощью блока (например, C или Java). Они обычно объявляют свои варианты, когда они собираются сделать их первое использование.
Проблемы с var.
Давайте рассмотрим этот фрагмент кода. Это похоже на последний, за исключением того, что он вычисляет каждую сумму асинхронно:
function stepSum() { var total = 0; for (var i = 0; i < arguments.length; i++) { var parameter = arguments[i]; setTimeout(function() { total += parameter; console.log(`${i}) adding ${parameter}, total=${total}`); }, i*1000); }}stepSum(3, 2, 1);
Вывод:
3) adding 1, total=13) adding 1, total=23) adding 1, total=3
Почему так случилось? Он подводят только последний параметр 1, в течение трех раз. А также подсчет шага всегда находится на 3, где мы ожидаем увидеть 1, 2 и 3. Что здесь не так?
Ответ следует: Варс Я и параметр получил лапы до начала Штурм Функция, и теперь они доступны для всей родительской функции. Более того, параметр На самом деле определяется только один раз, а затем он перенаправляется на каждую итерацию для цикла.
Учитывая, что мы используем Сетримс Звонит здесь, мы можем ожидать, что когда эта функция выполняется впервые (через секунду), Штурм Функция будет уже закончена. Итак, параметр в конечном итоге со значением его последнего назначения, которое является последней итерацией цикла для цикла, когда он был установлен на 1. То же самое с Я заканчивая со значением 3.
Вот почему эти значения поднимаются, когда 3 Сетримс Звонки в конечном итоге выполняются.
Как мы можем исправить это? Просто сделав хорошее использование навеса и подъема. Мы можем предоставить новую функцию, чтобы защитить i и параметр от переназначения. Это создает локальный объем только для них. Возможно, используя что-то другое, чем VAR, которые также могут дать нам локальный объем в блоке, как мы видим дальше.
Работа с пусть и const
ES2015 представил позволять и Const которые являются переменными, которые соблюдают область блока. Это означает, что они безопасны для объявления в блоке и не будут утечны на улице, как следующий пример:
function stepSum() { let total = 0; for (let i = 0; i < arguments.length; i++) { const parameter = arguments[i]; total += parameter; console.log(`${i}) adding ${parameter}`); } // outside the loop, we can no longer access i and parameter console.log(`i=${i}, parameter=${parameter}`); return total;}console.log(`total=${stepSum(3, 2, 1)}`);Вывод:
0) adding 31) adding 22) adding 1Uncaught ReferenceError: i is not defined at stepSum (:10:20) at :13:1
Хорошо, теперь, когда мы узнали, как предотвратить утечку и защищать переменные в рамках блока, давайте попробуем их!
Вернуться к Сетримс Выпуск выше, теперь мы можем использовать Пусть и Const Чтобы исправить нашу проблему:
function stepSum() { let total = 0; for (let i = 0; i < arguments.length; i++) { const parameter = arguments[i]; setTimeout(function() { total += parameter; console.log(`${i}) adding ${parameter}, total=${total}`); }, i*1000); }}stepSum(3, 2, 1);
Voilà, теперь вывод – это то, что мы ожидаем:
0) adding 3, total=31) adding 2, total=52) adding 1, total=6
Имейте в виду, что мы создали одну пару i и параметр Переменные для каждой итерации для цикла. Сравнить это с ранее, когда мы только что имели один сингл i и параметр переписан каждый раз. Это имеет значение немного для потребления памяти.
Наконец, так как мы также создали Сетримс Функция обратного вызова в пределах одинакового объема, они будут соответствовать защищенным значениям i и параметр Отказ Область блока останется сохраненным даже после Штурм закончил выполнение.
Работа с функциями
Вот что-то заслуживающее внимания: объявление Функция отличается от объявления var и присвоение к ней функции.
Например, вот пример объявления Функция После того, как он использовался, чтобы понять, как работает подъемник. Это действительный JavaScript:
console.log(`total=${stepSum(3, 2, 1)}`);function stepSum(...args) { let total = 0; args.forEach((parameter, i) => { total += parameter; console.log(`${i}) adding ${parameter}`); });return total;}
Вывод:
0) adding 31) adding 22) adding 1total=6
Почему это работает? Потому что функция Штурм был полностью подзагощен до того, как он был использован.
Тем не менее, объявляя его как var вызывает ошибку:
console.log(`total=${stepSum(3, 2, 1)}`);var stepSum = function(...args) { let total = 0; args.forEach((parameter, i) => { total += parameter; console.log(`${i}) adding ${parameter}`); });return total;}
Вывод:
Uncaught TypeError: stepSum is not a function at:1:22
Почему это сломалось?
Разница вот что когда Функция Поднимается, его тело также поднимается. По сравнению с когда var поднимается, только его декларация становится поднимается, но не его назначение. Таким образом, код выше, был бы похож на это, где мы пытаемся использовать Штурм до того, как функция будет назначена ему.
var stepSum;console.log(`total=${stepSum(3, 2, 1)}`);stepSum = function(...args) { let total = 0; args.forEach((parameter, i) => { total += parameter; console.log(`${i}) adding ${parameter}`); });return total;}
За вызов?
Теперь, когда вы понимаете это, я бы хотел оставить вам вызов, поэтому вы можете объяснить, что HEC работает с кодом ниже:
function stepSum(...args) { let total = 0; args.forEach((parameter, i) => { total += parameter; console.log(`${i}) adding ${parameter}`); return; function total() {} });return total;}
console.log(`total=${stepSum(3, 2, 1)}`);Вывод:
0) adding 31) adding 22) adding 1total=0
Почему 0 ?? Я приглашаю вас оставить свое объяснение в разделе комментариев ниже:)
Учить больше
Для более интересных сценариев на Scoping и Hosting я предлагаю прочитать эту разъясняющую статью:
JavaScript Scoping и Heasting Этот метод на самом деле довольно гибкий, и может использоваться в любом месте, где вам нужен временный объем, а не только в блоке … www.adequetegood.com.
И после этого вы можете попробовать свои знания с некоторыми вопросами собеседования:
Функциональные вопросы подъема и подъема Это часть 2 для моей предыдущей статьи о переменной подъемнике под названием «Руководство по переменным подъемам JavaScript? С … м Edium.freecodeCamp.org.
Эта статья была первоначально опубликована (версия Pre-ES2015) 4 февраля 2014 года как JavaScript Heating Отказ
Оригинал: “https://www.freecodecamp.org/news/a-brief-review-of-scoping-and-hoisting-in-javascript-e74c38283b65/”