【问题标题】:JavaScript EncapsulationJavaScript 封装
【发布时间】:2010-07-27 22:23:00
【问题描述】:

所以我一直在研究完整的面向对象的 JavaScript 开发实践,并想知道以下示例。

据我了解,(这对我来说很有意义)以下“秘密”字段是“私有”:

var MyObject = function() {

    var secret = 'sshhh';

    this.getSecret() = function() {
        return secret;
    }

}

这是因为字段 secret 具有内部函数可以访问的函数范围,但外部没有任何内容......到目前为止还不错。

但我已经看到了以下内容(尤其是在 Douglas Crockford 的书中):

var MyObject = function() {

    var secret = 'sshhh';

    return {
       getSecret : function() {
            return secret;
       }
    }   

}();

想知道有什么区别,为什么更好?我知道在这种情况下,我们甚至没有返回存在私有字段的同一个对象,但看不到巨大的好处,因为您无法直接访问该字段。

【问题讨论】:

  • 我唯一能想到的就是避免删除和覆盖/覆盖场景?
  • JavaScript: The Good Parts - 好吧,我几乎无法开始阅读这本书,因为我多次翻阅几页时感到困惑......
  • 是的,请告诉我:S - 很好,但绝对是你的想法!
  • 不要使用引号 (>) 格式化代码,而是使用 4 个空格缩进(使用编辑器窗格中的 code 按钮,而不是 quote 按钮) .
  • 抱歉,以后会做的

标签: javascript


【解决方案1】:

这些例子非常不同...第一个创建一个“MyObject”function,当使用new 作为构造函数调用它时,将有一个“getSecret”function 作为属性;第二个创建一个“MyObject”Object,并将“getSecret”function 作为属性。

在这方面,这有点像静态方法和公共方法之间的区别。在第一种情况下,该方法仅在调用构造函数时存在,而不是在构造函数本身中。在第二种情况下,没有构造函数。

假设你有:

var MyObject1 = function() {
  var secret = 'sshhh';
  this.getSecret = function() {
    return secret;
  }
}

// ...

var MyObject2 = function() {
  var secret = 'sshhh';
  return {
    getSecret : function() {
      return secret;
    }
  }
}();

运行一些测试:

MyObject1.getSecret();
// TypeError: Object has no method 'getSecret'
var m1 = new MyObject1();
m1.getSecret();
// "sshhh"

MyObject2.getSecret();
// "sshhh"
var m2 = new MyObject2();
// TypeError: object is not a function

所以 MyObject1 就像一个类,而 MyObject2 就像一个静态类。

【讨论】:

  • 我不认为第一个“类”是这样的(如果你可以这样称呼它的话)。据我了解,当您调用new MyObject() 时,“this”属性从全局范围(就像在函数调用中一样)更改为您正在构建的对象。所以 this.getSecret 将附加到对象而不是全局范围(如果这完全是废话,请有人评论!)
  • 哇,抱歉,评论完全变了(我确定之前提到过全局范围)。
  • 啊,我明白了 - 为信息欢呼。我不确定我是否会认为它是一个静态类(因为每次调用 MyObject2() 你都会得到一个“不同”的对象(我不确定如何在 javascript 中进行标识,但我确定 MyObject2() == MyObject2() 就身份而言并不等同。但是就像其他人提到的那样,我认为工厂方法更像它。无论哪种方式,相同的原则都成立 - 谢谢
  • 我要补充一点,MyObject2 有点类似于创建对象的工厂方法,如果这有帮助的话。 myObj = MyObject2(); myObj.getSecret(); // -> “嘘”
  • 好的,你得到了奖品,但是如果可以的话,再问一个简单的问题?你什么时候会使用工厂方法而不是“类”方法。这只是口味问题 - 还是其中一个比另一个有优势?
【解决方案2】:

在较大的对象中,让返回的对象明确显示返回的内容有助于您查看在一个地方公开的内容,而不必担心您错过了 this.something。

【讨论】:

  • 所以你基本上是说它只是构造函数与最终构造对象的分离?为了清楚起见,而不是某种信息隐藏之类的东西。
  • 没有。我意识到我的解释并不好。我想说的是,这两种方法都隐藏了内部信息,但后者更清楚地显示了暴露的信息。在第二种情况下,该函数不是这样的构造函数,它只是为隐藏变量提供了一个范围。
【解决方案3】:

这并没有更好 - 或更糟。它用于两种不同的场景。

您给出的第一个示例可以很好地将函数用作“类”:

 stuff = new MyObject();

第二个示例适用于定义带有一些函数的内联对象/“单例”。

【讨论】:

    【解决方案4】:

    如果您想了解更多关于它的信息,有一篇文章将其称为揭示模块模式:

    http://www.klauskomenda.com/code/javascript-programming-patterns/#revealing

    【讨论】:

      【解决方案5】:

      它们在功能上是相同的,至少在调用new MyObject().getSecret(); 时是如此。唯一的区别是后者不需要用new 调用,因为它本质上是一个“工厂方法”并为你创建对象。

      【讨论】:

      • 功能一样吗? new MyObject().getSecret()MyObject.getSecret() 对我来说似乎不是一回事......
      • 也许你对“功能性”这个词感到困惑。就像在其中一样,它们都执行完全相同的功能,即创建一个新对象并返回秘密属性。语法不是“函数”的一部分。
      【解决方案6】:

      我只能说第一个例子更容易实现。考虑一下,第一个变量是一个函数,它返回一个带有MyObject() 的简单字符串。

      第二个返回一个对象,它返回带有MyObject.getSecret()的“秘密”。

      所以,如果这就是你所说的“更好”的意思,我宁愿通过调用前一个示例来从函数中获取“秘密”(这需要更少的代码来做完全相同的事情)。

      也许克罗克福德在使用第二个例子时有一个更大的想法。

      【讨论】:

        【解决方案7】:

        使用 Javascript,事情就没有那么简单了,因为正如 Douglas Crockford 所描述的:“对象是名称-值对的集合”,因此我们可以随时为任何对象动态定义任何属性。这是实现 Javascript 封装的一种思路:

        var Person = (function () {
            var SSN = "";
            function Person(name, SSN) {
                this.name = name;
                /* Preventing any changes on the SSN property */
                Object.defineProperty(this, 'SSN', {
                    value: "",
                    writable : false,
                    enumerable : true,
                    configurable : false
                });
                this.getSSN = function() {
                    return SSN;
                };
                this.setSSN = function(ssn) {
                    console.log("Check red tape here");
                    SSN = ssn;
                };
                this.setSSN(SSN);
            }
            return Person;
        })();
        

        当对象实例化时,它执行 IEF(立即执行函数)并返回内部“Person”函数,该函数持有对外部函数中变量 SSN 的特殊引用(即闭包),该变量只能被返回的对象中的公共方法访问,因此它模拟了来自 Java 类的行为。

        var p = new Person("Marcelo","444");
        var p2 = new Person("Joe","777");
        p
        Person {name: "Marcelo", SSN: "", getSSN: function, setSSN: function}
        p2
        Person {name: "Joe", SSN: "", getSSN: function, setSSN: function}
        p.setSSN("111")
        p2.setSSN("222")
        p.getSSN()
        "111"
        p2.getSSN()
        "222"
        p.SSN = "999"
        p.SSN
        ""
        

        【讨论】:

          猜你喜欢
          • 2011-02-14
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多