Какова область действия функции в 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 is - после выполнения (). В поисках точного определения этого поведения в стандарте ECMAScript v.3 я не нашел точную формулировку, которую искал; то, что не указано в разделе 13 стр.71, - это какой объект должен быть связан с объектом функции, созданным оператором объявления функции. Я что-то пропустил?

5 ответов

Решение

Это статический обзор. Операции внутри функции находятся в пределах этой функции.

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

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

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

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

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

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

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

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

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

Вот из Javascript О'Рейли : Полное руководство (5-е издание):

8.8.1 Лексический обзор

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

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

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

Javascript, The Good Parts, также от О'Рейли.

Насколько я понимаю, это равнозначно, насколько это важно:

function a() { ... }

а также

var a = function() { ... }

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

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

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

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

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

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

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

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

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

...

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

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

function a() {
   function b() {
      alert('boo')
   }
   var c = 'Bound to local call object.'
   var d = 'Bound to local object.'
}
Другие вопросы по тегам