JavaScript 中的保留函数名称

Reserved function names in JavaScript

重命名我的函数后,代码停止工作。新名称 scrollIntoView 似乎与 element.scrollIntoView() 方法冲突。

<div onmousedown="scrollIntoView('id001')"/>

function scrollIntoView(id) {
    alert(id);
}

我创建了一个简单的测试用例 https://jsfiddle.net/mgtn215y/,它表明我的函数被忽略了 element.scrollIntoView() 甚至

解决方案很明显 - 使用不同的函数名称。由于这种行为在主要浏览器中是一致的,我希望这在某处指定。但是,我找不到任何相关内容,例如JavaScript lexical grammar。这种行为有什么背景吗?

要覆盖,只需尝试:

Element.prototype.scrollIntoView = function(id) {
    alert(id);
}

但请注意它适用于 addEventListener:

var element = document.getElementById("element");

function scrollIntoView(id) {
    alert(id);
}

element.addEventListener("mousedown", function() {
    scrollIntoView("id001");
});
div {
  width: 100px;
  height: 100px;
  background-color: red;
  cursor: pointer;
}
<div id="element"></div>

出于某些奇怪的原因,内联处理程序在 运行 时似乎隐式使用 with(this),其中 this 引用触发事件的元素。每当您尝试引用某些内容时,如果该内容作为 this 的 属性 存在,那么 that 属性 将最终被引用,而不是具有相同名称的外部变量:

console.log(typeof className); // Undefined in standard global scope
console.log(typeof scrollIntoView); // Undefined in standard global scope
.mydiv {
  width: 100px;
  height: 100px;
  background-color: red;
  cursor: pointer;
}
<div class="mydiv" onclick="
  console.log(typeof className); // Defined inside inline handler
  console.log(typeof scrollIntoView); // Defined inside inline handler
">

对于解释器来说,onclick 实际上看起来更像:

onclick="with(this) {
  console.log(typeof className);
  console.log(typeof scrollIntoView);
}"

这很奇怪。但是内联事件处理程序无论如何都是糟糕的做法,可能不应该使用;使用 addEventListeneronkeydown 正确分配处理程序:

document.querySelector('.mydiv').onmousedown = () => scrollIntoView("id001");
function scrollIntoView(id) {
  console.log(id);
}
.mydiv {
  width: 100px;
  height: 100px;
  background-color: red;
  cursor: pointer;
}
    <div class="mydiv"></div>

问题是从 HTML 源中声明的 HTML 元素属性值编译的函数范围链。 on_eventName=functionBodyCode 形式的属性表现出这种行为。

由于历史原因(DOM 的当前形式不存在,document.getElementByID 还没有被发明......)这些函数是用一个作用域链编译的,该作用域链包含对象提供了事件处理程序属性、元素所在的任何 form 元素以及 document 对象。 但是 不同的浏览器在模拟 Netscape 行为时采用了不同的方法。一些浏览器包含了提供事件处理程序属性的元素的所有父对象,而其他浏览器则省略了一些相关对象,例如 document.

技术细节可以在“Javascript 权威指南”O'Reilly,“19.1.6. 事件处理程序的范围”一节中找到。

主要建议是避免在 HTML 中提供事件处理程序 - 使用 addEventListener 将它们添加到 JavaScript 中。如果出于某种原因必须在 HTML 属性值中对函数调用进行编码,请避免使用作为 DOM 对象方法的函数名称。

请注意,事件处理程序的自定义作用域链仅适用于从 HTML 属性生成的函数。它 适用于在 JavaScript 中创建并使用 addEventListenerelement.onEventName=aFunctionObject.

添加到元素的函数

以下代码片段演示了在 HTML 中定义的事件处理程序范围链中定位 属性 外部元素的名称::

<form name="formName1" action="">
<p> Try to access the elements collection of the form:
   <button type="button"
      onclick="console.log( elements);">elements
   </button>
</p>

</form>
<form name="formName2" action="" onsubmit="return false">
<p> Try to access form name as form.name:
  <button type="button"
     onclick="console.log( 'form.name: %s', form.name);">form.name
  </button>
</p>
</form>

<form name="formName3" action="" onsubmit="return false">
<p>Access document.write as "write"
   <button type="button"
      onclick="console.log( 'write: %s', write);">write
   </button>
</p>
</form>

  • 在第一种形式中,elements是周围形式元素的属性。

  • 在第二种形式中,form 是 HTMLButtonElement 的 属性。

  • 在第三种形式中,writedocument的一个方法。

  • 引用 2020 年,HTML5 将 HTML 属性处理程序的范围链指定为“Scope 下的“元素 > 外部形式元素 > 文档” " internal raw uncompiled handler 的编号列表项 3.9 中。