【问题标题】:Object Oriented JavaScript: the patterns for private/public面向对象的 JavaScript:私有/公共的模式
【发布时间】:2014-02-21 07:43:25
【问题描述】:

全部-

伟大的 Douglas Crockford 在此处描述了一种在 Javascript 中实现信息隐藏的经典模式:

http://javascript.crockford.com/private.html

我还知道我在这里演示的另一个: http://jsfiddle.net/TvsW6/4/

总结如下:

function LogSystem(anotherPrivateVar) {
//. . 

  var _setting1;
  this.setting2;

  function _printLog(msg) {
    $("#" + _divId).append(msg + "<br/>");
  };

  return {
    printLog :function(msg) {
      console.log("PRINTING:" + msg);
      _printLog(msg);
    },
    logSetting_pub: function() {
       this.printLog("PUB: Setting1 is: " + _setting1);
       this.printLog("PUB: Setting2 is: " + this.setting2);
    }
//..
  };
};

问题

除了这两种模式之外,还有其他模式可以在 JavaScript 中实现公共和私有方法和成员吗?这两种模式有名称吗?而你对这两个(或更多!)有偏好吗?

非常感谢您的帮助。我发现了解原始 JavaScript 中的高级主题是罕见的技能,我想拥有它们!

【问题讨论】:

  • 我不喜欢你的第二种方法,因为返回的对象本身没有类型(它不是 LogSystem 的实例)并且没有 LogSystem() 构造函数这两个函数在某些情况下都很有用。
  • 我很欣赏这个论点。我希望有权衡,但这些肯定是缺点。谢谢!
  • 嘿,你的 cmets 真的让我想到了。请你看看这里好吗? stackoverflow.com/questions/21944115/…
  • 好的,我读过那篇文章。你想问什么?
  • 好吧,如果您对那里的问题有任何启发,那就太好了。对我来说最大的谜团是如何使用“公共”成员而不是公共方法。它就像函数必须在返回对象中,但简单的公共变量却没有。

标签: javascript object-oriented-analysis


【解决方案1】:

Crockford 的方法可能是我遇到最多的一种。坦率地说,这让我很伤心,因为它很混乱,语义上很糟糕——你的构造函数代码与你的类定​​义混杂在一起! --,如果我记得我之前的测试,效率低下。

我想我从来没有见过你在野外描述的第二种风格。出于与第一个类似的原因,它也不会让我很舒服。更不用说从构造函数返回是一个相当晦涩的行为,这可能会让很多人感到困惑。

我喜欢的风格是一种“契约”私人,或者更准确地说,有利于“受保护”成员。我自己的一个相当好的例子can be found here

代码的相关子集是:

var gk = (function(gk){

//static/constant members would be vars here, if I had them.

function List(collection){
    this._dummy = {};
    this._dummy.next = this._dummy;
    this._dummy.prev = this._dummy;
    this.length = 0;

    if(collection){
        this.addAll(collection);
    }
}

List.prototype = new gk.Collection();

//stuff...

List.prototype.pushBack = function(item){
    var curNode = this._dummy;
    var newNode = {};
    newNode.item = item;
    this._add(curNode, newNode);
}

List.prototype.add = List.prototype.pushBack;

List.prototype._add = function(curNode, newNode){
    newNode.prev = curNode.prev;
    curNode.prev.next = newNode;
    newNode.next = curNode;
    curNode.prev = newNode;
    ++this.length;
    this._registerAddition(curNode.item); //inherited from the superclass!
}

//stuff...

gk.List = List;

return gk;
})(gk || {}); 

所有公共和“私有”成员都附加到this 或原型,但任何旨在“特定于实现”的内容都带有下划线前缀。这表明它不是一个公开保证的 API,并且引用它会立即将您与实现紧密结合。如果您打算拥有一个可公开访问的对象,该对象可以将其内部暴露给需要它们的事物(例如我的 LinkedList,它由可能需要更多控制的其他数据结构在内部使用,但仍然是一个完全有效的数据结构自己)。

作为一个额外的好处,生成的代码(在我看来)是干净的、可维护的、语义化的,并且无论其“安全性”如何,都可以统一访问成员。重构公共/私有状态的东西也容易得多,因为您只需添加/删除下划线。您还可以获得原型链的全部好处(抽象的受保护成员供超类使用!)。因此,如果您关心这类事情,每个实例的开销似乎有点少(手头没有测试,抱歉)。

我早就放弃了尝试将 JS 制作成 Java/C++/C# 的完美克隆。这是一种不同的语言。在我看来,您最好让自己的开发更轻松,并编写干净、可读、可维护和可用的代码,而不是基于闭包的荣耀创建模仿其他语言的令人沮丧的怪物。是的,你可以用闭包做任何事情,但亲爱的上帝,这并不意味着你应该这样做。

【讨论】:

    【解决方案2】:

    我最喜欢的模式是 Mozilla 网站上的described

    Object.defineProperty(obj, "value", {
      enumerable: true,
      configurable: false,
      writable: true,
      value: 5
    });
    

    您也可以为此类属性添加 getter 和 setter。

    【讨论】:

    • 这如何创建一个只能由方法访问的私有变量?
    • 这是关于创建一个类的成员。你读过提供的网址吗?
    • 是的,我已经阅读了那篇文章并在实际项目中使用了它的技术。那篇文章的独特而相关的部分(对于 OP 的问题)是创建私有变量,这些变量只能通过您的答案没有执行的方法访问。
    • 哇。虽然你可能没有准确回答我的问题,但这绝对是相关的!!!如果您有任何示例说明何时这是赋予属性不同属性以使其成为公共、私有或您拥有的属性的一种优势方式,请告诉我们。我很惊讶我不知道这个!
    • @RClaven - 你不能用Object.defineProperty() 将事情公开/私有。对象的属性对所有人都是可见的。私有数据通常不是通过向对象本身添加属性来实现的,而是通过将变量隐藏在一个闭包中,该闭包仅在代码驻留在构造函数中的方法的范围内。您可以使用Object.defineProperty() 将属性设置为只读,但随后它们对所有人都是只读的。
    【解决方案3】:

    anotherPrivateVar 不是私人成员。它是函数的参数。在这种情况下,您的构造函数的参数。 _setting1 不能以其他方式声明。

    我不认为您的最后两个公共函数printLoglogSetting_pub 是定义公共函数的最佳方式。改用原型设计:

    LogSystem.prototype.printLog = function(msg) {...}
    

    编辑:您也可能对coffeescript 感兴趣。它有更好的方法来开发面向对象的类、构造函数等。但主要是另一种语法的 javascript。

    【讨论】:

    • anotherPrivateVar 是一个私有变量。它恰好是一个参数,但它是私有的,并且是一个可以像其他变量一样读取或设置的变量。它对printLog() 方法可用,但对外部世界不可用(因此它是私有的)。此外,以这种方式定义方法而不是使用原型的全部目的正是为了让您可以拥有私有变量。我认为您错过了这项技术的全部要点。
    • 确保在 javascript 中它在 printLog() 中可用,因为 printLog() 是在函数本身中定义的。但这只是一种 Javascript 行为,而不是面向对象的模式。除此之外,私有变量不是私有成员。我在变量名 (anotherPrivateVar) 中读多了,抱歉。
    猜你喜欢
    • 1970-01-01
    • 2014-10-07
    • 2017-10-11
    • 2010-11-04
    • 1970-01-01
    • 2021-01-19
    • 2011-12-03
    • 1970-01-01
    • 2012-05-14
    相关资源
    最近更新 更多