Оригинальная ссылка:Variable Scope in Modern JavaScript
Переводчик:OFED
Область видимости переменных в современном JavaScript
Когда я разговариваю с другими разработчиками JavaScript, я часто удивляюсь, как много людей не знаютпеременная область видимостиКак это работает в JavaScript. Под областью действия мы подразумеваем видимость переменных в коде или, другими словами, какие части кода могут получать доступ к переменным и изменять их. Я обнаружил, что люди часто используют в кодеvar
Объявляйте переменные, не зная, что с ними сделает JavaScript.
JavaScript претерпел некоторые существенные изменения за последние несколько лет; эти изменения включают новые ключевые слова объявления переменных и новые способы обработки областей видимости. Добавлен ES6 (ES2015)let
а такжеconst
Команда, прошло уже три года, и браузер очень хорошо ее поддерживает. Для других новых функций вы можете использоватьBabelПереведите ES6 на широко поддерживаемый JavaScript. Пришло время рассмотреть, как объявляются переменные, и узнать больше об области видимости.
В этом сообщении блога я покажу вам несколько примеров JavaScript.Глобальный,местныйа такжеблочный уровеньКак работают прицелы. Мы также продемонстрируем, как использовать для тех, кто еще не знаком с этой частьюlet
а такжеconst
объявить переменные.
глобальная область
Давайте начнем сглобальная областьГоворя о. К глобально определенным переменным можно получить доступ и изменить их в любом месте кода (почти, но об исключениях мы поговорим позже).
Переменная, объявленная в области верхнего уровня вне какой-либо функции, является глобальной переменной.
var a = 'Fred Flinstone'; // 全局变量
function alpha() {
console.log(a);
}
alpha(); // 输出 'Fred Flinstone'
В этом примереa
является глобальной переменной, поэтому легко доступна в любой функции. Таким образом, мы можем начать с методаalpha
выходa
ценность . когда мы звонимalpha
метод, вывод консолиFred Flinstone
.
Когда веб-браузер объявляет глобальную переменную, он действует как глобальная переменная.window
свойства объекта. Посмотрите этот пример:
var b = 'Wilma Flintstone';
window.b = 'Betty Rubble';
console.log(b); // 输出 'Betty Rubble'
b
можно использовать какwindow
свойства объекта (window.b
) доступ/изменение. Конечно, не обязательно проходитьwindow
модификация объектаb
значение, это только для того, чтобы доказать это. Мы, скорее всего, запишем приведенный выше случай как:
var b = 'Wilma Flintstone';
b = 'Betty Rubble';
console.log(b); // 输出 'Betty Rubble'
Будьте осторожны с глобальными переменными. Они делают код менее читаемым и трудным для тестирования. Я видел, как у многих разработчиков возникают неожиданные проблемы с обнаружением сброса значения переменной. Передача переменных в качестве аргументов функциям намного лучше, чем использование глобальных переменных. Глобальные переменные следует использовать с осторожностью.
Если вам нужно использовать глобальные переменные, лучше определить пространства имен, чтобы они были свойствами глобального объекта. Например, создайтеglobals
илиapp
глобальный объект.
var app = {}; // 全局对象
app.foo = 'Homer';
app.bar = 'Marge';
function beta() {
console.log(app.bar);
}
beta(); // 输出 'Marge'
Если вы используете NodeJS, область верхнего уровня не совпадает с глобальной областью. Если используется в модуле NodeJSvar foobar
, это локальная переменная этого модуля. Чтобы определить глобальные переменные в NodeJS, нам нужно использоватьобъект глобального пространства имен,global
.
global.foobar = 'Hello World!'; // 在 NodeJS 里是一个全局变量
Обратите внимание, что если ключевое слово не используетсяvar
,let
илиconst
Один для объявления переменной, затем переменная принадлежит глобальной области видимости.
function gamma() {
c = 'Top Cat';
}
gamma();
console.log(c); // 输出 'Top Cat'
console.log(window.c); // 输出 'Top Cat'
Мы рекомендуем всегда использовать ключевое слово variable для определения переменных. Таким образом, можно контролировать область действия каждой переменной в коде. Как и в приведенных выше примерах, надеюсь, вы знаете о потенциальных опасностях неиспользования ключевых слов.
локальная область
теперь мы возвращаемся клокальная область
var a = 'Daffy Duck'; // a 是全局变量
function delta(b) {
// b 是传入 delta 的局部变量
console.log(b);
}
function epsilon() {
// c 被定义成局部作用域变量
var c = 'Bugs Bunny';
console.log(c);
}
delta(a); // 输出 'Daffy Duck'
epsilon(); // 输出 'Bugs Bunny'
console.log(b); // 抛出错误:b 在全局作用域未定义
Переменные, определенные внутри функции, находятся внутри функции. В приведенном выше примере b и c являются локальными для соответствующих функций. Но каков будет результат вывода, когда произойдет следующий способ записи?
var d = 'Tom';
function zeta() {
if (d === undefined) {
var d = 'Jerry';
}
console.log(d);
}
zeta();
Ответ «Джерри», вероятно, один из часто задаваемых вопросов на интервью. Внутри дзета-функции определена новая локальная переменная d.var
При определении переменной JavaScript инициализирует ее в верхней части текущей области видимости, независимо от того, где она находится в коде.
var d = 'Tom';
function zeta() {
var d;
if (d === undefined) {
d = 'Jerry';
}
console.log(d);
}
zeta();
это называетсяпродвигать, что является одной из особенностей JavaScript, и следует отметить, что переменные не инициализируются в верхней части области видимости, что может легко привести к некоторым ошибкам. отличноlet
а такжеconst
появился, чтобы спасти нас. Итак, давайте посмотрим, как использоватьlet
Создать область блока.
область действия блока
С появлением ES6 несколько лет назад появились два новых ключевых слова для объявления переменных:let
а такжеconst
. Оба ключевых слова позволяют расширить объем блока кода, то есть контент, введенный между двумя бреками {}.
let
многие люди думаютlet
к существующемуvar
заменять. Однако это не совсем так, потому что они объявляют переменные в разных областях.let
объявляет блочную переменную, однакоvar
Операторы позволяют нам создавать переменные локального масштаба. Конечно, внутри функции мы можем использоватьlet
объявить область блока, как мы привыклиvar
Такой же.
function eta() {
let a = 'Scooby Doo';
}
eta();
здесьa
Область действия функцииeta
Внутри. Мы также можем использовать условные блоки и циклы. Область действия на уровне блока включает любые подблоки, содержащиеся в блоке верхнего уровня определения переменной.
for (let b = 0; b < 5; b++) {
if (b % 2) {
console.log(b);
}
}
console.log(b); // 'ReferenceError: b is not defined'
В этом примереb
существуетfor
Работает на уровне блоков (включая условные блоки) в рамках цикла. Таким образом, он выведет нечетные числа 1 и 3, а затем выдаст ошибку, потому что мы не можем получить к нему доступ за пределами его области видимости.b
.
Мы уже видели странный подъем переменных в JavaScript, влияющий на функции.zeta
В результате, что произойдет, если мы перепишем функцию, чтобы использовать let?
var d = 'Tom';
function zeta() {
if (d === undefined) {
let d = 'Jerry';
}
console.log(d);
}
zeta();
этот разzeta
выводит «Том», потому что d имеет право действовать внутри условного блока, но означает ли это, что здесь нет подъема? Нет, когда мы используемlet
илиconst
, JavaScript по-прежнему будет поднимать переменную в верхнюю часть области видимости, но сvar
разница в том,var
После начального значения обновления переменной декларацииundefined
,let
а такжеconst
Объявленные переменные после подъема не инициализируются, они находятся во временной мертвой зоне.
Давайте посмотрим, что происходит, когда вы используете блочную переменную перед объявлением инициализации.
function theta() {
console.log(e); // 输出 'undefined'
console.log(f); // 'ReferenceError: d is not defined'
var e = 'Wile E. Coyote';
let f = 'Road Runner';
}
theta();
Поэтому вызовtheta
переменные, которые будут иметь локальную область видимостиe
выходundefined
, а для переменных с блочной областью видимостиf
выдает ошибку. при запускеf
Раньше мы не могли его использовать, в данном случае мы установили его значение «Road Runner».
Прежде чем продолжить, нам нужно уточнить, что есть еще одно важное различие между let и var. Когда мы используем var на самом верхнем уровне нашего кода, она становится глобальной переменной и добавляется к объекту окна в браузере. С помощью let, несмотря на то, что переменная станет глобальной, поскольку ее область действия представляет собой блок всей кодовой базы, она не станет свойством объекта окна.
var g = 'Pinky';
let h = 'The Brain';
console.log(window.g); // 输出 'Pinky'
console.log(window.h); // 输出 undefined
const
Я упоминал ранее, кстатиconst
. Это ключевое слово связано сlet
Представлены вместе как часть ES6. По объему это то же самое, что иlet
работает так же.
if (true) {
const a = 'Count Duckula';
console.log(a); // 输出 'Count Duckula'
}
console.log(a); // 输出 'ReferenceError: a is not defined'
В этом примереa
Область примененияif
оператора, поэтому к нему можно получить доступ внутри условного оператора, но вне условного оператораundefined
.
а такжеlet
разные,const
Определенные переменные нельзя изменить путем переназначения.
const b = 'Danger Mouse';
b = 'Greenback'; // 抛出 'TypeError: Assignment to constant variable'
Однако ситуация немного отличается при работе с массивами или объектами. Мы по-прежнему не можем переназначить, поэтому следующее не удастся
const c = ['Sylvester', 'Tweety'];
c = ['Tom', 'Jerry']; // 抛出 'TypeError: Assignment to constant variable'
Однако мы можем изменять константные массивы или объекты, если только мы не используем для переменныхObject.freeze()
сделать его неизменным.
const d = ['Dick Dastardly', 'Muttley'];
d.pop();
d.push('Penelope Pitstop');
Object.freeze(d);
console.log(d); // 输出 ["Dick Dastardly", "Penelope Pitstop"]
d.push('Professor Pat Pending'); // 抛出错误
глобальная + локальная область
Что происходит, когда мы переопределяем существующую глобальную переменную в локальной области видимости.
var a = 'Johnny Bravo'; // 全局作用域
function iota() {
var a = 'Momma'; // 局部作用域
console.log(a); // 输出 'Momma'
console.log(window.a); // 输出 'Johnny Bravo'
}
iota();
console.log(a); // 输出 'Johnny Bravo'
Когда мы переопределяем глобальную переменную в локальной области видимости, JavaScript инициализирует новую локальную переменную. В примере уже есть глобальная переменная a, а внутри функции iota создается новая локальная переменная a. Новая локальная переменная не изменяет глобальную переменную.Если мы хотим получить доступ к значению глобальной переменной внутри функции, нам нужно использовать глобальную переменную.window
объект.
Для меня следующий код более удобочитаем, используя глобальное пространство имен вместо глобальных переменных, переписывая нашу функцию для использования области видимости на уровне блоков:
var globals = {};
globals.a = 'Johnny Bravo'; // 全局作用域
function iota() {
let a = 'Momma'; // 局部作用域
console.log(a); // 输出 'Momma'
console.log(globals.a); // 输出 'Johnny Bravo'
}
iota();
console.log(globals.a); // 输出 'Johnny Bravo'
локальная + блочная область
Надеюсь, следующий код работает так, как вы хотите.
function kappa() {
var a = 'Him'; // 局部作用域
if (true) {
let a = 'Mojo Jojo'; // 块级作用域
console.log(a); // 输出 'Mojo Jojo'
}
console.log(a); // 输出 'Him'
}
kappa();
Вышеприведенный код не особо читаем, но доступ к переменным в области блока возможен только в пределах определенного уровня блока. Изменение переменных уровня блока вне области действия уровня блока не имеет никакого эффекта, используйтеlet
Переопределение переменной a также не дает результата, как в следующем примере:
function kappa() {
let a = 'Him';
if (true) {
let a = 'Mojo Jojo';
console.log(a); // 输出 'Mojo Jojo'
}
console.log(a); // 输出 'Him'
}
kappa();
var, let или const?
Я надеюсь, что это краткое изложение области видимости помогло вам лучше понять, как JavaScript обрабатывает переменные. Во всех примерах я использую var, let и const для определения переменных. С появлением ES6 мы можем заменить var на let и const.
Так является ли var избыточным? Нет действительно правильного или неправильного ответа, но лично я все еще использую var для определения глобальных переменных верхнего уровня. Однако я бы консервативно использовал глобальные переменные и вместо этого использовал бы глобальное пространство имен. Также я использую const для переменных, которые больше не меняются, а let для остальных.
Как вы будете определять переменные в конце, или, надеюсь, вы лучше понимаете область видимости в своем коде.