Какова область действия функции в Javascript / ECMAScript? - PullRequest
12 голосов
/ 25 октября 2008

Сегодня у меня был разговор с коллегой о вложенных функциях в 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 ]

22 голосов
/ 25 октября 2008

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

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

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

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

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

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

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

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

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

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

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

8.8.1 Лексическое определение объема

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

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

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

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

4 голосов
/ 25 октября 2008

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

function a() { ... }

и

var a = function() { ... }
2 голосов
/ 25 октября 2008

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

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

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

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

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

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

1 голос
/ 25 октября 2008

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

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

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

0 голосов
/ 25 октября 2008

...

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