Какова область действия функции в Javascript/ECMAScript?

Сегодня у меня была дискуссия с коллегой о вложенных функциях в Javascript:

function a() {
   function b() {
      alert('boo')
   }
   var c = 'Bound to local call object.'
   d = 'Bound to global object.'
}

В этом примере испытания показывают, что b недостижим за пределами тела a, как и c. Однако d есть - после выполнения a(). Ищите точное определение этого поведения в ECMAScript v. 3 стандарт, я не нашел точной формулировки, которую искал; о чем не говорится в разделе 13, стр. 71, так это о том, к какому объекту должен быть привязан объект функции, созданный оператором объявления функции. Я что-то упускаю?


person Dong Hoon    schedule 24.10.2008    source источник


Ответы (5)


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

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

Кроме того, чтобы ответить на вторую часть вашего вопроса: функция существует в любой области, в которой она объявлена, точно так же, как переменная.

Примечание: вам, вероятно, не нужны глобальные переменные, особенно те, которые не подразумеваются. Рекомендуется всегда использовать ключевое слово var, чтобы избежать путаницы и сохранить все в чистоте.

Примечание. Стандарт ECMA, вероятно, не самое полезное место для поиска ответов о Javascript, хотя, безусловно, это не плохой ресурс. Помните, что javascript в вашем браузере — это всего лишь реализация этого стандарта, поэтому документ стандартов будет давать вам правила, которым (в основном) следовали разработчики при создании движка javascript. Он не может предоставить конкретную информацию об интересующих вас реализациях, а именно об основных браузерах. В частности, есть пара книг, которые дадут вам очень прямую информацию о том, как ведут себя реализации javascript в основных браузерах. Чтобы проиллюстрировать разницу, ниже я приведу выдержки из спецификации ECMAScript и книги по Javascript. Я думаю, вы согласитесь, что книга дает более прямой ответ.

Вот из Спецификации языка ECMAScript:

10.2 Вход в контекст выполнения

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

Когда элемент управления входит в контекст выполнения, создается и инициализируется цепочка областей видимости, выполняется создание экземпляра переменной и определяется значение this.

Инициализация цепочки областей видимости, создание экземпляра переменной и определение значения this зависят от типа вводимого кода.

Вот цитата из :

8.8.1 Лексическая область видимости

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

Настоятельно рекомендуется для освещения подобных вопросов книга Дугласа Крокфорда:

http://oreilly.com/catalog/covers/9780596517748_cat.gif

Javascript, лучшие стороны, также от O'Reilly.

person Community    schedule 24.10.2008
comment
Совершенно верно -- вообще говоря, function a(){} эквивалентно var a = function(){} (есть небольшие семантические различия, но ничего особенного). - person olliej; 25.10.2008
comment
спасибо, но где я могу найти следующие утверждения в стандарте ECMAScript (или они отсутствуют?): операторы внутри функции ограничены областью действия этой функции. По моему мнению, семантика var a= function(){} хорошо определена, но не семантика оператора function a(){...}. - person Dong Hoon; 25.10.2008
comment
Стандарт ECMAScript даст вам только рекомендации по реализации ECMAScript, из которых Javascript является лишь одним из членов семьи. Таким образом, вы не найдете это точное утверждение, но есть другие ресурсы, которые могут вам помочь. См. мое дополнительное примечание выше. - person keparo; 26.10.2008
comment
Большое спасибо за подробное объяснение, keparo! Я действительно понял из обоих цитируемых источников, что ‹i›внутри‹/i› тела функции локальные переменные привязаны к локальному контексту выполнения. Однако семантика вложенного оператора ‹b›function‹/b› в этом отношении нигде не эксплицируется. Я знаю, что стандарт ничего не должен говорить о реализациях (среди которых Javascript), хотя он должен быть недвусмысленным в отношении семантики всех его элементов и конструкций. Спасибо также за указатель на книгу Дугласа Крокфорда --- не знал. - person Dong Hoon; 27.10.2008

Насколько я понимаю, они эквивалентны в отношении области видимости:

function a() { ... }

а также

var a = function() { ... }
person eyelidlessness    schedule 24.10.2008

Кажется важным отметить, что хотя d создается как «глобальный», на самом деле он создается как свойство объекта окна. Это означает, что вы можете непреднамеренно перезаписать что-то, что уже существует в объекте окна, или ваша переменная может вообще не быть создана. Так:

function a() {
    d = 'Hello World';
}
alert(window.d); // shows 'Hello World'

Но вы не можете сделать:

function a() {
    document = 'something';
}

потому что вы не можете перезаписать объект window.document.

Для всех практических целей вы можете представить, что весь ваш код выполняется в гигантском блоке with(window).

person Prestaul    schedule 24.10.2008
comment
Да, такое поведение указано в гл. 10.1.9 стандарта ECMAScript. - person Dong Hoon; 25.10.2008

Javascript имеет две области видимости. Глобально и функционально. Если вы объявите переменную внутри функции с помощью ключевого слова «var», она будет локальной для этой функции и любых внутренних функций. Если вы объявляете переменную вне функции, она имеет глобальную область видимости.

Наконец, если вы опускаете ключевое слово var при первом объявлении переменной, javascript предполагает, что вам нужна глобальная переменная, независимо от того, где вы ее объявляете.

Итак, вы вызываете функцию а, а функция а объявляет глобальную переменную d.

person Alan Storm    schedule 24.10.2008

...

function a() {
   function b() {
      alert('boo')
   }
   var c = 'Bound to local call object.'
   d = 'Bound to global object.'
}

без предшествующего var, d является глобальным. Сделайте это, чтобы сделать d частным:

function a() {
   function b() {
      alert('boo')
   }
   var c = 'Bound to local call object.'
   var d = 'Bound to local object.'
}
person rp.    schedule 24.10.2008