Какова область действия функции в Javascript/ECMAScript?
-
04-07-2019 - |
Вопрос
Сегодня я обсуждал с коллегой вложенные функции в 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, так это то, к какому объекту должен быть привязан объект функции, созданный оператором объявления функции.Я что-то пропустил?
Решение
Это статическая область видимости.Операторы внутри функции ограничены этой функцией.
Однако Javascript имеет необычное поведение: без вар ключевое слово, вы подразумевали глобальная переменная.Это то, что вы видите в своем тесте.Ваша переменная «d» доступна, поскольку она является подразумеваемой глобальной, несмотря на то, что она записана в теле функции.
Также, чтобы ответить на вторую часть вашего вопроса:Функция существует в любой области видимости, как и переменная.
Примечание: Вероятно, вам не нужны глобальные переменные, особенно неявные.Рекомендуется всегда использовать ключевое слово var, чтобы избежать путаницы и сохранить чистоту.
Примечание:Стандарт ECMA, вероятно, не самое полезное место для поиска ответов о Javascript, хотя это определенно неплохой ресурс.Помните, что javascript в вашем браузере — это всего лишь реализация этого стандарта, поэтому документ по стандартам будет содержать правила, которым (в основном) следовали разработчики при создании движка javascript.Он не может предоставить конкретную информацию о интересующих вас реализациях, а именно об основных браузерах.В частности, есть пара книг, которые дадут вам очень прямую информацию о том, как ведут себя реализации javascript в основных браузерах.Чтобы проиллюстрировать разницу, я приведу ниже выдержки из спецификации ECMAScript и книги по Javascript.Я думаю, вы согласитесь, что книга дает более прямой ответ.
Вот из Спецификация языка ECMAScript:
10.2 Вход в контекст выполнения
Каждый вызов функции и конструктора входит в новый контекст выполнения, даже если функция рекурсивно вызывает себя.Каждый возврат выходит из контекста выполнения.Исключение, если не поймать, может также выйти из одного или нескольких контекстов выполнения.
Когда элемент управления входит в контекст выполнения, цепочка областей создается и инициализируется, выполняется переменная экземпляра, и это значение определяется.
Инициализация цепочки объема, переменной экземпляры и определение этого значения зависят от типа введенного кода.
Вот из О'Рейли Javascript:Полное руководство (5-е издание):
8.8.1 Лексическая область видимости
Функции в JavaScript лексически, а не динамически охватываются.Это означает, что они работают в сфере, в которой они определены, а не в сферу, из которого они выполнены.Когда функция определяется, цепочка объема тока сохраняется и становится частью внутреннего состояния функции....
Для освещения подобных вопросов настоятельно рекомендуется прочитать книгу Дугласа Крокфорда:
JavaScript, хорошие детали http://oreilly.com/catalog/covers/9780596517748_cat.gif
Javascript, Хорошие стороны, также от О'Рейли.
Другие советы
Насколько я понимаю, они эквивалентны с точки зрения области видимости:
function a() { ... }
и
var a = function() { ... }
Кажется важным отметить, что хотя d создается как «глобальный», в действительности он создается как свойство объекта window. Это означает, что вы можете случайно перезаписать то, что уже существует в объекте окна, или ваша переменная может вообще не быть создана. Итак:
function a() {
d = 'Hello World';
}
alert(window.d); // shows 'Hello World'
Но вы не можете сделать:
function a() {
document = 'something';
}
потому что вы не можете перезаписать объект window.document.
Для практических целей вы можете представить, что весь ваш код выполняется в гигантском блоке с (окном)
.
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.'
}
без предшествования вар, d является глобальным.Сделайте это, чтобы сделать d приватным:
function a() {
function b() {
alert('boo')
}
var c = 'Bound to local call object.'
var d = 'Bound to local object.'
}