Variable scope in javascript callback Functions

Source: Internet
Author: User

1. Background
The callback function in Javascript is familiar to everyone. The most obvious example is the callback function provided during Ajax requests,
In fact, the event processing method (onclick, ondblclick, etc.) of DOM nodes is also a callback function.
When using DWR, the callback function can appear as the first or last parameter, for example:
JScript code function callBack (result) {} myDwrService. doSomething (param1, param2, callBack); // DWR recommended method // or myDwrService. doSomething (callBack, param1, param2 );

2. Problem Description
Recently, when I was using Dojo + Dwr, I encountered a problem:
If the callback function belongs to an object (marked as obj1), when DWR executes the callback function,
The context is not obj1.
The symptom is that any attribute accessing obj1 In the callback function is undefined.
Versions: Dojo1.3.1 and dwr2
3. Simulate the problem code
The following test code can simulate this problem:
JScript code
Copy codeThe Code is as follows:
<Html>
<Head>
<Script type = "text/javascript"> <! --
Var context = "Global ";
Var testObj = {
Context: "initial ",
Callback: function (str ){
// Callback function
Alert ("callback: in my context, context =" + this. context + ", callback method:" + str );
}
};
// Create an object as the context of the test callback function
TestObj. context = "set ";
Function testCall (){
CallMethod (testObj. callback );
CallObjMethod (testObj, testObj. callback );
}
Function callMethod (method ){
Method ("Callback by default context ");
}
Function callObjMethod (obj, method ){
Method. call (obj, "specify explicit object context callback ");
}
// --> </Script>
</Head>
<Body> <a href = "javascript: void (0)" onclick = "testCall ()"> call test </a> </body>
</Html>

In the callObjMethod method, I used two methods to call back the "method" method:
Method ("Callback by default context ");
No context is specified. We found that the value of context accessed by the callback function is the value of the global variable,
This indicates that the default context for executing this method is the global context.
Method 2: method. call (obj, "specify explicit object context callback ");
If obj is the context of method execution, the context inside the object can be accessed.

4. Research on DWR
Because I had encountered this problem when I used DOJO + DWR (1.0) in, and did not do much homework at that time, I directly changed the source code of dwr.
Now we use dwr2, so I want to see if DWR has a new way to solve this problem,
Take engine. js from dwr. jar and view the relevant callback code (_ remoteHandleCallback and _ execute ),
It seems that the callback processing method is simpler than 1.0, and the object and method cannot be passed together.
5. Conduct further research
Because DWR is widely used in projects this time, and I believe this requirement can be met, so the source code is not modified immediately,
First, I searched for Dojo + dwr on Google and did not find any conclusion. Maybe there are not many Dojo users.
So I searched "javascript callback object context" and got an article specifically about java callback functions:
Http://bitstructures.com/2007/11/javascript-method-callbacks
The most important sentence:
When a function is called as a method on an object (obj. alertVal ()),
"This" is bound to the object that it is called on (obj ).
And when a function is called without an object (func ()),
"This" is bound to the JavaScript global object (window in web browsers .)
This article also provides a solution that uses Closure and anonymous methods,
In javascript, when a function is created inside a function, a closure is automatically created,
The closure can remember the context of the corresponding function during creation.
Therefore, if:
JScript code var closureFunc = function () {testObj. callback ();}
Therefore, the direct call of closureFunc () and the call of testObj. callback () are equivalent no matter where it is.
For more information, see the above article: http://bitstructures.com/2007/11/javascript-method-callbacks.
6. Improve the simulated code
The simulated Code only adds a callback method:
JScript code
Copy codeThe Code is as follows:
<Html>
<Head>
<Script type = "text/javascript"> <! --
Var context = "Global ";
Var testObj = {
Context: "initial ",
Callback: function (str ){
// Callback function
Alert ("callback: in my context, context =" + this. context + ", callback method:" + str );
}
};
// Create an object as the context of the test callback function
Function testCall (){
CallMethod (testObj. callback );
CallWithClosure (function (param) {testObj. callback (param );});
TestObj. context = "set ";
CallObjMethod (testObj, testObj. callback );
}
Function callMethod (method) {method ("Callback by default context ");}
Function callWithClosure (method) {method ("Keep context callback through Closure ");}
Function callObjMethod (obj, method) {method. call (obj, "specify explicit object context callback ");}
// --> </Script>
</Head>
<Body> <a href = "javascript: void (0)" onclick = "testCall ()"> call test </a> </body>
</Html>

By testing the code above, we can find that Closure achieves the same effect as a specified object.
7. simulate more real call scenarios
However, the above Code still has a problem. Generally, in the real environment, if the callback function is a method in an object, the method for initiating a request is also in the same object,
In javascript, this can also represent the current object, but cannot be used directly in anonymous functions. For example:
JScript code var testObj = {context: "initial", callback: function (str) {// callback function alert ("callback: My context, context =" + this. context + ", callback method:" + str) ;}, caller: function () {callWithClosure (function (param) {this. callback (param) ;}};// create an object as the context for testing the callback function
In the above Code, this is not testObj, but the global context,
You need to write a temporary variable outside closure to represent this. The complete code is as follows:
JScript code
Copy codeThe Code is as follows:
<Html>
<Head>
<Script type = "text/javascript"> <! --
Var context = "Global ";
Var testObj = {
Context: "initial ",
Callback: function (str ){
// Callback function
Alert ("callback: in my context, context =" + this. context + ", callback method:" + str );
},
Caller: function (){
CallWithClosure (function (param) {this. callback (param );});
Var temp = this;
CallWithClosure (function (param) {temp. callback (param );});
}
};
// Create an object as the context of the test callback function
TestObj. context = "set ";
Function testCall (){
// CallMethod (testObj. callback );
TestObj. caller ();
// CallWithClosure (function (param) {testObj. callback (param );});
// CallObjMethod (testObj, testObj. callback );
}

Function callObjMethod (obj, method) {method. call (obj, "specify explicit object context callback ");}
Function callMethod (method) {method ("Callback by default context ");}
Function callWithClosure (method) {method ("Keep context callback through Closure ");}
Function callback (str) {alert ("callback: I am a global function defined on the outside. ");}
// --> </Script>
</Head>
<Body>
<A href = "javascript: void (0)" onclick = "testCall ()"> call test </a>
</Body>
</Html>

8. What is Closure?
Two one sentence summaries:
A closure is the local variables for a function-kept alive after the function has returned,
Or
A closure is a stack-frame which is not deallocated when the function returns. (as if a 'stack-framework' were malloc 'ed instead of being on the stack !)

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.