在声明之前引用 JavaScript 值 - 有人可以解释一下吗

IT技术 javascript
2021-03-15 09:03:06

我希望有人可以向我解释为什么在浏览器中查看 HTML 时,下面的 JavaScript/HTML 会显示“门 #2”:

<!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在第二个声明中覆盖 dos的行为testprint它没。请注意,如果我将第四个声明移动到第testprint一个脚本块的末尾,它将被调用window.onload

3个回答

函数声明是提升的主题,它们在解析时被评估,通过提升意味着它们可用于声明它们的整个范围,例如:

foo(); // alerts foo
foo = function () { alert('bar')};
function foo () { alert('foo');}
foo(); // alerts bar

第一次调用foo将执行函数声明,因为在解析时它可用,第二次调用foo将执行运行时声明函数表达式

有关函数表达式和函数声明之间差异的更详细讨论,请查看此问题本文

浏览器不同意的情况下,函数提升有一个微妙之处SpiderMonkey 不会提升在条件作用域中声明的函数,而V8(在撰写本文时)会这样做。
2021-05-02 09:03:06

#3 不改变 window.onload 的原因是函数是通过引用而不是名称调用的。当您设置 时window.onload = testprint,它会将对testprint(门 #2,如 CMS 所解释的)的当前值的引用分配window.onloadtestprint稍后更改的值不会影响window.onload的值。

门 #4 不会覆盖门 #2(除非,正如你所说,你将它移到第一个脚本块),因为它在不同的脚本块中,所以它在第一个块完成后被解析。

功能 testprint 对页面是全局的。testprint = function... 分配了一个变量,我不确定它的整个范围,但我知道它没有像第一个那样添加到函数表字典中。