【问题标题】:best approach to member variables in object-oriented javascript?面向对象的javascript中成员变量的最佳方法?
【发布时间】:2009-01-12 17:32:39
【问题描述】:

这是我刚刚发布的问题的后续。 我想知道你们在使用 MyClass.prototype 定义方法时如何处理 javascript 类中的成员变量。

如果在构造函数中定义了所有方法:

function MyClass(){
 this.myMethod = function(){}
}

您可以很好地声明成员变量并从您的方法中访问它们:

function MyClass(){
 var myVar = "hello";
 this.myMethod = function(){
  alert(myVar);
 }
}

当使用 Object.prototype 技术时,你失去了这种精细,不得不这样做;

function MyClass(){}
MyClass.prototype.myVar = "hello";
MyClass.prototype.myMethod = function(){alert(this.hello)};

我对每次访问成员变量时都必须写“this”并不感到疯狂。出于内存和灵活性的原因,我想使用 Object.prototype 方法,但它在语法方面似乎更笨拙。你们一般都是这样工作的吗?

谢谢,

-摩根

【问题讨论】:

标签: javascript


【解决方案1】:

您应该克服对使用this 指针访问成员变量的反感。

在构造函数中赋值成员变量,可以通过原型方法访问:

function Cat(){
    this.legs = 4;
    this.temperament = 'Apathetic';
    this.sound = 'Meow';
}

Cat.prototype.speak = function(){alert(this.sound)}

var cat = new Cat();
cat.speak();

是的,这些对象属性是公开的,但正如 Guido 所说,我们在这里都是成年人。毕竟,Javascript 是一种纯文本、松散类型的解释语言。在这种环境中,“私有”变量的好处充其量是不稳定的。

我说的是应该如何访问您的对象的明确和明显,违规者将自担风险偏离该目标。

【讨论】:

  • 问题当然是你不能有私有方法/变量。您能否发布一种使用原型方法允许的方式?
  • @Nelson - 原型方法永远无法访问“私有变量”(实际上是构造函数的局部变量)。在这里查看我的答案:stackoverflow.com/questions/436120/…
  • 所以如果你使用 Nelson 的技术(如果我没记错的话也是 Crockford 的),你可以拥有私人成员,但有潜在的内存问题,如果你使用 Tryiptych,你可以避免内存问题,有一些额外的细节(能够在没有的情况下扩展/修改原型),但失去了你的私人空间?
  • 没有什么能阻止您组合不同的方法。在需要的地方使用私有/特权方法,在其他地方使用原型。
  • 不应使用原型创建成员变量,因为根据定义原型不反映实例。关键字“this”非常有价值,因为它可以准确地告诉后来的读者所讨论的变量的范围是什么(与 Crockford 所说的“this”相反)
【解决方案2】:

对象属性的可见性因您声明它们的方式而异

function Cat( name ) {

    //private variable unique to each instance of Cat
    var privateName = 'Cat_'+Math.floor( Math.random() * 100 );

    //public variable unique to each instance of Cat
    this.givenName = name;

    //this method has access to private variables
    this.sayPrivateName = function() {
        alert( privateName );
    }
}

//this variable is shared by all cats
Cat.prototype.generalName = 'tiddles';

//this method is shared by all cats and has no access to private vars
Cat.prototype.sayname = function( type ) {
    alert( this[type+'Name'] || 'private!' );
}

var vic = new Cat('Victor');
var ellers = new Cat('Elmore');

vic.sayname('general');    //tiddles
vic.sayname('given');      //Victor
vic.sayname('private');    //private - no access
vic.sayPrivateName();      //cat will say its name

ellers.sayname('general');    //tiddles
ellers.sayname('given');      //Elmore
ellers.sayname('private');    //private - no access
ellers.sayPrivateName();      //cat will say its name

【讨论】:

  • 注意:如果您的构造函数返回任何内容(如对象,以公开函数或值),那么您使用 this. 声明的所有成员将不再公开可见。换句话说,在构造函数中,要么坚持使用this.,要么返回object——通常不要两者都做。
【解决方案3】:

您应该使用原型来存储方法,因为当您发现自己有 100 个方法时,它们不会在实例之间复制,而是使用相同的原型。 我使用这些方面的东西:

var myClass = function(){};
myClass.prototype = {
    method1: function(){}
    ,method2: function(){}   
};

【讨论】:

  • 感谢 sktrdie,这是我改用原型的主要原因。我想知道管理成员变量的最佳方法是什么。我是否只需要让自己多输入“这个”?
  • re: "this" :是的,这是你必须习惯的事情之一。
【解决方案4】:

在将方法分配给原型时,对“私有”变量的一个(不是那么)小评论:

确实,您不能使用构造函数对其变量创建闭包,但您当然可以用匿名函数包围原型方法,并在对象实例之间共享私有变量:

function Foo() {}

(function() {
    var sharedPrivateVar;
    Foo.prototype.methodWithAccessToSharedPrivateVar = function() {};
})();

通过一些进一步的操作,您可以实现自己的保护机制,例如只能通过以下方式读取而不是写入的变量:

function Foo() {
    this.registerInstance({ bar : 'baz' });
    this.registerInstance = undefined;
}

(function() {
    var store = {}, guid = 0;

    Foo.prototype.registerInstance = function(protectedProperties) {
        this.__guid = ++guid;
        store[this.__guid] = protectedProperties;
    };

    Foo.prototype.getProtectedProperty = function(name) {
        return store[this.__guid][name];
    };

})();

这种方法不会受到大量函数对象和闭包创建的影响,但会稍微增加查找时间。

编辑:你还应该提供一个函数

Foo.prototype.unregisterInstance = function() {
    delete store[this.__guid];
};

否则,这是引入内存泄漏的好方法......

Edit2:您还可以通过以下模式解决对registerInstance() 函数的需求:

Foo = (function() {
    var store = {}, guid = 0;

    function Foo() {
        this.__guid = ++guid;
        store[guid] = { bar : 'baz' };
    }

    Foo.prototype.getBar = function() {
        var privates = store[this.__guid];
        return privates.bar;
    };

    Foo.prototype.destroy = function() {
        delete store[this.__guid];
    };

    return Foo;
})();

【讨论】:

    猜你喜欢
    • 2011-08-20
    • 1970-01-01
    • 2015-01-04
    • 1970-01-01
    • 2021-10-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多