JS关闭怪异

JS closure weirdness

本文关键字:JS      更新时间:2023-09-26

我正在尝试从函数设置对象的属性:

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.foothis.foor.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((。

相关文章:
  • 没有找到相关文章