Ссылка на значение 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... присваивает переменную, что я не уверен точно всю область действия, но я понимаю, что она не добавлена ​​в словарь таблицы функций, как первый.