Какова область применения переменных в JavaScript? Есть ли у них один атлетии внутри, в отличие от внешней функции? Или это вообще имеет значение? Кроме того, где хранятся переменные, если они определены глобально?

2119
lYriCAlsSH 1 Фев 2009 в 11:27

18 ответов

1) Существует глобальная область действия, область действия функции, а также области действия with и catch. В общем случае для переменных нет области уровня «блок» - операторы with и catch добавляют имена в свои блоки.

2) Области применения вложены функциями вплоть до глобальной области видимости.

3) Свойства определяются путем прохождения цепочки прототипов. Оператор with переводит имена свойств объекта в лексическую область, определенную блоком with.

РЕДАКТИРОВАТЬ: ECMAAScript 6 (Harmony) предназначен для поддержки let, и я знаю, что Chrome позволяет флаг 'Harmony', так что, возможно, он поддерживает его ..

Пусть будет поддержкой для определения уровня блока, но вы должны использовать ключевое слово, чтобы это произошло.

РЕДАКТИРОВАТЬ: Исходя из того, что Бенджамин указал на высказывания with и catch в комментариях, я отредактировал пост и добавил больше. Оба оператора with и catch вводят переменные в соответствующие блоки, а является областью действия блока. Эти переменные привязываются к свойствам объектов, передаваемых в них.

 //chrome (v8)

 var a = { 'test1':'test1val' }
 test1   // error not defined
 with (a) { var test1 = 'replaced' }
 test1   // undefined
 a       // a.test1 = 'replaced'

РЕДАКТИРОВАТЬ: Уточняющий пример:

Test1 ограничен блоком with, но имеет псевдоним a.test1. «Var test1» создает новую переменную test1 в верхнем лексическом контексте (функция или глобальный), если только она не является свойством a, которым она является.

Хлоп ! Будьте осторожны, используя 'with' - точно так же, как var - noop, если переменная уже определена в функции, это также noop относительно имен, импортируемых из объекта! Небольшое упоминание имени, которое уже определено, сделает это намного безопаснее. Я лично никогда не буду использовать с из-за этого.

17
Gerard ONeill 6 Июн 2014 в 17:13

Попробуйте этот любопытный пример. В приведенном ниже примере, если бы a было числовым значением, инициализированным в 0, вы бы увидели 0, а затем 1. За исключением того, что a является объектом, и javascript передаст f1 указатель, а не его копию. В результате вы получаете одно и то же предупреждение оба раза.

var a = new Date();
function f1(b)
{
    b.setDate(b.getDate()+1);
    alert(b.getDate());
}
f1(a);
alert(a.getDate());
3
Mig82 10 Авг 2013 в 17:37

Переменные, объявленные глобально, имеют глобальную область видимости. Переменные, объявленные внутри функции, относятся к этой функции и скрывают глобальные переменные с тем же именем.

(Я уверен, что есть много тонкостей, на которые настоящие программисты JavaScript смогут указать в других ответах. В частности, я сталкивался с эта страница о том, что именно this означает в любое время. Надеемся, что этой более вводной ссылки достаточно, чтобы начать работу.)

107
gilly3 25 Фев 2014 в 18:12

Вот пример:

<script>

var globalVariable = 7; //==window.globalVariable

function aGlobal( param ) { //==window.aGlobal(); 
                            //param is only accessible in this function
  var scopedToFunction = {
    //can't be accessed outside of this function

    nested : 3 //accessible by: scopedToFunction.nested
  };

  anotherGlobal = {
    //global because there's no `var`
  }; 

}

</script>

Вы захотите исследовать замыкания и узнать, как их использовать, чтобы сделать частными участниками.

38
geowa4 1 Фев 2009 в 08:48

В JavaScript есть два типа области видимости:

  • Локальная сфера
  • Глобальная сфера

Функция Below имеет локальную переменную области видимости carName. И эта переменная не доступна извне функции.

function myFunction() {
    var carName = "Volvo";
    alert(carName);
    // code here can use carName
}

Класс ниже имеет глобальную переменную области видимости carName. И эта переменная доступна из любого места в классе.

class {

    var carName = " Volvo";

    // code here can use carName

    function myFunction() {
        alert(carName);
        // code here can use carName 
    }
}
2
Abdur Rahman 1 Ноя 2017 в 09:16

В EcmaScript5 в основном есть две области: локальная область и глобальная область , но в EcmaScript6 у нас есть в основном три области: локальная область, глобальная область и новая область под названием область видимости .

Пример объема блока:

for ( let i = 0; i < 10; i++)
{
 statement1...
statement2...// inside this scope we can access the value of i, if we want to access the value of i outside for loop it will give undefined.
}
1
Billa 15 Дек 2017 в 07:49

ПОЧТИ есть только два типа областей JavaScript:

  • область действия каждого объявления var связана с наиболее непосредственно включающей функцией
  • если нет функции включения для объявления var, это глобальная область

Таким образом, любые блоки, кроме функций, не создают новую область видимости. Это объясняет, почему циклы for перезаписывают внешние переменные области видимости:

var i = 10, v = 10;
for (var i = 0; i < 5; i++) { var v = 5; }
console.log(i, v);
// output 5 5

Вместо этого используйте функции:

var i = 10, v = 10;
$.each([0, 1, 2, 3, 4], function(i) { var v = 5; });
console.log(i,v);
// output 10 10

В первом примере отсутствовала область видимости блока, поэтому первоначально объявленные переменные были перезаписаны. Во втором примере из-за функции появилась новая область видимости, поэтому первоначально объявленные переменные были затенены, а не перезаписаны.

Это почти все, что вам нужно знать с точки зрения JavaScript, за исключением:

  • try / catch вводит новую область видимости ТОЛЬКО для самой переменной исключения, другие переменные не имеют новой области видимости
  • with-clause, очевидно, является еще одним исключением, но использование with-clause крайне нежелательно (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/with )

Таким образом, вы можете видеть, что область видимости JavaScript на самом деле очень проста, хотя и не всегда интуитивно понятна. Несколько вещей, о которых нужно знать:

  • Объявления var поднимаются в верхнюю часть области видимости. Это означает, что независимо от того, где происходит объявление var, для компилятора это происходит так, как будто сама переменная var происходит сверху
  • объединяются несколько объявлений var в одной области видимости

Итак, этот код:

var i = 1;
function abc() {
  i = 2;
  var i = 3;
}
console.log(i);     // outputs 1

Эквивалентно:

var i = 1;
function abc() {
  var i;     // var declaration moved to the top of the scope
  i = 2;
  i = 3;     // the assignment stays where it is
}
console.log(i);

Это может показаться нелогичным, но это имеет смысл с точки зрения императора языкового конструктора.

6
jackbean818 29 Окт 2015 в 16:12

В ECMAScript 6 введены ключевые слова let и const. Эти ключевые слова могут использоваться вместо ключевого слова var. В отличие от ключевого слова var ключевые слова let и const поддерживают объявление локальной области видимости внутри операторов блока.

var x = 10
let y = 10
const z = 10
{
  x = 20
  let y = 20
  const z = 20
  {
    x = 30
    // x is in the global scope because of the 'var' keyword
    let y = 30
    // y is in the local scope because of the 'let' keyword
    const z = 30
    // z is in the local scope because of the 'const' keyword
    console.log(x) // 30
    console.log(y) // 30
    console.log(z) // 30
  }
  console.log(x) // 30
  console.log(y) // 20
  console.log(z) // 20
}

console.log(x) // 30
console.log(y) // 10
console.log(z) // 10
1
Dava 9 Фев 2018 в 15:37

Просто чтобы добавить к другим ответам, область видимости является списком всех объявленных идентификаторов (переменных) и обеспечивает строгий набор правил, касающихся того, как они доступны для выполняемого в настоящее время кода. Этот поиск может быть использован для назначения переменной, которая является ссылкой LHS (слева), или для получения ее значения, которая является ссылкой RHS (правой стороны). Эти поиски - то, что движок JavaScript делает внутренне, когда он компилирует и выполняет код.

Таким образом, с этой точки зрения, я думаю, что поможет картина, которую я нашел в электронной книге «Области применения и замыкания» Кайла Симпсона:

image

Цитирую из его книги:

Здание представляет собой набор правил для вложенной области действия нашей программы. Первый этаж здания представляет вашу текущую область действия, где бы вы ни находились. Верхний уровень здания - глобальная сфера. Вы решаете рекомендации LHS и RHS, просматривая свой текущий этаж, а если вы его не находите, поднимаетесь на лифте на следующий этаж, смотрите там, затем на следующий и так далее. Как только вы попадаете на верхний этаж (глобальный охват), вы либо находите то, что ищете, либо нет. Но ты должен остановиться независимо.

Стоит упомянуть одну вещь: «Поиск в области видимости прекращается, когда он находит первое совпадение».

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

9
James Drinkard 30 Мар 2016 в 13:33

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

Элемент в цепочке областей действия - это в основном Map с указателем на родительскую область видимости.

При разрешении переменной javascript начинается с самой внутренней области и выполняет поиск за ее пределами.

232
krosenvold 14 Авг 2012 в 07:54

Идея определения объема в JavaScript, изначально разработанная Бренданом Айхом, возникла из HyperCard язык сценариев HyperTalk.

На этом языке показы были сделаны аналогично стопке карточек. Там была мастер-карта, называемая фоном. Это было прозрачно и может быть замечено как нижняя карта. Любой контент на этой базовой карте был предоставлен картам, размещенным поверх нее. Каждая карта, размещенная сверху, имела свой собственный контент, который имел приоритет над предыдущей картой, но при желании имел доступ к предыдущим картам.

Именно так спроектирована система определения объема JavaScript. У него просто разные имена. Карты в JavaScript известны как контексты выполнения ECMA . Каждый из этих контекстов состоит из трех основных частей. Переменная среда, лексическая среда и привязка this. Возвращаясь к справочнику карточек, лексическая среда содержит весь контент из предыдущих карточек ниже в стопке. Текущий контекст находится на вершине стека, и любой объявленный там контент будет храниться в переменной среде. Переменная среда будет иметь приоритет в случае именования коллизий.

Привязка this будет указывать на содержащий объект. Иногда контексты или контексты выполнения изменяются без изменения содержащего объекта, например, в объявленной функции, где содержащийся объект может быть window или функцией конструктора.

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

Это техническое объяснение. На практике важно помнить, что в JavaScript

  • Области применения технически "контексты исполнения"
  • Контексты образуют стек сред, в которых хранятся переменные
  • Вершина стека имеет приоритет (низ - глобальный контекст)
  • Каждая функция создает контекст выполнения (но не всегда новый, это связывание)

Применяя это к одному из предыдущих примеров (5. «Закрытие») на этой странице, можно следовать стекам контекстов выполнения. В этом примере в стеке три контекста. Они определяются внешним контекстом, контекстом в немедленно вызываемой функции, вызываемой var шестым, и контекстом в возвращаемой функции внутри немедленно вызываемой функции var шестого.

i ) Внешний контекст. Он имеет переменную среду = 1
ii ) Контекст IIFE имеет лексическое окружение a = 1, но переменное окружение a = 6, которое имеет приоритет в стеке
iii ) Возвращенный контекст функции имеет лексическое окружение a = 6, и это значение, на которое ссылается оповещение при вызове.

enter image description here

24
Travis J 14 Сен 2015 в 20:29

Современные Js, ES6 +, 'const' и 'let'

Для каждой создаваемой переменной вы должны использовать блочную область видимости, как и большинство других основных языков. var устарел . Это делает ваш код безопаснее и удобнее в обслуживании.

const следует использовать в 95% случаев . Это делает так, что переменная ссылка не может измениться. Свойства массива, объекта и узла DOM могут изменяться и, вероятно, должны быть const.

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

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

5
Gibolt 8 Дек 2017 в 19:03

В JS есть только функциональные области. Не блокируйте прицелы! Вы можете увидеть, что поднимает тоже.

var global_variable = "global_variable";
var hoisting_variable = "global_hoist";

// Global variables printed
console.log("global_scope: - global_variable: " + global_variable);
console.log("global_scope: - hoisting_variable: " + hoisting_variable);

if (true) {
    // The variable block will be global, on true condition.
    var block = "block";
}
console.log("global_scope: - block: " + block);

function local_function() {
    var local_variable = "local_variable";
    console.log("local_scope: - local_variable: " + local_variable);
    console.log("local_scope: - global_variable: " + global_variable);
    console.log("local_scope: - block: " + block);
    // The hoisting_variable is undefined at the moment.
    console.log("local_scope: - hoisting_variable: " + hoisting_variable);

    var hoisting_variable = "local_hoist";
    // The hoisting_variable is now set as a local one.
    console.log("local_scope: - hoisting_variable: " + hoisting_variable);
}

local_function();

// No variable in a separate function is visible into the global scope.
console.log("global_scope: - local_variable: " + local_variable);
4
koredalin 11 Июл 2015 в 18:13

Запустить код. надеюсь, что это даст представление о сфере охвата

Name = 'global data';
document.Name = 'current document data';
(function(window,document){
var Name = 'local data';
var myObj = {
    Name: 'object data',
    f: function(){
        alert(this.Name);
    }
};

myObj.newFun = function(){
    alert(this.Name);
}

function testFun(){
    alert("Window Scope : " + window.Name + 
          "\nLocal Scope : " + Name + 
          "\nObject Scope : " + this.Name + 
          "\nCurrent document Scope : " + document.Name
         );
}


testFun.call(myObj);
})(window,document);
8
Yeasin Abedin Siam 18 Окт 2014 в 09:54

Глобальная сфера:

Глобальные переменные точно такие же, как глобальные звезды (Джеки Чан, Нельсон Мандела). Вы можете получить к ним доступ (получить или установить значение) из любой части вашего приложения. Глобальные функции похожи на глобальные события (Новый год, Рождество). Вы можете выполнить (вызвать) их из любой части вашего приложения.

//global variable
var a = 2;

//global function
function b(){
   console.log(a);  //access global variable
}

Локальный охват:

Если вы находитесь в США, вы можете знать Ким Кардашьян, печально известную знаменитость (ей каким-то образом удается создавать таблоиды). Но люди за пределами США не узнают ее. Она местная звезда, привязанная к своей территории.

Локальные переменные похожи на локальные звезды. Вы можете получить к ним доступ только (получить или установить значение) внутри области. Локальная функция похожа на локальные события - вы можете выполнять только (праздновать) внутри этой области. Если вы хотите получить к ним доступ за пределами области действия, вы получите ошибку ссылки

function b(){
   var d = 21; //local variable
   console.log(d);

   function dog(){  console.log(a); }
     dog(); //execute local function
}

 console.log(d); //ReferenceError: dddddd is not defined    

Проверьте эту статью для глубокого понимания области

8
John Slegers 23 Фев 2016 в 18:56

В «Javascript 1.7» (расширение Mozilla до Javascript) можно также объявить переменные области блока с помощью { {X0}} заявление:

 var a = 4;
 let (a = 3) {
   alert(a); // 3
 }
 alert(a);   // 4
26
kennytm 6 Апр 2010 в 11:19

Насколько я понимаю, есть 3 области: глобальная область, доступная глобально; локальная область, доступная для всей функции независимо от блоков; и область видимости блока, доступная только блоку, выражению или выражению, в котором он был использован. Глобальная и локальная область видимости указываются с помощью ключевого слова var как внутри функции, так и снаружи, а область видимости блока указывается с помощью ключевого слова let.

Для тех, кто считает, что существует только глобальная и локальная область видимости, пожалуйста, объясните, почему у Mozilla будет целая страница, описывающая нюансы области видимости блока в JS.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let

3
mrmaclean89 16 Сен 2017 в 22:35