JS封闭怪异

时间:2014-05-26 02:36:47

标签: javascript inheritance

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

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关键字是指引用称为函数的任何对象吗?

4 个答案:

答案 0 :(得分:1)

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";
        }
    };
}

答案 1 :(得分:1)

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's solution有效,请观察小提琴中的代码:

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's solution中,不使用不断变换的引用this,而是由明确引用self替换,该引用始终引用父对象而永远不引用{{1} }}

答案 2 :(得分:0)

function createObject(){
    var self={};
    self.foo=function(){
        self.wheatly="apple";
    }
    return self;
}

上面怎么样?

答案 3 :(得分:0)

原因是当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()。