1

我定义了以下 BaseClass:

function BaseClass (arg1,arg2,arg3) {
    //constructor code here then - 
    var privateVar = 7500;
    this.getPrivateVar = function() { return privateVar; };
}

我想要以下子类,它允许像这样更改 privateVar:

function SubClass (arg1,arg2,arg3,privateVar) {
    //constructor code here then - 
    var privateVar = privateVar;
}
SubClass.prototype = new BaseClass();

现在我希望 SubClass 继承该getPrivateVar方法。但是,当我尝试这个时,它总是返回7500BaseClass 中的值而不是privateVar.

换句话说,是否可以继承 BaseClass 的公共方法,但其中的任何引用都引用了 SubClass 的属性?我该怎么做?


从事物的声音来看,这是不可能的。这个想法是为我的学生代码(我辅导孩子)自动化代码检查器,但我只需要找到另一种方法。不管怎么说,还是要谢谢你。

4

6 回答 6

3

您将 Javascript 对象模型与不互操作的范围变量混合*。

SubClass.prototype = new BaseClass();仅当您自然地使用原型和构造函数时,继承的习语才有效:

function BaseClass(arg1, arg2, arg3) {
    this._privateVar = 7500;
}
BaseClass.prototype.getPrivateVar = function() {
    return this._privateVar;
};

function SubClass(arg1, arg2, arg3, privateVar) {

}
SubClass.prototype = new BaseClass();
//Better way to do it is 
//SubClass.prototype = Object.create(BaseClass.prototype);
SubClass.prototype.constructor = SubClass;

在您争论任何人都可以通过编写来访问该属性之前_,我可以反驳说任何人都可以通过使用反射来访问 Java、PHP 或 C# 中的任何私有。或者在 Ruby 中使用instance_evalor等​​等。send所以无论如何它不在你的手中。


*当您根据实现使用作用域变量时,这些都不起作用或大部分不起作用:

  • 可枚举性
  • 可写性
  • 一流的访问器
  • 密封性、冻结性和延伸状态
  • 通过 getPropertyNames 或键进行反射
  • instanceof 运算符
  • 通用方法
  • 遗产
于 2013-08-02T15:33:52.020 回答
2

拥有一个私有变量的想法是它不应该在声明的范围之外访问。但是,有几种方法可以实现您想要做的事情。例如,您可以将privateVarin的默认值BaseClass设为动态:

function BaseClass(arg1,arg2,arg3) {
    var privateVar = BaseClass.privateVar;

    this.getPrivateVar = function () {
        return privateVar;
    };
}

BaseClass.privateVar = 7500;

现在您可以SubClass按如下方式创建:

function SubClass(arg1, arg2, arg3, privateVar) {
    var args = Array.prototype.slice.call(arguments, 0, 3); // the first 3 args
    var defaultPrivateVar = BaseClass.privateVar;           // save the old value
    BaseClass.privateVar = privateVar;                      // set a new default
    BaseClass.call(this, args);                             // call super
    BaseClass.privateVar = defaultPrivateVar;               // restore old value
}

SubClass.prototype = Object.create(BaseClass.prototype);    // inherit new way

现在您需要做的只是创建一个实例:http SubClass: //jsfiddle.net/Pytkj/

于 2013-08-02T16:04:23.913 回答
2

您定义 privateVar 的方式使其成为 BaseClass“构造函数”范围内的局部变量。就像尼尔所说,你不能从任何继承的类继承或“看到”它。您可以使用 Neal 所说的闭包(但这可能是内存过度使用,具体取决于您的使用上下文),或者将变量设为实例变量:

function BaseClass (arg1,arg2,arg3) {
    //constructor code here then - 
    this.privateVar = 7500;
    this.getPrivateVar = function() { return this.privateVar; };
}

function SubClass (arg1,arg2,arg3,privateVar) {
    //constructor code here then - 
    this.privateVar = privateVar;
}

SubClass.prototype = new BaseClass();

var subClass = new SubClass(1,2,3,4000);

console.log(subClass.getPrivateVar());
于 2013-08-02T15:33:28.020 回答
0

继承 BaseClass 的公共方法,但其中的任何引用都引用了 SubClass 的属性?

不,那是不可能的。在构造函数范围内创建的方法BaseClass将始终引用该范围内的变量,您无法更改它。它是一个变量,而不是对象的属性

但是,你做错了继承。您有一个BaseClass 实例 ,您可以从该实例继承,并且所有SubClass实例都将与该实例共享它们的getPrivateVar方法。给他们一个自己的!为此,您可以在子实例上应用父构造函数,创建一个新的闭包范围和一个新方法。并且不要使用new

function SubClass (arg1,arg2,arg3) {
    BaseClass.call(this);
}
// or, if you need a reference to the variable:
function SubClass (arg1,arg2,arg3) {
    // you have to create it on your own
    var privateVar = arguments[3]; // or use a formal parameter
    // and create `getPrivateVar` yourself
    this.getPrivateVar = function() { return privateVar; };
}

SubClass.prototype = Object.create(BaseClass.prototype);
于 2013-08-02T15:46:06.547 回答
0

你不会。即使可以,该财产也不能再称为“私人”了。也许“受保护”。

缺少不同访问级别的语言只使用公共属性和某种命名约定(例如称它们为 __semiPrivateVar)。

有一些不同的解决方案,但它们并不能真正用 OO 来描述(你真正拥有的不是类和属性,而是构造函数、作用域和变量)。

于 2013-08-02T15:34:24.227 回答
0

privateVar是 的局部变量BaseClass。它不能被子类继承或更改。

您可以将父类和子类封装在同一范围内,如下所示:

(function(){
    var privateVar = 7500;

    function BaseClass (arg1,arg2,arg3) {
        //constructor code here then - 
        this.getPrivateVar = function() { return privateVar; };
    }

    function SubClass (arg1,arg2,arg3,privateVar) {
        //constructor code here then - 
    }

    SubClass.prototype = new BaseClass();

    return SubClass;
})();
于 2013-08-02T15:29:34.097 回答