【问题标题】:How to inherit private variables in javascript with Object.create如何使用 Object.create 在 javascript 中继承私有变量
【发布时间】:2015-04-30 16:12:34
【问题描述】:

我有这个:

function Book (){
  this.width = 7;
  this.height = 10;
  var pages = 100;

  this.tear_page = function(){
    return --pages;
  }
}
function TechBook () {
  var pages = 50;
  this.open_book = function(){ return "Opened in page "+(pages/2); };
  return this;
}
var bBook = Object.create(new Book(), new TechBook());


console.log(bBook);
console.log(bBook.tear_page());
console.log(bBook.open_book());

我无法让它工作。我尽可能让 TechBook 从 Book 继承对本地/私有变量的访问,但只能从 Book 函数继承。如果我添加新方法或覆盖它们,它们将无法再获取这些变量。我想知道是否有办法仍然可以从子类的方法中访问这些变量并在子类中创建新的私有变量。

如果这是不可能的,那意味着如果你想要继承,你就不能拥有私有变量,反之亦然。哦,顺便说一句,我知道 chrome 现在(感谢 ES6)可以自然地实现类: class TechBook extends Book (){} 和许多其他语言一样,但目前支持仅限于 chrome 的最新版本......不知道有没有其他方法可以解决这个问题。

【问题讨论】:

  • 您试图将经典概念应用到 JavaScript 中,但它们在这里并不适用。 JavaScript 中没有“public”或“private”之类的东西,只有 closure
  • 虽然可以使用闭包来模拟 privacy,但据我所知,没有办法拥有 protected 成员。这真的是你想要的。私有成员永远不会被继承,这在 Java/C# 或任何其他 oo 语言中都不起作用。最后一件事,ES6 类也没有受保护的成员。
  • 你的bBook = Object.create(new Book(), new TechBook()) 代码完全搞砸了。请参阅here 以正确进行继承(然后使用bBook = new TechBook(); 进行实例化)。
  • @Vandervals:但是,您已经覆盖了访问私有变量的公共方法……
  • 具有继承的语言永远不会授予您访问私有变量的权限。私有意味着......在它们所在的上下文中是私有的,并且没有人可以在该上下文之外访问它。

标签: javascript oop inheritance


【解决方案1】:

任何语言都不能继承 private,只能继承 protected 或 public。

该概念在 javascript 中不存在,但您可以在创建对象时进行模拟(属性 = 公共,范围事物 = 私有);

解决方法可以是添加一个属性,该属性执行返回对象范围的私有变量/函数的函数。

如果公开一个返回私有对象的方法,它可以被修改,因为你有返回的引用。

我喜欢这样做:

var SomeObject = function() {
    //private var one, can't access it outside of this scope
    var one = 1;

    /*private object anotherObject, can't access it directly
     but if you return it with a public function you can modify it.*/
    var anotherObject = {
        a : 'somevalue'
    };

    //public prop two, can access it outside of this scope.
    this.two = 2;

    //public method getOne, you can access it.
    this.getOne = function() {
       return one;
    };

    /* return private var anotherObject */
    this.getAnotherObject = function() {
       return anotherObject;
    };
};

var someObject = new SomeObject();
console.log(someObject.two); // print in console 2
console.log(someObject.getOne()); // print in console 1

var referencedObject = someObject.getAnotherObject();
console.log(referencedObject);
referencedObject.a = 'anotherValue';

console.log(someObject.getAnotherObject());

Fiddle

【讨论】:

  • 如果您使用 Object 来保存 one 并传递该 Object,您也可以在外部对其进行修改。跨度>
  • 这很有趣,但我的问题是关于继承以及为什么子类可以访问私有变量但只能从“父”方法访问。在我接受答案之前,您想扩展您的答案以考虑这一点吗?
【解决方案2】:

这是一个示例,说明您如何通过了解秘密

来传递数据
function Book(secret) {
    secret = secret || {};
    var env = {}; // `env` to hold data requiring `secret`
    this.width = 7;
    this.height = 10;
    env.pages = 100;
    this.getEnv = function (s) { // give access to `env` if you know the secret
        if (s === secret) return env;
    };
    this.tear_page = function () {
        return --env.pages;
    };
}

function TechBook(secret) {
    secret = secret || {};
    Book.call(this, secret); // construct from Book
    var env = this.getEnv(secret); // get references via secret

    this.open_book = function () {
        return "Opened in page " + (env.pages/2);
    };
}

TechBook.prototype = Object.create(Book.prototype); // set up inheritance

使用 Object 引用 作为 secret 将比使用原语更安全,因为您需要原始引用才能访问。

现在你有

var bBook = new TechBook();
console.log(bBook); // instance of TechBook
console.log(bBook.tear_page()); // 99
console.log(bBook.open_book()); // Opened in page 49.5

【讨论】:

    【解决方案3】:

    参考prototype inheritanceObject.create 属性参数的基本原理。

    根据你的例子实现

    function Book (){
      this.width = 7;
      this.height = 10;
      this.pages = 100;
    
      this.tear_page = function(){
        return --this.pages;
      }
      this.init = function() {
        return this
      }
    }
    
    Book.prototype = {
      open_book: function(){ return "Opened in page "+(this.pages/2) }
    }
    
    
    var bBook = Object.create(new Book(), {pages: { value: 50 } }).init();
    
    
    console.log( new Book())              // { width: 7, height: 10, pages: 100, tear_page: [Function], init: [Function] }
    console.log( bBook )                  //{}
    console.log( bBook.width )            //->7              
    console.log( bBook.height )           //-> 10             
    console.log( bBook.pages )            // -> 50             
    console.log( bBook.tear_page())       //-> 49
    console.log(bBook.open_book())       //-> Opened in page 25
    

    【讨论】:

    • 这个问题是,当你创建 bBook 时,你不是在创建一个新的类,而是一个新的实例,自动的。是否可以创建一个返回 Object.create(new Book(), {pages: {value:50} }); 的 TechBook 类?创建实例?
    • 在Book函数中添加init方法并在创建继承Object时返回实例。我更新了答案中的代码。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-20
    • 2014-11-17
    • 2012-10-31
    • 2016-07-15
    • 2017-09-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多