Special scopes of inline event processing functions of elements vary with browsers.

Source: Internet
Author: User

Standard Reference

None.

Problem description

Binding events to an element property actually createsInline event processing functions(For example,

Alert (this );"...>... </H1> ),Inline event processing functionsIt has a special scope chain, and the Implementation Details of various browsers are also different.

Impact

IfInline event processing functionsImproper variables or calling methods used in the script will cause the script to run incorrectly.

Affected browsers
All browsers
Problem Analysis 1. Scope chain of inline event processing functions

Unlike other functions,Inline event processing functionsFrom the header, the scope chain is called object, DOM object of the element, DOM object of the FORM to which the element belongs (if any), document object, and window object (Global object ).

Run the following code:

<form action="." method="get"><input type="button" value="compatMode" onclick="alert(compatMode);"></form>

Equivalent to 1:

<form action="." method="get"><input type="button" value="compatMode"></form><script>document.getElementsByTagName("input")[0].onclick=function(){with(document){with(this2.form)3{with(this2){alert(compatMode);}}}}</script>

The document. compatMode value is displayed in all browsers.

Replace 'compatmode' with 'method' in the above code, then 'get' is displayed in each browser, that is, the method attribute value of the form object where the INPUT element is located.

Note:
1. This Code simulates the behavior of Each browser only to illustrate the problem. It does not mean that all browsers are implemented in this way.
2. whether to use the this keyword or directly use this DOM object is different in different browsers. For details, refer to the content in article 2.1.
3. Whether to add FORM objects to the scope chain. The implementations of different browsers are also different. For details, see section 2.2.

2. Differences between the scope chains of inline event handlers in various browsers

Refer to the WebKit source code:

void V8LazyEventListener::prepareListenerObject(ScriptExecutionContext* context){  if (hasExistingListenerObject())    return;  v8::HandleScope handleScope;  V8Proxy* proxy = V8Proxy::retrieve(context);  if (!proxy)    return;  // Use the outer scope to hold context.  v8::Local<v8::Context> v8Context = worldContext().adjustedContext(proxy);  // Bail out if we cannot get the context.  if (v8Context.IsEmpty())    return;  v8::Context::Scope scope(v8Context);  // FIXME: cache the wrapper function.  // Nodes other than the document object, when executing inline event handlers push document, form, and the target node on the scope chain.  // We do this by using 'with' statement.  // See chrome/fast/forms/form-action.html  //   chrome/fast/forms/selected-index-value.html  //   base/fast/overflow/onscroll-layer-self-destruct.html  //  // Don't use new lines so that lines in the modified handler  // have the same numbers as in the original code.  String code = "(function (evt) {" \      "with (this.ownerDocument ? this.ownerDocument : {}) {" \      "with (this.form ? this.form : {}) {" \      "with (this) {" \      "return (function(evt){";  code.append(m_code);  // Insert '\n' otherwise //-style comments could break the handler.  code.append( "\n}).call(this, evt);}}}})");  v8::Handle<v8::String> codeExternalString = v8ExternalString(code);  v8::Handle<v8::Script> script = V8Proxy::compileScript(codeExternalString, m_sourceURL, m_lineNumber);  if (!script.IsEmpty()) {    v8::Local<v8::Value> value = proxy->runScript(script, false);    if (!value.IsEmpty()) {      ASSERT(value->IsFunction());      v8::Local<v8::Function> wrappedFunction = v8::Local<v8::Function>::Cast(value);      // Change the toString function on the wrapper function to avoid it      // returning the source for the actual wrapper function. Instead it      // returns source for a clean wrapper function with the event      // argument wrapping the event source code. The reason for this is      // that some web sites use toString on event functions and eval the      // source returned (sometimes a RegExp is applied as well) for some      // other use. That fails miserably if the actual wrapper source is      // returned.      DEFINE_STATIC_LOCAL(v8::Persistent<v8::FunctionTemplate>, toStringTemplate, ());      if (toStringTemplate.IsEmpty())        toStringTemplate = v8::Persistent<v8::FunctionTemplate>::New(v8::FunctionTemplate::New(V8LazyEventListenerToString));      v8::Local<v8::Function> toStringFunction;      if (!toStringTemplate.IsEmpty())        toStringFunction = toStringTemplate->GetFunction();      if (!toStringFunction.IsEmpty()) {        String toStringResult = "function ";        toStringResult.append(m_functionName);        toStringResult.append("(");        toStringResult.append(m_isSVGEvent ? "evt" : "event");        toStringResult.append(") {\n ");        toStringResult.append(m_code);        toStringResult.append("\n}");        wrappedFunction->SetHiddenValue(V8HiddenPropertyName::toStringString(), v8ExternalString(toStringResult));        wrappedFunction->Set(v8::String::New("toString"), toStringFunction);      }      wrappedFunction->SetName(v8::String::New(fromWebCoreString(m_functionName), m_functionName.length()));      setListenerObject(wrappedFunction);    }  }}

From the code above, we can see that when WebKit adds an object to the scope chain, it uses the 'eas' keyword and judges 'this. form 'to determine whether to add the FORM object to the scope chain.

Similar implementation is also available in other browsers, but in each browser, the target object (that is,Inline event processing functionsThe methods used to add a FORM object to the scope chain are different. The methods used to determine whether to add a FORM object to the scope chain are also different.

2.1. Different browsers use different methods to add target objects when generating this special scope chain

All browsersInline event processing functionsThe DOM object of the element to which it belongs is added to the scope chain, but the joining method is different.

Run the following code:

<input type="button" value="hello" onclick="alert(value);">

'Hello' is displayed in all browsers '.

Modify the code to changeInline event processing functionsExecution context:

<input type="button" value="hello" onclick="alert(value);"><script>var $target=document.getElementsByTagName("input")[0];var o={onclick:$target.onclick,value:"Hi, I'm here!"};o.onclick();</script>

The running results in various browsers are as follows:

IE Chrome Hi, I'm here!
Firefox Safari Opera Hello

As you can seeInline event processing functionsThe DOM object of the element to which it belongs is added to the scope chain in different ways.

In IE Chrome, add the following code:

<input type="button" value="hello"><script>var $target=document.getElementsByTagName("input")[0];$target.onclick=function(){with(document){with(this){alert(value);}}}</script>

In Firefox Safari Opera, you can add the following code:

<input type="button" value="hello"><script>var $target=document.getElementsByTagName("input")[0];$target.onclick=function(){with(document){with($target){alert(value);}}}</script>

Because few changes need to be madeInline event processing functionsThe execution context.

2.2. Different browsers have different understandings about the situation in which FORM objects are added when this special scope chain is generated.

All browsersInline event processing functionsAffiliatedThe FORM object is added to the scope chain, but how to determine whether the element "belongs" to a FORM object is different in different browsers.

Run the following code:

<form action="." method="get"><div><span onclick="alert(method);">click</span></div></form><script>document.method="document.method";</script>

In each browser, click the SPAN element and the pop-up information is as follows:

IE Safari Opera Get
Chrome Firefox Document. method

Visible:

  • IE Safari Opera adds the FORM objectInline event processing functionsIn the scope chain, whether to add a FORM object seems to be determined by whether this element is a child-level element of a FORM. Therefore, in these browsers, the variable 'method' in the function finally gets the 'method' value of FORM.
  • Chrome Firefox does not add FORM objectsInline event processing functionsTo check whether the 'form' attribute of the target object bound to the function exists. From the WebKit source code above, we can see that Chrome uses 'this. form, the 'form' attribute exists only when the target element is a child-level element of a FORM and the target element is a form element. In this example, the SPAN element is not a form element. Therefore, the variable 'method' gets the value of 'document. method.

If you replace the SPAN element in the above Code with the INPUT element or other form elements, the performance in all browsers will be consistent.

3. instance 3.1 is faulty due to this special scope chain of inline event processing functions. the problem that occurs when the variables accessed in the element's inline event handler function accidentally duplicate the attributes of other non-Global Objects in the function scope chain.

When a variable accessed by an inline event processing function accidentally has a duplicate attribute of another non-Global Object (window) object in the function scope chain, the actual value of the variable is not an expected value.

Assume the following code is available:

<button onclick="onsearch()"> click here </button><script>function onsearch(){alert("Click!");}</script>

The author simply clicks the button to bring up "Click !" But the HTMLElement object of the WebKit engine browser has an event listener named onsearch, which causes the above Code to fail to be executed as expected in Chrome Safari. In this example, the "Uncaught TypeError: object is not a function" error is reported because the listener is undefined (null.

Appendix: In the above Code, append the following code to confirm the location of 'onsearch:

<Script> var o = document. getElementsByTagName ("button") [0]; if ("onsearch" in o) alert ("the current object has the onsearch attribute. "); If (o. hasOwnProperty (" onsearch ") alert (" onsearch property is private to the current object. "); </Script>
3.2. Problems with the attempt to call the form attributes or methods in the inline event handler function of Child-level non-form elements in the form

Assume the following code is available:

<form action="xxx" method="get">...<a href="#" onclick="submit();">click</a></form>

The author calls the 'submit 'method of FORM after clicking Element A, but Chrome Firefox does not add the FORM object to thisInline event processing functionsSo the above Code cannot run normally in Chrome Firefox.

Solution

1. Try not to useInline event processing functions, Use the DOM standard event registration method to register Event Handlers for this element, such:

<button> click here </button><script>function onsearch(){alert("Click!");}function bind($target,eventName,onEvent){$target.addEventListener?$target.addEventListener(eventName,onEvent,false):$target.attachEvent("on"+eventName,onEvent);}bind(document.getElementsByTagName("button")[0],"click",onsearch);</script>

2. when you must use an inline event processing function, make sure that the variables that the function tries to access are in the global scope, instead of referencing unexpected objects because of the unique scope chain of the function. The simplest method is to use a prefix, such as 'my _ onsearch '.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.