Знаете ли вы JavaScript

У Дмитрия Барановского (это автор Raphaël — JavaScript-библиотеки для построения диаграмм) в бложике нашёл чудесный тест на знание JavaScript, привожу его здесь полностью. Попробуйте, я прошёл его довольно посредственно.

Итак, что выведет каждый кусок кода?

if (!("a" in window)) {
    var a = 1;
}
alert(a);
var b = function a(x) {
    x && a(--x);
};
alert(a);
function a(x) {
    return x * 2;
}
var a;
alert(a);
function b(x, y, a) {
    arguments[2] = 10;
    alert(a);
}
b(1, 2, 3);
function a() {
    alert(this);
}
a.call(null);
Поделиться
Отправить
38 комментариев
Alisey (alisey.myopenid.com)

На первый неправильно ответил. Так и не понял как оно работает.

Евгений Степанищев (bolknote.ru)

Комментарий для alisey.myopenid.com:

Насколько я это понимаю, интерпретатор смотрит вперёд и создаёт переменные в зоне видимости и только потом выполняет код, но могу и ошибаться.

А как последний работает и какой смысл во втором?

arikon (sergeybelov.ru)

Комментарий для Евгения Степанищева:

В первом же всё очевидно? Атрибута «a» в window нет, и ему там неоткуда появится после if, поэтому undefined.

Тайный смысл второй конструкции я совсем не понял.

В третьем для меня было не очевидно, что var не переинициализирует переменную.

В четвёртом логично, что a и arguments[2] — это ссылка на одно и то же значение. Иначе попадаем на память.

В пятом: this в глобальной области указывает на window. Вызов call() у функции с параметром null равнозначно вызову call() без аргументов. А без аргументов вызываемая функция не «биндится» ни к какому объекту (или «биндится» к «объекту по умолчанию» — window).

Я всё так это понимаю.

Евгений Степанищев (bolknote.ru)

Комментарий для sergeybelov.ru:

Попробуй в первом примере поставить alert внутри if.

arikon (sergeybelov.ru)

Комментарий для Евгения Степанищева:

Может я что-то не понимаю, но интерпретатор в if не заходит. И, как бы, не должен.

Вот этот код алертит один раз undefined.
<script type=«text/javascript»>
if (!(«a» in window)) {
    var a = 1;
    alert(a);
}
alert(a);
</script>

Евгений Степанищев (bolknote.ru)

Комментарий для sergeybelov.ru:

Теперь убери «var» (alert оставь), тебе по прежнему кажется, что ты понимаешь как это работает?

ExH (exh.myopenid.com)

Запись var a = 1; в глобальном скопе означает window.a = 1;

Вот ещё забавно:
if (!(«a» in window)) {
alert( ’no’ );
}
alert(window.a);

Получается что не важно где задаётся var a или window.a, оно инициализируется в любом случае.

Алик Кириллович (www.alik.su)

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

Точно также, конструкция function f () {} объявляет функцию во всей лексической области видимости, вне зависимости от того, на какой конкретно строчке находится эта конструкция.

Например, функцию можно объявить уже после ее использования:

alert (f (5))
function f (x) {return (x*x)}

Или даже на той строчке, на которую никогда не ступит нога интерпретатора:

if (false)
  {
  function f (x) {return (x*x)}
  }

alert (f (5))

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

Евгений Степанищев (bolknote.ru)

Комментарий для www.alik.su:

Я там во втором комменте примерно то же самое и написал :)

Евгений Степанищев (bolknote.ru)

Комментарий для exh.myopenid.com:

Это одна из первых вещей, которую я узнал о JS — что всё, что в глобальной зоне видимости, создаётся в window.

zeroglif.livejournal.com

Что выведет второй кусок в IE? Неоднозначный вопрос, в общем.

zeroglif.livejournal.com

Комментарий для www.alik.su:

Объявленная функция внутри if(false) по-разному воспринимается браузерами, это своя трактовка стандарта.

astur (astur.net.ru)

Второй пример — вуду, однозначно. Хоть кто-нибудь объясните, что там происходит.

shabunc.ya.ru

Комментарий для www.alik.su:

нет, в файрфоксе if’ы обрубят определение функции
здесь это важно понимать )))

Алик Кириллович (www.alik.su)

Комментарий для zeroglif.livejournal.com:

Объявленная функция внутри if(false) по-разному воспринимается браузерами, это своя трактовка стандарта.

Какие браузеры как-то иначе воспринимают эту конструкцию?

Евгений Степанищев (bolknote.ru)

Комментарий для astur.net.ru:

Это вуду не работает в моей «Опере» 10 :)

Алик Кириллович (www.alik.su)

Хотя, да.

Евгений Степанищев (bolknote.ru)

Комментарий для zeroglif.livejournal.com:

В IE он выведет тело функции, а вот мой основной браузер (Opera 10) скажет, что там ошибка (нет переменной «а»).

Алик Кириллович (www.alik.su)

Да, действительно, в FF функция не будет объявлена, если она определена в любой вложенном блоке: if, while и т. д.

Т. е. такой пример сработает:

alert (f (5))
function f (x) {return (x*x)}

А вот такой уже нет (даже с условием true):

alert (f (5))
if (true)
  {
  function f (x) {return (x*x)};
  }

Однако, если функция находится НЕ во вложенном блоке, то она БУДЕТ объявлена. Даже если до ее строчки интерпретатор заведомо никогда не дойдет:

function main ()
  {
  alert (f (5));
  return;
  function f (x) {return (x*x)};
  }
main ();

Alisey (alisey.myopenid.com)

Второй пример — не вуду. Всё зависит от реализации, но в целом так:

b = function a() { ...по имени «a» функцию видно только здесь }

...а здесь undefined (если выше не определили)

Евгений Степанищев (bolknote.ru)

Комментарий для alisey.myopenid.com:

Забавно, спасибо. Как я уже говорил, в «Опере» это не так.

astur (astur.net.ru)

Комментарий для alisey.myopenid.com:

У меня в FF второй пример не делает вообще ничего. Даже алерт не выбрасывает.

Евгений Степанищев (bolknote.ru)

Комментарий для astur.net.ru:

Возможно, JS-ошибка.

arty (arty.name)

Комментарий для Евгения Степанищева:

alisey.myopenid.com написал всё правильно, кроме последней строчки. Да, действительно имя a видно только внутри функции, поэтому снаружи функции такое имя вообще не задано, и опера выдаёт Undefined variable: a. То есть, «такого имени в scope вообще нет», а не «такое имя есть, но значение ему не присвоено»

arty (arty.name)

Комментарий для Евгения Степанищева:

а, ну да, показывается это сообщение не в алёрте, а в консоли

имхо какой-то смысл имеют только первые два примера, остальное — знакомство с извращениями

Евгений Степанищев (bolknote.ru)

Комментарий для arty.name:

Возможно. Очень обидно, что в таких вещах браузеры ведут себя по-разному. Можно наступить на большое количество граблей.

arty (arty.name)

Комментарий для Евгения Степанищева:

имхо, примеры, начиная с третьего — ошибки, глумление над программированием, которое нельзя использовать в практике, поэтому всё равно, что как браузеры обрабатывают эти ошибки

1smash1.livejournal.com

Комментарий для arty.name:

Что бы вы понимали вообще в программировании програм.

Эти примеры нужны для того, чтоб понимать что происходит с вашим кодом и как именно устроен ваш инструмент.

arikon (sergeybelov.ru)

Комментарий для Евгения Степанищева:

Да, всё ещё понимаю =)

JS интерпретируется как бы в 2 этапа.
Сначала создаются «глобальные» объекты -​-​ функции, глобальные переменные и т. п. Потом выполняется код. Это и позволяет определять функции в произвольном месте кода, в том числи позже первого использования.

Вижу, об этом выше уже написали.

zeroglif.livejournal.com

Комментарий для sergeybelov.ru:

Сначала создаются «глобальные» объекты

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

zeroglif.livejournal.com

Комментарий для www.alik.su:

Однако, если функция находится НЕ во вложенном блоке, то она БУДЕТ объявлена

Всё так, я просто обратил внимание на то, что и у вас, и у автора теста были приведены неоднозначные (браузерозависимые) примеры. Результат будет зависить от консоли. ;)

Евгений Степанищев (bolknote.ru)

Комментарий для sergeybelov.ru:

Ну, это мой первый комментарий в этом посте.

arty (arty.name)

Комментарий для 1smash1.livejournal.com:

ой-ой, гуру % )

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

Dmitry Baranovskiy (dmitry.baranovskiy.com)

Комментарий для zeroglif.livejournal.com:

Действительно второй пример в IE отрабатывает неправильно. Можно в начале написать var a = 1; тогда результат будет одинаковый. Там был ещё один пример изначально: alert(1 in [,,2]), но пришлось убрать из-за Firefox. :)
Ещё буквально вчера добавил:
var a = 5;
a.t = 3;
alert(a.t);

sharovatov.livejournal.com

что интересно, в багзилле наличествует баг про первый кусок кода —  https://bugzilla.mozilla.org/show_bug.cgi?id=468096

Евгений Степанищев (bolknote.ru)

Комментарий для dmitry.baranovskiy.com:

А! Это я знаю. Что в JavaScript два вида типов :)

zeroglif.livejournal.com

Комментарий для dmitry.baranovskiy.com:

буквально вчера добавил

Усилить хочется:
var a = 5;
alert(a.t = 3);
alert(a.t);

Dmitry Baranovskiy (dmitry.baranovskiy.com)

Комментарий для zeroglif.livejournal.com:

Хорошее дополнение :)

Популярное