JavaScript oop:正确设计类

时间:2015-06-09 12:23:25

标签: javascript oop closures prototype

列出类似问题清单:

  1. How to set up JavaScript namespace and classes properly
  2. Javascript namespace declaration with function-prototype
  3. Best OOP approach to these two small JavaScript classes
  4. 我得出结论,在JS中实现实例有两种可能的方法:使用内部函数或使用原型。
    因此,我们假设我们在命名空间 BOX_LOGIC 中有一个 Box 类,其中包含一个简单的代码。我可以编写以下代码:

    BOX_LOGIC.Box = (function() {
        // private static
        var boxCount = 0;
    
        var classDefinition = function(x) {
            x = x || 0;
            var capacity = x;
            var id = ++boxCount;
    
            // public methods
            this.getCapacity = function() { return capacity; };
            this.getId = function() { return id; };
            this.add = function(weight) { 
                weight = weight || 0;
                if (capacity >= weight) {
                    capacity -= weight;
                }   
                return capacity;
            };
        };
        return classDefinition;
    })();
    

    我能够编码:

    BOX_LOGIC.Box = (function () {
        var boxCount;
    
        var Box= function (x) {
            x = x || 0;
            this.capacity = x;
            this.id = ++boxCount;
        };
    
        Box.prototype = {
            Constructor: Box,
            add: function (weight) {
                weight = weight || 0;
                if (this.capacity >= weight) {
                    this.capacity -= weight;
                }   
                return this.capacity;
            }
        };
        return Box;
    })();
    

    Mi问题是:使用 Box原型的不同之处是什么?是出于任何原因(成本,易读性,标准......)更好的方法吗? 在第二种方法中是否有任何方式来模拟static id变量? THX!

1 个答案:

答案 0 :(得分:1)

  

Mi问题是:使用Box原型的不同之处是什么?

     

是出于任何原因(成本,易读性,标准......)更好的方法吗?

原型上的函数(和其他属性)在实例之间是共享;如果你在构造函数中创建它们,每个实例都会获得所有这些函数的自己的副本。

主要的好处是你可以添加到原型,甚至已经存在的实例看到添加,因为他们动态地使用原型。特别是,这可以帮助进行面向方面的编程和各种调试和日志记录技术,因为您可以动态地将函数包装在原型上以捕获调用。当每个实例都有自己的实例时,你不能这样做(除非你有一个对每个实例的引用,这是不可能的)。

理论上,使用原型还意味着更低的内存消耗。在实践中,你必须有数百万个实例需要关注,现代引擎擅长重用函数的底层代码,即使涉及的函数对象是不同的。

因此,除非您要动态扩充原型,否则其中一个主要是一种风格问题。

  

第二种方法是否可以模拟静态id变量?

我不会把它称为静电;"它是每个实例的私有。使用原型方法(即几乎私有的信息原型函数可以访问),有多种方法可以关闭私有信息,但是真正无法实现获取私有信息的原型函数可以访问。 ES7中可能会有(不是ES6,目前正在最终确定; ES7)。我解决了其中一个近私人机制in this blog post。该帖子中的ES6信息现已过期;隐私的东西被推回到ES7,并且"私人Name"对象变为Symbol,根本不提供真正的隐私。

我应该标记你的第三个选项,你现在可以使用ES6转换器:ES6' class

// This is similar to the prototype version; `getCapacity` and
// `add` end up on `Box.prototype`
BOX_LOGIC.Box = (function () {

    class Box {
        constructor() {
            x = x || 0;
            this.capacity = x;
        }

        getCapacity() {
            return this.capacity;
        }

        add(weight) {
            weight = weight || 0;
            if (this.capacity >= weight) {
                this.capacity -= weight;
            }   
            return this.capacity;
        }
    }

    return Box;
})();

旁注:因为您正确地使用了""在你的标题中,我会在你的原型示例中标出一个非常小的东西:你正在弄乱constructor属性。默认情况下,Box.prototype有一个属性constructor,它返回Box。但是,通过使用完全不同的对象替换 Box.prototype上的对象,您可以删除它。为了与标准功能保持一致,我将对其进行修改:

Box.prototype = {
    constructor: Box,
    //...the existing stuff goes here...
};

重要吗?只有当您最终得到依赖于constructor属性的代码(以及某些库可能)时。尽管JavaScript规范定义了属性,但JavaScript本身没有任何功能。