JS关闭怪异
JS closure weirdness
我正在尝试从函数设置对象的属性:
function createObject(){
var self={};
self.foo=function(){
this.wheatly="apple";
}
return self;
}
问题是,当我调用self.foo((时,"this"指的是函数对象(self.foo(,而不是父对象(self(如何强制函数设置父对象的属性?在stackoverflow上有很多类似的问题,但作者一直在使用这个"闭包"的东西,它应该适用于这里???
编辑:
我忘了提到函数是异步调用的,所以这里有一个更好的例子:http://jsfiddle.net/Pj59q/让我困惑的是控制台(chrome中(说this
是一个XMLHttpRequest(可能是self.ajax
中声明的那个(。this
关键字是否只是指调用该函数的任何对象?
x = createObject()
>> Object {foo: function}
x.foo()
x
>> Object {foo: function, wheatly: "apple"}
那么,问题出在哪里呢?这是预期的行为。顺便说一句,这与闭包无关。
更新
所以事实证明你没有提供所有必要的信息。您需要将要传递的回调绑定到ajax调用,这样它就知道this
应该是什么:
r.onload=this.foo.bind(this);
顺便说一下,您构建createObject
的方式有点奇怪。更惯用的是:
function createObject(){
return {
foo: function() {
this.wheatly="apple";
}
};
}
this
不是指self.foo
,而是指self
。你是如何得出它指self.foo
的结论的?您可以在控制台中验证是否发生以下情况:
var bar = createObject();
bar.wheatly; //=> undefined
bar.foo();
bar.wheatly; //=> 'apple'
因此,self
(此处标识为bar
(被正确引用和修改。
顺便说一下;闭包";是一个概念的名称,当一个函数在一个范围内有变量的环境中创建时,该函数吸收("关闭"(这些变量,并继续能够引用它们,即使它们超出了范围。例如:
var outerFunc = function() {
var closeMe = 'hello';
return function() {
return closeMe;
};
};
innerFunc = outerFunc();
innerFunc(); //=> 'hello'
变量closeMe
被正确读取并返回,即使它超出了作用域。这是因为innerFunc
在定义时关闭了它。
我不认为你的问题(请你为我澄清(与关闭有关。
编辑:
为了确保每个人都清楚TGH的解决方案为什么有效,请观察下面的代码:
self.foo=function(){
this.wheatly="apple";
console.log(this);
}
self.ajax=function(){
var r = new XMLHttpRequest();
r.open("GET","example.com",true);
r.onload=this.foo;
r.send();
}
在该代码中,有参考self.foo
、this.foo
和r.onload
。这些引用可能有不同的名称,但它们实际上是对相同函数的引用。但是,当AJAX调用完成时,它将此函数调用为r.onload
,即r
的成员。因此,this
以经典的面向对象方式指向r
。
在TGH的解决方案中,不使用不断移动的引用this
,而是由始终引用父对象而从不引用r
的明确引用self
代替。
function createObject(){
var self={};
self.foo=function(){
self.wheatly="apple";
}
return self;
}
以上内容如何?
原因是当XMLHTTPRequest回调onload函数时,它会切换上下文(this(。
换句话说,XMLHTTPRequest对象实现为:
function send() {
if (status == 200) {
this.onload(); //// Now the context is XMLHTTPRequest Object!!!!
}
}
您可以将代码更改为
self.ajax=function(){
var r = new XMLHttpRequest();
r.open("GET","/",true);
var that = this;
r.onload=function() {
that.foo.apply(that);
}
r.send();
}
绑定上下文,并使用该上下文调用foo((。
- 没有找到相关文章