предисловие
В JavaScript есть функция, называемая областью действия. Хотя многим начинающим разработчикам концепция области действия не очень проста для понимания, в этой статье я постараюсь объяснить область действия и цепочку областей действия самым простым способом, надеюсь, вы что-то поняли!
Чтобы прочитать больше качественных статей, нажмитеБлог GitHub
Объем
1. Что такое объем
Область действия — это доступность переменных, функций и объектов в определенной части кода во время выполнения. Другими словами, область видимости определяет видимость переменных и других ресурсов в блоке кода. Возможно, эти два предложения не так просто понять, давайте сначала рассмотрим пример:
function outFun2() {
var inVariable = "内层变量2";
}
outFun2();//要先执行这个函数,否则根本不知道里面是啥
console.log(inVariable); // Uncaught ReferenceError: inVariable is not defined
Из приведенного выше примера вы можете понять концепцию области видимости: переменная inVariable не объявлена в глобальной области видимости, поэтому при принятии значения в глобальной области действия будет сообщено об ошибке. Мы можем понять это так:Область действия — это независимый сайт, поэтому переменные не будут раскрыты и не будут раскрыты.. то естьОбласть действия чаще всего используется для изоляции переменных. Переменные с одинаковыми именами в разных областях видимости не будут конфликтовать.
До ES6 в JavaScript не было блочной области, только глобальная область действия и область действия функции.. Появление ES6 предоставляет нам «область действия на уровне блоков», что можно отразить добавлением команд let и const.
2. Глобальный объем и объем функций
Объекты, к которым можно получить доступ в любом месте кода, имеют глобальную область действия.Вообще говоря, следующие ситуации имеют глобальную область действия:
- Самая внешняя функция и переменные, определенные за пределами самой внешней функции, имеют глобальную область видимости.
var outVariable = "我是最外层变量"; //最外层变量
function outFun() { //最外层函数
var inVariable = "内层变量";
function innerFun() { //内层函数
console.log(inVariable);
}
innerFun();
}
console.log(outVariable); //我是最外层变量
outFun(); //内层变量
console.log(inVariable); //inVariable is not defined
innerFun(); //innerFun is not defined
- Все переменные, которые не определены и назначены напрямую, автоматически объявляются имеющими глобальную область действия.
function outFun2() {
variable = "未定义直接赋值的变量";
var inVariable2 = "内层变量2";
}
outFun2();//要先执行这个函数,否则根本不知道里面是啥
console.log(variable); //未定义直接赋值的变量
console.log(inVariable2); //inVariable2 is not defined
- Все свойства объекта окна имеют глобальную область видимости.
Как правило, встроенные свойства объекта окна имеют глобальную область действия, например, window.name, window.location, window.top и т. д.
У глобальной области видимости есть недостаток: если мы пишем много строк JS-кода, а определения переменных не включены в функции, то они все находятся в глобальной области видимости. Это загрязнит глобальное пространство имен и легко вызовет конфликты имен.
// 张三写的代码中
var data = {a: 100}
// 李四写的代码中
var data = {x: true}
Вот почему исходный код таких библиотек, как jQuery, Zepto и т. д., весь код будет помещен в(function(){....})()
середина. Потому что все переменные, размещенные в нем, не будут просочены и раскрыты, не будут загрязнены наружу и не повлияют на другие библиотеки или JS-скрипты. Это проявление объема функции.
Область действия функции относится к переменным, объявленным внутри функции.В отличие от глобальной области действия, локальная область обычно доступна только в пределах фиксированного сегмента кода, чаще всего внутри функции.
function doSomething(){
var blogName="浪里行舟";
function innerSay(){
alert(blogName);
}
innerSay();
}
alert(blogName); //脚本错误
innerSay(); //脚本错误
Область иерархична, внутренняя область может обращаться к переменным внешней области и наоборот.. Давайте рассмотрим пример. Возможно, будет проще понять использование пузыря в качестве метафоры для области действия:
Конечный результат: 2, 4, 12.
- Пузырь 1 является глобальной областью действия и имеет идентификатор foo;
- Пузырь 2 — это область действия foo с идентификаторами a, bar, b;
- Пузырь 3 представляет собой бар с ограниченной областью действия и имеет только идентификатор c.
Стоит отметить, что:Блочные операторы (операторы между фигурными скобками "{}"), такие как if и switch условные операторы или циклы for и while, в отличие от функций, они не создают новую область. Переменные, определенные в операторе блока, останутся в той области, в которой они уже существуют.
if (true) {
// 'if' 条件语句块不会创建一个新的作用域
var name = 'Hammad'; // name 依然在全局作用域中
}
console.log(name); // logs 'Hammad'
Новичкам в JS часто нужно время, чтобы привыкнуть к переменным, и если они не понимают этого уникального поведения, это может привести к Ошибка. Из-за этого в ES6 вводится область действия на уровне блоков, что делает жизненный цикл переменных более контролируемым.
3. Область действия блока
Область на уровне блока может быть объявлена с помощью новых команд let и const, а к объявленным переменным нельзя получить доступ за пределами области действия указанного блока. Блочные области создаются, когда:
- внутри функции
- внутри блока кода (окруженного парой фигурных скобок)
Синтаксис объявления let такой же, как у var. В основном вы можете использовать let вместо var для объявлений переменных, но это ограничит область действия переменной текущим блоком кода. Область действия на уровне блоков имеет следующие характеристики:
- Объявление переменных не поднимается в начало блока кода
Объявления let/const не поднимаются вверх текущего блока, поэтому вам нужно вручную разместить объявления let/const вверху, чтобы сделать переменную доступной во всем блоке.
function getValue(condition) {
if (condition) {
let value = "blue";
return value;
} else {
// value 在此处不可用
return null;
}
// value 在此处不可用
}
- Не повторяйте декларации
Если идентификатор уже определен внутри блока кода, объявление let с тем же идентификатором внутри блока приведет к возникновению ошибки. Например:
var count = 30;
let count = 40; // Uncaught SyntaxError: Identifier 'count' has already been declared
В этом примере переменная count объявлена дважды: один раз с помощью var и один раз с помощью let. Поскольку let не может дублировать существующий идентификатор в той же области, объявление let здесь выдает ошибку. Но если новая переменная с тем же именем объявлена с помощью let внутри вложенной области, ошибка не будет выдана.
var count = 30;
// 不会抛出错误
if (condition) {
let count = 40;
// 其他代码
}
- Волшебное использование Binding Block Scope в циклах
Разработчики могут захотеть реализовать циклы for с блочной областью действия, потому что можно ограничить объявленную переменную счетчика циклом, например:
for (let i = 0; i < 10; i++) {
// ...
}
console.log(i);
// ReferenceError: i is not defined
В приведенном выше коде счетчик i действителен только в теле цикла for, и за пределами цикла будет сообщено об ошибке.
var a = [];
for (var i = 0; i < 10; i++) {
a[i] = function () {
console.log(i);
};
}
a[6](); // 10
В приведенном выше коде переменная i объявлена командой var и действительна в глобальной области видимости, поэтому глобально существует только одна переменная i. Значение переменной i будет меняться каждый раз, когда цикл зацикливается, а console.log(i) внутри функции, назначенной массиву a в цикле, i в нем указывает на глобальный i. Другими словами, i во всех элементах массива a указывает на одно и то же i, что приводит к тому, что на выходе среды выполнения будет значение i в последнем раунде, равное 10.
Если используется let, объявленная переменная действительна только в области блока, а последний вывод равен 6.
var a = [];
for (let i = 0; i < 10; i++) {
a[i] = function () {
console.log(i);
};
}
a[6](); // 6
В приведенном выше коде переменная i объявлена с помощью let, и текущая i действительна только в этом цикле, поэтому i каждого цикла на самом деле является новой переменной, поэтому окончательный вывод равен 6. Вы можете спросить, если переменная i повторно объявляется в каждом цикле, как она узнает значение предыдущего цикла для вычисления значения текущего цикла? Это связано с тем, что движок JavaScript внутренне запоминает значение предыдущего цикла, и при инициализации переменной i в этом цикле расчет выполняется на основе предыдущего цикла.
Кроме того, у цикла for есть особенность, то есть часть, задающая переменную цикла, является родительской областью видимости, а внутренняя часть тела цикла — отдельной дочерней областью.
for (let i = 0; i < 3; i++) {
let i = 'abc';
console.log(i);
}
// abc
// abc
// abc
Приведенный выше код работает правильно и выводит abc 3 раза. Это указывает на то, что переменная i внутри функции и переменная цикла i не находятся в одной и той же области видимости, а имеют разные области видимости.
цепочка прицелов
1. Что такое свободная переменная
Во-первых, давайте узнаем, что такоесвободная переменная. В следующем кодеconsole.log(a)
Чтобы получить переменную, но a не определена в текущей области видимости (сравните b). Переменные, не определенные в текущей области видимости, становятся свободными переменными. Как получить значение свободной переменной — ищем родительскую область видимости (примечание: это утверждение не является строгим, и оно будет объяснено ниже).
var a = 100
function fn() {
var b = 200
console.log(a) // 这里的a在这里就是一个自由变量
console.log(b)
}
fn()
2. Что такое цепочка областей действия
А если у родителя его нет? Ищите слой за слоем, пока не найдете глобальную область видимости и все еще не найдете ее, а затем сдайтесь. Эта послойная связь представляет собой цепочку областей видимости.
var a = 100
function F1() {
var b = 200
function F2() {
var c = 300
console.log(a) // 自由变量,顺作用域链向父作用域找
console.log(b) // 自由变量,顺作用域链向父作用域找
console.log(c) // 本作用域的变量
}
F2()
}
F1()
3. О значении свободных переменных
По поводу значения свободной переменной, выше было сказано, что его нужно брать из родительской области видимости, на самом деле иногда такая интерпретация будет вызывать неоднозначность.
var x = 10
function fn() {
console.log(x)
}
function show(f) {
var x = 20
(function() {
f() //10,而不是20
})()
}
show(fn)
В функции fn при получении значения свободной переменной x из какой области его следует брать? - Чтобы перейти к области, где была создана функция fn,везде, где будет вызываться функция fn.
Итак, прекратите использовать приведенное выше утверждение. Напротив, было бы более уместно описать это в этом предложении:в поле, где была создана функция». Значение в области действия, ударение здесь "создать", а не "вызвать", не забудьте запомнить - на самом деле это так называемый "статический прицел"
var a = 10
function fn() {
var b = 20
function bar() {
console.log(a + b) //30
}
return bar
}
var x = fn(),
b = 200
x() //bar()
fn() возвращает функцию bar, которая назначена x. Выполнить x(), то есть выполнить код функции штриха. Принимая значение b, берите его непосредственно в области действия fn. При взятии значения a я пытался взять его в области действия fn, но не смог его получить, поэтому я мог только обратиться к области, в которой была создана fn, чтобы найти его, и результат был найден, поэтому окончательный результат был 30
область действия и контекст выполнения
Многие разработчики часто путают понятия области действия и контекста выполнения, ошибочно полагая, что это одно и то же понятие, но это не так.
Мы знаем, что JavaScript — это интерпретируемый язык.Выполнение JavaScript делится на две фазы: интерпретация и выполнение.Эти две фазы делают разные вещи:
Стадия интерпретации:
- лексический анализ
- Разбор
- определение правила области видимости
Этап выполнения:
- Создайте контекст выполнения
- выполнить код функции
- вывоз мусора
Правила области определяются на этапе интерпретации JavaScript, поэтому область определяется при определении функции, а не при вызове функции, но контекст выполнения создается до выполнения функции. Наиболее очевидным контекстом выполнения является то, что указатель на this определяется во время выполнения. Переменные, к которым обращается область действия, определяются структурой написанного кода.
Самая большая разница между областью действия и реализацией контекста заключается в следующем:Контекст выполнения определяется во время выполнения и может измениться в любое время; область действия определяется во время определения и не изменится..
Область действия может содержать несколько контекстов. Возможно, что контекста никогда не было (функция никогда не вызывалась); может быть, и теперь после вызова функции контекст уничтожается; может быть один или несколько (замыканий) одновременно .В одной и той же области разные вызовы будут генерировать разные контексты выполнения, а затем генерировать разные значения переменных..
Порекомендуйте полезный инструмент мониторинга ошибок для всехFundebug, добро пожаловать, чтобы попробовать это бесплатно!
Добро пожаловать в публичный аккаунт:Мастер по фронтенду, мы будем свидетелями вашего роста вместе! Если вы чувствуете, что что-то приобрели, пожалуйста, дайте мне вознаграждение, чтобы мотивировать меня выпускать больше высококачественного контента с открытым исходным кодом.
Справочные статьи и книги
- Глубокое понимание прототипа javascript и серии замыканий
- Руководство по веб-интервью и анализ часто задаваемых вопросов на экзамене
- Глубокое понимание декларативного подъема, области (цепочки) и
this
ключевые слова - Продвинутая разработка JavaScript: понимание области видимости JavaScript и цепочки областей видимости
- Области действия JavaScript и цепочки областей видимости
- Глубокое понимание ES6