Ссылка на значение JavaScript до его объявления - может кто-нибудь объяснить это
Я надеюсь, кто-то может объяснить мне, почему ниже JavaScript/HTML покажет "дверь №2", когда HTML просматривается в браузере:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<script type="text/javascript">
function testprint() {
alert('door #1');
};
window.onload = testprint;
function testprint() {
alert('door #2');
};
testprint = function() {
alert('door #3');
};
</script>
<script type="text/javascript">
function testprint() {
alert('door #4');
};
</script>
</head>
<body>
</body>
</html>
Поскольку только объявление testprint
встречается до того, как window.onload
установлено в testprint
, я ожидаю, что window.onload
приведет к появлению "двери №1". Фактически, onload вызывает "дверь № 2". Обратите внимание, что это сделает это, если включено первое объявление testprint
.
В третьем и четвертом объявлении testprint
используются разные способы назначения функции, я попробовал это, чтобы увидеть, будет ли она переопределять поведение window.onload
в том же самом, что и второе объявление testprint
. Это не так. Обратите внимание, что если я переместил четвертое объявление testprint
в конец первого блока script, он будет вызываться window.onload
.
Ответы
Ответ 1
Объявления функций подлежат подъему, и они оцениваются во время разбора, путем подъема означает, что они доступны для всего объема в том месте, где они были объявлены, например:
foo(); // alerts foo
foo = function () { alert('bar')};
function foo () { alert('foo');}
foo(); // alerts bar
Первый вызов foo
выполнит объявление функции, поскольку во время разбора он был доступен, второй вызов foo
выполнит выражение функции . > , объявленный во время выполнения.
Для более подробного обсуждения различий между выражениями функций и деклараций функций, проверьте этот вопрос и в этой статье.
Ответ 2
Причина № 3 не меняет window.onload - это то, что функции вызываются по ссылке, а не по имени. Когда вы устанавливаете window.onload = testprint
, он присваивает ссылку на текущее значение testprint
(дверь # 2, как объясняется CMS) на window.onload
. Изменение значения testprint
позже не влияет на значение window.onload
.
Дверь №4 не переопределяет дверь № 2 (если, как вы сказали, вы не переместите ее в первый блок script), потому что она находится в другом блоке script, поэтому он получает синтаксический анализ после того, как первый блок завершено.
Ответ 3
Функция testprint является глобальной для страницы.
testprint = function... присваивает переменную, что я не уверен точно всю область действия, но я понимаю, что она не добавлена в словарь таблицы функций, как первый.