1. Что такое объем
Область видимости — это доступность переменных, функций и объектов в определенных частях вашего кода во время выполнения. Другими словами, область видимости определяет, насколько доступны переменные и функции, т.е.作用域控制着变量与函数的可见性和生命周期.
Об авторе: koala, сосредоточив внимание на совместном использовании полного стека технологий Node.js, от JavaScript до Node.js, до серверной базы данных, я желаю вам стать отличным старшим инженером Node.js. [Руководство по развитию программиста] Автор, блог Github с открытым исходным кодомGitHub.com/koala-co Nth…
2. Область видимости в JavaScript
В JavaScript есть два типа областей видимости.
- глобальная область
- локальная область
Если переменная находится вне функции или фигурных скобок{}внешнее объявление, затем определяет全局作用域, до ES6 локальная область видимости содержала только область действия функции,Что нам дает ES6块级作用域, также относящийся к локальной области
2.1 Глобальный охват
К объектам с глобальной областью можно получить доступ в любом месте кода.В js обычно бывают следующие ситуации с глобальной областью:
- Самая внешняя функция и самая внешняя переменная:
var globleVariable= 'global'; // 最外层变量
function globalFunc(){ // 最外层函数
var childVariable = 'global_child'; //函数内变量
function childFunc(){ // 内层函数
console.log(childVariable);
}
console.log(globleVariable)
}
console.log(globleVariable); // global
globalFunc(); // global
console.log(childVariable) // childVariable is not defined
console.log(childFunc) // childFunc is not defined
Как вы можете видеть из приведенного выше кодаglobleVariableа такжеglobalFuncК нему можно получить доступ где угодно, тогда как переменные, которые не имеют функции глобальной области видимости, могут использоваться только в пределах своей области.
- Неопределенная переменная с прямым назначением (что делает ее глобальной из-за подъема переменной)
function func1(){
special = 'special_variable';
var normal = 'normal_variable';
}
func1();
console.log(special); //special_variable
console.log(normal) // normal is not defined
Хотя мы можем объявить функции и переменные в глобальной области видимости, чтобы сделать их глобальными переменными, это не рекомендуется, поскольку это может привести к конфликту с другими именами переменных.С одной стороны, если мы используемconstилиletПри объявлении переменных будет сообщено об ошибке при конфликте имен.
// 变量冲突
var globleVariable = "person";
let globleVariable = "animal"; // Error, thing has already been declared
С другой стороны, если вы используетеvarПри объявлении переменной второе объявление той же переменной перезапишет предыдущее, что затруднит отладку вашего кода.
var name = 'koala'
var name = 'xiaoxiao'
console.log(name); // xiaoxiao
2.2 Локальная область применения
В отличие от глобальной области, локальная область обычно доступна только в фиксированной части кода. Наиболее распространенным являетсяобъем функции.
2.2.1 Объем функций
Переменные, определенные в функции, находятся в области видимости функции. И функция имеет разную область видимости каждый раз, когда она вызывается. Это означает, что переменные с одним и тем же именем могут использоваться в разных функциях. Потому что эти переменные привязаны к разным функциям, имеют разную область видимости и не могут обращаться друг к другу.
//全局作用域
function test(){
var num = 9;
// 内部可以访问
console.log("test中:"+num);
}
//test外部不能访问
console.log("test外部:"+num);
будь осторожен:
- Если вы определите переменную в функции, но не добавите ключевое слово var, переменная будет продвинута и станет глобальной переменной.
function doSomeThing(){
// 在工作中一定避免这样写
thing = 'writting';
console.log('内部:'+thing);
}
console.log('外部:'+thing)
- любая пара фигурных скобок
{...}Набор операторов во всех принадлежит блоку, и до es6 переменные, определенные в блоке оператора, оставались в области видимости, где они уже существовали:
var name = '程序员成长指北';
for(var i=0; i<5; i++){
console.log(i)
}
console.log('{}外部:'+i);
// 0 1 2 3 4 {}外部:5
мы видим переменнуюnameи переменнаяiявляется родственной областью.
2.2.2 На что следует обратить внимание перед объяснением области действия блока ES6
переменное продвижение
Английское название продвижения переменной — hoisting. Объяснение этого в MDN заключается в том, что объявление переменной обрабатывается перед выполнением любого кода. Объявление переменной в любом месте области кода такое же, как объявление ее в начале (вверху). То есть похоже, что переменную можно использовать до того, как она будет объявлена! Такое поведение называется «подъемом» или подъемом переменной, и похоже, что объявление переменной автоматически перемещается в начало функции или глобального кода. Посмотрите на кусок кода:
var tmp = new Date();
function f() {
console.log(tmp);
if(false) {
var tmp='hello';
}
}
С этим вопросом должны были столкнуться многие мелкие партнеры на собеседовании, и некоторые люди подумают, что выходом является текущая дата. Но правильный результат не определен. Это связано с переменным подъемом, здесьЗаявление было улучшено, и содержание определения не будет улучшено, соответствующий код после обновления выглядит следующим образом:
var tmp = new Date();
function f() {
var tmp;
console.log(tmp);
if(false) {
tmp='hello';
}
}
f();
Когда консоль выводит, переменная tmp только объявляется, но не определяется. Таким образом, выход не определен. Хотя он может быть выведен, этот метод записи не рекомендуется.Рекомендуемая практика заключается в том, чтобы записывать переменные, используемые в верхней части области (глобальной области или области действия) при объявлении переменных, чтобы код выглядел более понятным и простым для понимания. посмотреть, какая переменная исходит из области видимости функции, а какая — из цепочки областей видимости
Повторите заявление
См. пример:
// var
var name = 'koloa';
console.log(name); // koala
if(true){
var name = '程序员成长指北';
console.log(name); // 程序员成长指北
}
console.log(name); // 程序员成长指北
Хотя кажется, что имя объявляется дважды, как упоминалось выше, переменная var js имеет только два типа: глобальную область видимости и область действия функции, и объявление будет продвигаться, поэтому на самом деле имя будет объявлено только в топ. раз,var name='Оператор Programmer's Growth Guide игнорируется и используется только для назначения. То есть приведенный выше код на самом деле такой же, как и следующий.
// var
var name = 'koloa';
console.log(name); // koala
if(true){
name = '程序员成长指北';
console.log(name); // 程序员成长指北
}
console.log(name); // 程序员成长指北
Подъем переменных и функций одновременно
Что произойдет, если одновременно будут объявлены функции и переменные? см. ниже, но код
console.log(foo);
var foo ='i am koala';
function foo(){}
Выходfunction foo(){}, то есть содержание функции
А если бы это была другая форма?
console.log(foo);
var foo ='i am koala';
var foo=function (){}
Выходundefined
Два результата анализируются и объясняются:
Первый: объявление функции. Это первый сверху.function foo(){}эта форма
Другое: функциональные выражения. Это второй сверху.var foo=function(){}эта форма
Вторая форма на самом деле является объявлением и определением переменной var, поэтому должно быть понятно, что второй вывод выше не определен.
И первая форма объявления функции при повышении будет продвигаться в целом, включая часть определения функции! Таким образом, первая форма эквивалентна следующей!
var foo=function (){}
console.log(foo);
var foo ='i am koala';
Причина в следующем:
- объявления функций поднимаются вверх;
- Заявление делается только один раз, поэтому следующее
var foo='i am koala'декларации игнорируются. - Объявления функций имеют приоритет над объявлениями переменных, а объявления функций продвигаются вместе с их определениями (здесь они отличаются от переменных).
Далее, после области блока, представленной в ES6!
2.2.2 Область действия блока
добавлен ES6
letа такжеconstкоманда, которую можно использовать для создания переменных блочной области, используяletПеременные, объявленные командой, являются толькоletгде команда代码块действует в течение.
Синтаксис объявления let такой же, как у var. В основном вы можете использовать let вместо var для объявлений переменных, но это ограничит область действия переменной текущим блоком кода. Область действия на уровне блоков имеет следующие характеристики:
- Переменные не поднимаются в начало блоков кода, а внутренние переменные с областью действия блока не допускаются извне.
console.log(bar);//抛出`ReferenceErro`异常: 某变量 `is not defined`
let bar=2;
for (let i =0; i<10;i++){
console.log(i)
}
console.log(i);//抛出`ReferenceErro`异常: 某变量 `is not defined`
На самом деле эта функция дает много преимуществ: когда разработчикам нужно проверить код, они могут избежать случайного использования некоторых переменных вне области видимости и гарантировать, что переменные не будут перепутаны, а будут использоваться повторно, что улучшит удобство сопровождения кода. Как и в примере в коде, переменная i, используемая только внутри цикла for, больше не будет очищать всю область видимости.
- Повторные декларации не допускаются
ES6letа такжеconstПовторные декларации не допускаются, т.к.varразные
// var
function test(){
var name = 'koloa';
var name = '程序员成长指北';
console.log(name); // 程序员成长指北
}
// let || const
function test2(){
var name ='koloa';
let name= '程序员成长指北';
// Uncaught SyntaxError: Identifier 'count' has already been declared
}
Необходимо посмотреть, чувствуете ли вы здесь появление блочной области видимости.
3. Цепочка областей действия
Прежде чем объяснять цепочку областей действия, давайте поговорим об этом, сначала поймите, как выполняется JavaScript?
3.1 Как выполняется JavaScript?
Выполнение кода JavaScript разделено на две фазы:
3.1.1 Этап анализа
Компилятор javascript компилируется и анализируется после генерации кода
- Параметры функции анализа
- Объявление переменной анализа
- Объявление функции анализа
Ядро фазы анализа после завершения анализа (то есть в момент следующей фазы выполнения функции) создастAO(Active Object 活动对象)
3.1.2 Этап выполнения
После успешного анализа на этапе анализаAO(Active Object 活动对象)на этап исполнения
- Движок запрашивает область, есть ли в области переменная с именем X.
- Если область действия имеет переменную X, движок будет использовать эту переменную.
- Если переменная не найдена в области видимости, движок продолжит ее поиск (вверх по области), а если переменная не будет найдена в конце, движок выдаст ошибку.
Суть фазы исполнения找, как именно找, что будет объяснено позжеLHS查询а такжеRHS查询.
3.1.3 Примеры выполнения JavaScript
Посмотрите на кусок кода:
function a(age) {
console.log(age);
var age = 20
console.log(age);
function age() {
}
console.log(age);
}
a(18);
Сначала войдите в стадию анализа
Как упоминалось ранее, в момент запуска функции создается AO (Active Object Active Object).
AO = {}
Шаг 1: Анализ параметров функции:
形式参数:AO.age = undefined
实参:AO.age = 18
Второй шаг — проанализировать объявление переменной:
// 第3行代码有var age
// 但此前第一步中已有AO.age = 18, 有同名属性,不做任何事
即AO.age = 18
Третий шаг — анализ объявления функции:
// 第5行代码有函数age
// 则将function age(){}付给AO.age
AO.age = function age() {}
Примечание по объявлениям функций: Если в AO есть атрибут с тем же именем, что и у функции, он будет перезаписан этой функцией. Но следующая ситуация
var age = function () {
console.log('25');
}
Объявленная функция не переопределяет одноименное свойство в цепочке АО.
войти в фазу выполнения
После успешного анализа на этапе анализаAO(Active Object 活动对象)На этапе выполнения движок запросит область действия,找процесс. Таким образом, приведенный выше код в цепочке АО изначально должен быть
AO.age = function age() {}
//之后
AO.age=20
//之后
AO.age=20
Итак, окончательный вывод:
function age(){
}
20
20
3.2 Концепция цепочки областей применения
После прочтения предыдущего полного процесса выполнения функции javascript давайте поговорим о концепции цепочки областей видимости.JavaScript上每一个函数执行时,会先在自己创建的AO上找对应属性值。若找不到则往父函数的AO上找,再找不到则再上一层的AO,直到找到大boss:window(全局作用域)。 而这一条形成的“AO链” 就是JavaScript中的作用域链。
3.3 找Специальные инструкции для обработки запросов LHS и RHS
Термины LHS и RHS появляются, когда механизм запрашивает переменные. В «Javascript, которого вы не знаете (часть 1)» также есть очень четкое описание. Здесь я хотел бы процитироватьfreecodecamp Ответ выше, чтобы объяснить:
LHS = присвоение переменной или запись в память. Думайте об этом как о сохранении текстового файла на жесткий диск. RHS = поиск переменных или чтение из памяти. Думайте об этом как об открытии текстового файла с вашего жесткого диска. Изучение Javascript, LHS RHS
3.3.1 Характеристики левой и правой стороны
- будет запрашиваться во всех областях
- В строгом режиме, когда нужная переменная не найдена, движок выдает
ReferenceErrorаномальный. - В нестрогом режиме
LHRНемного особенного: автоматически создается глобальная переменная - При успешном выполнении запроса, если над значением переменной выполняется необоснованная операция, например, выполняется вызов функции для значения нефункционального типа, движок выдает ошибку
TypeErrorаномальный
3.3.2 Примеры LHS и RHS
Пример взят из «Javascript, которого вы не знаете (часть 1)».
function foo(a) {
var b = a;
return a + b;
}
var c = foo( 2 );
Смотрите прямо на двигатель в прицел找этот процесс:LSH (запись в память):
c=, a=2(隐式变量分配), b=
RHS (чтение памяти):
读foo(2), = a, a ,b
(return a + b 时需要查找a和b)
3.4 Краткое изложение цепочки областей применения
Наконец, сделайте краткий обзор цепочки областей видимости, сославшись на картинку из «Javascript, которую вы не знаете (часть 1)», чтобы объяснить
Присоединяйтесь к нам, чтобы учиться вместе!