Reserved function names in JavaScript

好久不见. 提交于 2019-12-23 22:18:27

问题


After renaming my function the code stopped working. That new name scrollIntoView seems to be clashing with the element.scrollIntoView() method.

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

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

I've created a simple test case https://jsfiddle.net/mgtn215y/ which has shown my function is simply ignored in favor of element.scrollIntoView() even

  • it is not called on element
  • attributes do not match

The solution is obvious - to use a different function name. As this behavior is consistent across major browsers, I expect this is specified somewhere. However, I couldn't find anything related in e.g. JavaScript lexical grammar. Is there any background for this behavior?


回答1:


The issue is the scope chain of functions compiled from HTML element attribute values declared in HTML source. Attributes of the form on_eventName=functionBodyCode exhibit this behavior.

For historical reasons (the DOM did not exist in its current form, document.getElementByID had yet to be invented...) such functions are compiled with a scope chain comprising the object on which the event handler attribute is provided, any form element the element is within, and the document object. However different browsers took different approaches when emulating Netscape behavior. Some browsers included any and every parent object of an element providing an event handler attribute, while others omitted some pertinent objects such as document.

Technical detail may be found in "Javascript the definitive guide" O'Reilly, section "19.1.6. Scope of Event Handlers".

The main recommendation is to avoid supplying event handlers in HTML - add them in JavaScript using addEventListener instead. If for some reason function calls must be coded in HTML attribute values, avoid using function names that are methods of DOM objects.

Note the custom scope chain for event handlers only applies to functions generated from HTML attributes. It does not apply to functions created in JavaScript and added to an element using addEventListener or element.onEventName=aFunctionObject.


The following snippet demonstrates locating property names of outer elements in the scope chain of event handlers defined in 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>
  • In the first form, elements is a property of the surrounding form element.

  • In the second form, form is a property of the HTMLButtonElement.

  • In the third form, write is a method of document.




回答2:


For some strange reason, it looks like inline handlers implicitly use with(this) when they run, where this references the element that triggered the event. Whenever you try to reference something, if that something exists as a property of this, then that property will end up being referenced, rather than an outer variable with the same name:

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
">

To the interpreter, the onclick actually looks something more like:

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

It's pretty strange. But inline event handlers are terrible practice anyway, and probably shouldn't be used; assign the handler properly with addEventListener or onkeydown instead:

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>



回答3:


To override, simply try:

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

But do note that it works with 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>


来源:https://stackoverflow.com/questions/52599614/reserved-function-names-in-javascript

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!