Could someone point out why do开发者_JS百科es the following code fail in the first case:
CASE 1
// In a constructor
this.gallery = new Gallery();
addChild(this.gallery);
this.gallery.addEventListener(GalleryEvent.WHATEVER, function(event:*) {
// When this callback fires, there is a fail:
// because there is no 'this.gallery'.
this.gallery.someAction();
});
CASE 2
this.gallery.addEventListener(GalleryEvent.WHATEVER, function(event:*) {
// This works fine
gallery.someAction();
})
Are there any rules regarding this
usage in such cases?
This is because of the "scope chain". In ActionScript 3 (which is ECMAScript compliant -- JavaScript has the same behavior described below), there is a built-in list of "places" that is used to resolve any named variable, called the scope chain. E.g. when in a "normal" method of a class, the scope chain looks like this:
- The current instance object (the same as
this
) - The class object (used for accessing static variables)
- The global scope (used for accessing globals, e.g.
Math
)
But when you are in an anonymous inner function, the scope chain has one more entry at the top, representing the method that was in scope at the point in the time when the anonymous function was created. So for example, suppose you have this code:
class C {
var membervar:int;
function f() {
var localvar:int;
var innerfunc:Function = function() {
// what is on the scopechain here?
};
innerfunc();
}
}
In this case, when you are the the line that says "what is on the scopechain here", the scopechain looks like this (with the first scope below being the first place that will be checked):
- One instance of the function
f()
, with variableslocalvar
andinnerfunc
- The current instance of class
C
- The class
C
- The global scope
It's important to realize that that when the line of code var innerfunc:Function = function()...
executes, it is creating the Function object on the fly, and setting its scope chain on the fly. So for example, suppose you had this (confusing) code, which, given an argument an_arg
, returns a Function which, when invoked, will print the value of an_arg:
function f(an_arg:int):Function {
return function():void {
trace(an_arg);
}
}
Each function returned by calls to f()
has its own scope chain, pointing to different instances of f()
. So:
var func1:Function = f(3);
var func2:Function = f(4);
func1(); // prints 3
func2(); // prints 4
The common way to avoid this problem, if you really want to refer to this
in the inner function rather than relying on the magic of the scope chain, is to create a temporary variable called self
in the outer function -- in the case of your sample code, it would look like this:
var self = this;
this.gallery.addEventListener(GalleryEvent.WHATEVER, function(event:*) {
// This works fine
self.gallery.someAction();
})
I could go on forever on this subject -- I find it fascinating :-)
because you're passing this function function(event:*)
which means it is executed in that scope.
so when it tries to look for this
it is looking for event.gallery.someAction();
when you use gallery
, it tries to find it within the list of global variables.
One way to verify this is to add a trace(this) and see what happens.
精彩评论