Какова область действия функции в 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 standard, я не нашел точной формулировки, которую я искал; что не указано в Sec.13 p.71, является ли объект, к которому должен привязываться объект функции, созданный оператором объявления функции. Я что-то пропустил?

Ответ 1

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

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

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

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

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

Здесь из Спецификация языка ECMAScript:

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

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

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

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

Здесь из O'Reilly Javascript: окончательное руководство (5-е издание):

8.8.1 Лексическое обследование

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

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

JavaScript, хорошие части http://oreilly.com/catalog/covers/9780596517748_cat.gif

Javascript, The Good Parts, также из O'Reilly.

Ответ 2

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

function a() { ... }

и

var a = function() { ... }

Ответ 3

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

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

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

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

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

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

Ответ 4

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

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

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

Ответ 5

...

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.'
}