Javascript:如何访问同一个类中的公共变量?

时间:2011-10-17 11:33:49

标签: javascript oop class

我最近开始编写JavaScript并认为一切都会很好...... 那么今天我遇到了一个我自己无法解决的问题。 我的教程/学习项目有一个名为model的类。在这个类中有几个私有变量和一个公共变量。此变量的类型为CustomEvent:

      function Model(){
        /**
         * Array in which the questions are stored
         */
        var questions=new Array();
        var db;
        var valuesSplit="*";
        var tableName="quests";
        this.myEvent=new CustomEvent("my event");

因此,您可以看到“myEvent”是公开的,可以从外部调用。在这种情况下,它是一个可以订阅的事件(这是在这个类之外由其他想要监听的对象完成的)并且可以被触发(这在同一个类中完成)。这是我的问题。 如何在模型类中访问myEvent?

我试过了:

    this.myEvent.fire()

    myEvent.fire()

但我总是得到“myEvent未定义”。

3 个答案:

答案 0 :(得分:6)

可能首先要说的是:JavaScript没有类。你越早停止思考“JavaScript类”,你就越好。 :-) JavaScript有OOP,但没有类的类。您的Model函数称为构造函数

您可以从任何引用myEvent创建的对象的代码中访问new Model,其中包含构造函数中的代码(通过this - 例如,您的方式设置它)和任何用this调用的函数引用该对象(当然,通过someObjReference.myEvent“外部”)。

所以this.myEvent.fire()可能就是您想要的,但您调用它的代码没有正确的this值。这是因为在JavaScript中,this完全由如何调用函数控制,而不是,其中函数被定义,就像在其他一些语言中一样。有关详细信息,请参阅我的博客文章Mythical methodsYou must remember this,但我在下面做了一些有些截断的讨论。

以下是使用所有实例共享的有用方法设置构造函数的相当标准方法的示例:

function Foo() {
    this.myEvent = new CustomEvent("my event");
}
Foo.prototype.bar = function() {
    this.myEvent.fire();
};

// Usage:
var f = new Foo();
f.bar();          // Fires the event indirectly, via the code in `bar`
f.myEvent.fire(); // Fires it directly

请注意,只有在bar调用this时才会引用具有myEvent属性的对象。通过将bar完全设置为其他内容,可以轻松调用this

document.getElementById("someID").onclick = f.bar;

点击发生时,bar函数会被调用,但this 会引用通过Model创建的对象。 (它将引用id为“someID”的元素。)所以bar中的这一行

this.myEvent.fire();

......会失败。

如果您习惯使用基于类的语言,您可以看到它与Java,C#或C ++完全不同。在这些语言中,this内的bar将始终引用通过new Model创建的对象。不是那么JavaScript,这既尴尬又强大。

这种函数的灵活性(不受任何特定对象的约束)是在JavaScript中习惯并利用的最重要的事情之一。另一个是函数闭包的功能,它功能强大但是not complicated

因此,如果this是根据函数的调用方式设置的,那么你如何做到这一点?有两种方法:

  1. 通过从与调用相同的表达式中的对象属性引用该函数来调用该函数。这是一种尴尬的说法:

    var f = new Foo();
    f.bar();    // <== The key bit
    f["bar"](); // <== Also works
    

    表达式f.bar()执行两项交互操作:它首先要检索bar引用的对象的属性f,并获取该属性的值(即功能参考)。然后它调用该函数(因为())。 JavaScript的工作方式,因为您在同一个整体表达式中执行了这两项操作,解释器会在为this调用f期间将bar设置为var f = new Foo(); var b = f.bar; b(); // <== Different! 。但请注意这一关键区别:

    bar

    现在调用this函数时,f设置为window(它将被设置为全局对象,即浏览器上的call,因为我们已将属性检索与函数调用分开。

  2. 或者,您可以使用JavaScript函数对象的内置功能,applycall函数。 applyvar f = new Foo(); f.bar(1, 2): // <== Calls `bar` with `this` === `f` and passing in // the arguments 1 and 2 var b = f.bar; b.call(f, 1, 2); // <== Does the same thing as f.bar(1, 2) var args = [1, 2]; b.apply(f, args); // <== Does the same thing as f.bar(1, 2) 完成相同的事情,它们之间的唯一区别是你如何提供函数的参数。例如:

    call

    例如,applythis允许您在调用函数时设置call应明确的内容。它们之间的唯一区别是call接受参数以将函数作为apply的进一步参数,而{{1}}接受它们作为数组。

答案 1 :(得分:1)

如果您想在myEvent的非公开功能中使用Model,则必须创建对未使用myEvent的{​​{1}}的其他引用您的模型的参考。因为另一个函数中的this不是this函数中的Model。绕过此问题的最简单方法是在Model中定义新变量:

var that = this;

然后你可以打电话给myEvent,如:

that.myEvent

答案 2 :(得分:0)

myEvent成员应该在内部和外部都可见。对象的外部范围:

function Model(){
    this.myEvent = 'some value';
    this.canAccessEvent = function(){
        return 'myEvent' in this;
    }
}

var m = new Model();
// access from outside : 
alert(m.myEvent);
// access from inside : 
alert('Model can access the even? ' + m.canAccessEvent());

但是,您的new CustomEvent函数很可能不存在或者未返回有效对象,导致myEvent变量为undefined。我建议你将一些其他值归因于myEvent属性并查看它是否已定义。如果已定义,则问题出在您的CustomEvent函数中。