为啥正文中的 javascript 函数优先于头部中的函数?

Posted

技术标签:

【中文标题】为啥正文中的 javascript 函数优先于头部中的函数?【英文标题】:Why javascript function in the body takes precedence over function in the head?为什么正文中的 javascript 函数优先于头部中的函数? 【发布时间】:2018-06-03 04:49:47 【问题描述】:

我试图了解 javascript 中的执行顺序。为什么body中的foo优先于head中的foo。不是先编译的head里的foo吗?

<head>
  <meta charset="UTF-8">
  <title>Hello</title>

  <script type="text/javascript">
    function foo() 
      greeting = "hello from the head";
      alert(greeting);
    
  </script>
</head>

<body>
  <div id="clickMe" onclick="foo()">Click me</div>
  <script>
    function foo() 
      greeting = "hello from the body";
      alert(greeting);
    
  </script>
</body>

</html>

【问题讨论】:

【参考方案1】:

以后的函数声明会覆盖旧的函数声明。在新函数被声明之前,旧函数仍然可以被调用:

<script type="text/javascript">
  function foo() 
    greeting = "hello from the head";
    alert(greeting);
  
  foo();
</script>
<div id="clickMe" onclick="foo()">Click me</div>
<script>
  function foo() 
    greeting = "hello from the body";
    alert(greeting);
  
</script>

但是一旦较低的脚本标签运行,函数名就会被重新分配。如果你这样看可能更有意义,每个函数都重新分配window.foo

<script type="text/javascript">
  window.foo = function foo() 
    greeting = "hello from the head";
    alert(greeting);
  
</script>
<div id="clickMe" onclick="window.foo()">Click me</div>
<script>
  window.foo = function foo() 
    greeting = "hello from the body";
    alert(greeting);
  
</script>

【讨论】:

Javascript 未被解释。它有一个运行时编译器。【参考方案2】:

这与两次声明同一个函数没有什么不同

function foo() 
  console.log("first");


function foo() 
  console.log("second");


foo();  // prints "second"

这在某种程度上与此没有什么不同

let bar;
bar = 1;
bar = 2;

bar 现在是2

您可以通过使用不同的语法来避免这种情况

const foo = () => 
  console.log("first");
;

const foo = () => 
  console.log("second");
;

在这种情况下你会得到一个错误

Uncaught SyntaxError: Identifier 'foo' has already been declared

而且似乎可以跨脚本工作

<script>
const foo = () => 
  console.log("first");
;
</script>
<script>
const foo = () => 
  console.log("second");
;
</script>

【讨论】:

【参考方案3】:

这就是所谓的影子。

JS 编译器提升脚本中的函数。后面的会用相同的名字覆盖前面的遭遇。

function foo() 
   console.log('Foo early');


function foo() 
   console.log('Foo late');


foo();    //Foo leate

【讨论】:

这不是阴影。不同之处在于阴影意味着仍然存在对原始定义的引用。 阴影如何引用原始定义?能举个例子吗? var array = []; array.map = () =&gt; ; array.map(); /* returns undefined */ delete array.map; array.map(() =&gt; ); /* returns array */ 这使用原型链来隐藏 map() 的定义。在HTMLInputElement 上使用具有相同名称的 DOM 元素属性和属性时存在类似的示例,例如 value 那是属性阴影。虽然这是真的,但它并没有使 OP 的案例不被遮蔽。后面的声明会影响前面的提升函数。 “属性阴影”,不管你喜欢怎么称呼它,仍然存在于***函数声明中,它只是window 的一个自己的属性。例如function addEventListener () 会影响window.addEventListener,因为它不是window 自己的属性,但function prompt () 会覆盖window.prompt,因为它 window 的自己的属性【参考方案4】:

基本上只是因为主体中的那个是它读取的最后一个函数,所以它只是坚持下去。

记住 HTML 文档是从上到下读取的,所以如果你有两个相同函数的实例,它实际上会保留最接近文档末尾的那个

【讨论】:

以上是关于为啥正文中的 javascript 函数优先于头部中的函数?的主要内容,如果未能解决你的问题,请参考以下文章

在 Python 中,为啥属性优先于实例属性?

为啥&&和||优先于 -a 和 -o

为啥跳过列表不优先于数据库的 B+-树?

javascript 使用对象优先于数组删除重复项。

CNAME 记录中的 * 是不是优先于显式子域?

是否可以强制超类中的非常量虚拟方法优先于子类中同名的 const 方法?