创建同一类的对象:Javascript原型、私有成员、继承

Posted

技术标签:

【中文标题】创建同一类的对象:Javascript原型、私有成员、继承【英文标题】:Create an object of the same class: Javascript prototype, private members, inheritance 【发布时间】:2010-02-17 04:02:45 【问题描述】:

有些代码可能会说一千多个单词:

/**
 * Represents an amount of a resource
 * @param number amount
 * @param string type
 */
function Resource(amount, type) 

    var nAmount = amount;
    var sType = type;

    if (amount < 0) 
    
        throw new IllegalArgumentException("amount has to be positive");
    

    /**
     * @method Resource
     * @return number amount of the resource
     */
    this.getAmount = function() 
    
        return nAmount;
    ;

    /**
     * @method Resource
     * @return string resource type
     */
    this.getType = function() 
    
        return sType;
    ;


/**
 * Addition of two resources produces a new resource with the sum amount
 * the new object uses the old one as prototype
 * @param Resource resource
 * @return Resource new Resource object
 */
Resource.prototype.plus = function(resource) 

    if (!(resource instanceof Resource && this.getType() == resource.getType())) 
    
        throw new IllegalArgumentException("resources don't match.");
    

    var newRes = Object.create(this); // create a new object based on the current one
    // execute the Resource constructor on it
    Resource.call(newRes, this.getAmount() + resource.getAmount(), this.getType());
    return newRes;
;

资源对象是被认为是不可变的值对象。它们在加法操作中返回一个新对象。现在,我不只是调用“new Resource(args)”来创建要返回的新对象,而是基于旧对象创建了一个新对象。这也允许继承。

当我开始在我的所有 ValueObjects 上使用它时(以防我将来想从它们继承),我开始考虑更多。

javascript 不允许不可变对象。然而,通过直接方法覆盖或调用其构造函数,对象很容易受到攻击。我所能做的就是确定这些是坏习惯。不幸的是,ECMAScript5“冻结”还没有出现,尽管我的模式与它兼容。

现在我有这种在不可变对象上调用构造函数的“坏风格”以及代码重复,我正在考虑创建一个新函数来封装这个过程:

Object.recreate = function(proto, constructor, args) 

    var obj = Object.create(proto);
    constructor.apply(obj, args);
    return obj;
;

因此:

Resource.prototype.plus = function(resource) 

    // if ... throw ...
    return Object.recreate(this, Resource, 
            [this.getAmount() + resource.getAmount(), this.getType()]);
;

也许有人对这个函数的名称有更好的想法。 “重建”是我的第一个想法。您如何看待这种模式?是不是过于抽象了?我应该把它保存到我确定会继承的类吗?我错过了什么重要的事情吗?

编辑:我发现我忘了提及一些重要的事情,目前本文没有反映。使用 Object.create 可以轻松克隆 ValueObject。他们的私人成员是不变的。但是可变的私人成员呢?如果在克隆上调用 set(),它将在闭包中设置原始原型对象!当我的 Object.recreate 重新创建闭包时,这个问题就解决了。

那么有没有更好的私有变量继承方式呢?为什么每个人都使用糖来创建课程?我已经阅读了很多关于原型的知识,但我仍然没有掌握它的窍门。

【问题讨论】:

【参考方案1】:

多年后回到这一点,我可以说我当时编写的代码在混合概念方面存在缺陷。 JavaScript 实际上可以通过闭包来提供真正的私有变量。但是由于 ValueObjects 无论如何都是不可变的,因此无法更改私有状态,并且隐藏它会使事情变得过于复杂。

另外,巧妙的 Object.recreate 是一种过度抽象的“工厂方法”,如果需要,应该为每个类单独声明。

使用组合而不是继承! Crockford 提供了很棒的 JavaScript 见解:https://crockford.com/javascript/prototypal.html

【讨论】:

【参考方案2】:

我认为复制或克隆会是一个更好的名称。 article 解释了创建此类通用函数的机制。

【讨论】:

不错的文章,但我无法从中获得多少新意。 owl.clone 正是 Object.create 在这里,我认为这个名字更合适。对于具有与“克隆/创建”冲突但与我的重新创建冲突的非 ValueObjects 的情况,我将编辑我的问题。

以上是关于创建同一类的对象:Javascript原型、私有成员、继承的主要内容,如果未能解决你的问题,请参考以下文章

javascript类继承系列二(原型链)

如何创建一个可以操作同一类的多个对象的函数,访问 C++ 中的私有属性?

javascript类和原型学习笔记

JavaScript类和模块

昼猫笔记 JavaScript -- 面向对象(II)- 继承

设计模式之原型模式