Области видимости JavaScript

Для новичков область видимости JavaScript немного запутанна. Эти концепции могут показаться простыми; Однако это не так. Существуют некоторые важные тонкости, которые необходимо понимать, чтобы овладеть концепцией. Итак, что такое Область видимости? В JavaScript область видимости относится к текущему контексту кода.
Область видимости переменной — это контекст, в котором существует переменная. Область определяет, откуда вы можете получить доступ к переменной и имеете ли вы доступ к переменной в этом контексте. Области могут быть определены глобально или локально.

Глобальная область видимости

Любая переменная, которую вы объявляете, по умолчанию определена в глобальной области. Это одно из самых раздражающих решений в JavaScript. Поскольку глобальная переменная видна во всех других областях, глобальная переменная может быть изменена в любой области. Глобальные переменные затрудняют запуск встроенных подпрограмм в одном приложении / модуле. Если в подпрограммах есть глобальные переменные, которые имеют одни и те же имена, тогда они будут мешать друг другу и, скорее всего, не сработают. Это иногда называют конфликтом пространства имен.

Глобальную переменную можно создать двумя способами:
• Первым способом является размещение оператора var вне любой функции. По существу, любая переменная, объявленная вне функции, определяется в глобальной области.
• Второй способ — опустить оператор var при объявлении переменной. Я думаю, что это было разработано как удобство для новых программистов, а в итоге оказалось кошмаром. Даже в пределах области функций, если вы опускаете оператор var при объявлении переменной, она создается по умолчанию в глобальной области. Это неприятно. Вы всегда должны запускать свою программу против ESLint или JSHint, чтобы позволить им обнаружить такие нарушения. В следующем примере показано, как ведет себя глобальная область видимости:

//Global Scope
var a = 1;
function scopeTest() {
    console.log(a);
}
scopeTest(); //prints 1

Здесь мы объявляем переменную вне функции и в глобальной области. Эта переменная доступна в функции scopeTest(). Если вы присвойте новое значение глобальной переменной в пределах области действия (локальной), исходное значение в глобальной области будет перезаписано:

//Global Scope
var a = 1;
function scopeTest() {
    a = 2; //Overwrites global variable 2, you omit 'var'
    console.log(a);
}
console.log(a); //prints 1
scopeTest(); //prints 2
console.log(a); //prints 2 (global value is overwritten)

Локальная область видимости

В отличие от большинства языков программирования, JavaScript не имеет области видимости блочного уровня (переменные, привязанные к окружающим фигурным скобкам); Вместо этого JavaScript имеет область функционального уровня. Переменные, объявленные внутри функции, являются локальными переменными и доступны только внутри этой функции или из функций внутри этой функции:

var scope_name = "Global";
function showScopeName () {
    // local variable; only accessible in this function
    var scope_name = "Local";
    console.log (scope_name); // Local
}
console.log (scope_name); //prints - Global
showScopeName(); //prints – Local

Функциональная область видимости против блочной области

Переменные JavaScript ограничены уровнем функции. Вы можете думать об этом как о создании небольшого пузыря, который предотвращает видимость переменной извне этого пузыря. Функция создает такой пузырь для переменных, объявленных внутри функции. Вы можете визуализировать пузырьки следующим образом:

-GLOBAL SCOPE---------------------------------------------|
var g =0;                                                 |
function foo(a) { -----------------------|                |
    var b = 1;                           |                |
    //code                               |                |
    function bar() { ------|             |                |
        // ...             |ScopeBar     | ScopeFoo       |
    }                ------|             |                |
    // code                              |                |
    var c = 2;                           |                |
}----------------------------------------|                |
foo(); //WORKS                                            |
bar(); //FAILS                                            |
----------------------------------------------------------|

JavaScript использует систему областей для определения области видимости для данной функции. Обычно существует одна глобальная область видимости, и каждая определенная функция имеет собственную вложенную область. Любая функция, определенная внутри другой функции, имеет локальную область, связанную с внешней функцией. Это всегда позиция в источнике, которая определяет область видимости.
В предыдущей грубо нарисованной визуализации вы можете видеть, что функция foo() определена в глобальной области. Функция foo() имеет свою локальную область действия и доступ к переменной g, поскольку она находится в глобальной области. Переменные a, b и c доступны в локальной области, поскольку они определены в пределах области функции. Функция bar() также объявляется в пределах области действия и доступна в функции foo(). Однако, как только область функции закончена, функция bar() недоступна. Вы не можете видеть или вызывать функцию bar() вне функции foo() — пузырь видимости области.
Теперь, когда функция bar() также имеет свою собственную область действия (пузырь), что доступно здесь? Функция bar() имеет доступ к функции foo() и всем переменным, созданным в родительской области функции foo()a, b и c. Функция bar() также имеет доступ к глобальной переменной области, g.
Это мощная идея. Потратьте минутку, чтобы подумать об этом. Мы только что обсудили, как в JavaScript может появиться необузданная и неконтролируемая глобальная область. Как насчет того, чтобы взять произвольный фрагмент кода и обернуть его функцией? Мы сможем скрыть и создать пузырь видимости вокруг этого фрагмента кода. Создание правильной области видимости, используя обертывание функции поможет нам создать правильный код и предотвратить обнаружение ошибок.
Другим преимуществом области видимости функций и сокрытие переменных и функций в этой области является то, что вы можете избежать конфликтов между двумя идентификаторами. Следующий пример показывает такой дурной случай:

function foo() {
  function bar(a) {
    i = 2; // changing the 'i' in the enclosing scope's for-loop
    console.log(a+i);
  }
  for (var i=0; i<10; i++) {
    bar(i); // infinite loop
  }
}
foo();

В функции bar() мы непреднамеренно модифицируем значение i = 2. Когда мы вызываем bar() из цикла for, значение переменной i становится равным 2, и мы никогда не выйдем из бесконечного цикла. Это дурной случай столкновения пространства имен.

До сих пор использование функций как области видимости звучало как отличный способ добиться модульности и корректности JavaScript. Ну, хотя эта техника работает, она не идеальна. Первая проблема заключается в том, что мы должны создать именованную функцию. Если мы будем создавать такие функции только для того, чтобы ввести область действия, мы засоряем глобальную область видимости или родительскую область. Кроме того, мы должны продолжать вызывать такие функции. Это вводит много шаблонов, что делает код нечитаемым со времени:

var a = 1;
//Lets introduce a function -scope
//1. Add a named function foo() into the global scope
function foo() {
    var a = 2;
    console.log( a ); // 2
}
//2. Now call the named function foo()
foo();
console.log( a ); // 1

Мы внесли область видимости функции, создав новую функцию foo() для глобальной области видимости и позже вызвали эту функцию для выполнения кода.
В JavaScript вы можете решить обе эти проблемы, создав функции, которые немедленно выполнятся. Внимательно изучите следующий пример:

var a = 1;
//Lets introduce a function -scope
//1. Add a named function foo() into the global scope
(function foo() {
    var a = 2;
    console.log( a ); // 2
})(); //<---this function executes immediately
console.log( a ); // 1

Обратите внимание, что оператор обертывающей функции начинается с функции. Это означает, что вместо того, чтобы рассматривать функцию как стандартную декларацию, функцию рассматривают как выражение функции.

Оператор (function foo () {}) как выражение означает, что идентификатор foo находится только в области функции foo(), а не во внешней области. Скрытие имени foo само по себе означает, что оно не загрязняет область применения без необходимости. Это так полезно и намного лучше. Мы добавляем () после выражения функции для его немедленного выполнения. Таким образом, полный шаблон выглядит следующим образом:

(function foo(){ /* code */ })();

Этот шаблон настолько распространен, что у него есть имя: IIFE, что означает выражение Exited Exited Expression. Некоторые программисты опускают имя функции, когда используют IIFE. Поскольку первое использование IIFE заключается в том, чтобы внести область функционального уровня, именование функции действительно не требуется. Мы можем написать предыдущий пример следующим образом:

var a = 1;
(function() {
    var a = 2;
    console.log( a ); // 2
})();
console.log( a ); // 1

Здесь мы создаем анонимную функцию типа IIFE. Хотя это идентично ранее названному IIFE, есть несколько недостатков использования анонимных IIFE:
• Поскольку вы не можете видеть имя функции в трассировке стека, отладка такого кода очень сложна
• Вы не можете использовать рекурсию для анонимных функций (как мы обсуждали ранее)
• Избыточность анонимных IIFE иногда приводит к нечитаемому коду

Дуглас Крокфорд и несколько других экспертов рекомендуют небольшое изменение IIFE:

(function(){ /* code */ }());

Обе эти формы IIFE являются популярными, и вы увидите много кода, используя оба этих варианта.
Вы можете передавать параметры в IIFE. В следующем примере показано, как передать параметры для IIFE:

(function foo(b) {
    var a = 2;
    console.log( a + b );
})(3); //prints 5

 

Написать комментарий

Ваш Email не будет опубликован

На нашем сервере не хранятся какие-либо объекты авторского права согласно действующему законодательству страны, в которой находится сайт и сервер. Все материалы хранятся на файлообменных общедоступных серверах и у нас представлены только ссылки, что не является нарушением законодательства текущей страны местонахождения сайта. Если вы хотите заявить о нарушении авторских прав, пожалуйста, предоставьте нам полную информацию и обоснованные аргументы, согласно которым мы должны удалить какую-либо информацию с нашего сайта.