关于javascript克隆的简单问题

时间:2011-07-08 10:56:38

标签: javascript clone deep-copy

我有一个点

function Point(x, y) {
    this.x = x;
    this.y = y;
};

如你所见,它是可变的。所以我可以改变它的属性,比如

 var p = new Point(2, 3);
 p.x = 6;

我想添加克隆方法,以便预期的行为是

 var p1 = new Point(2, 3);
 var p2 = p1.clone();
 p1.x = 6;

 assert p1 != p2;     //first assertion. pseudocode.
 assert p2.x == 2;    //second assertion. pseudocode.

为了实现clone()我以下一种方式重写Point

function Point(x, y) {
    this.x = x;
    this.y = y;
    this.clone = function () {
        function TrickyConstructor() {
        }
        TrickyConstructor.prototype = this;
        return new TrickyConstructor();
    };
};

但是我的实施失败了第二个断言。我应该如何重新实现呢?

2 个答案:

答案 0 :(得分:4)

如果属性仅为xy,我会这样做:

function Point(x, y) {
    this.x = x;
    this.y = y;
};

Point.prototype.clone = function() {
    return new Point(this.x, this.y);
}

请注意,我将clone方法附加到Point.prototype。这对下一个工作方法很重要:

如果没有,则必须创建一个新实例,并将所有属性复制到新实例:

Point.prototype.clone = function() {
    var clone = new Point(this.x, this.y);
    for(var prop in this) {
        if(this.hasOwnProperty(prop)) {
            clone[prop] = this[prop];
        }
    }
    return clone;
}

但这将是深层复制属性。这仅适用于原始值。

如果您真的想要深层复制属性,这可能会变得更加复杂。幸运的是,之前已经问过这个问题:How to Deep clone in javascript


解释克隆方法不起作用的原因:

p2的原型链将如下所示:

 +-----------+      +-----------+
 |Instance p2|      |Instance p1|
 |           |----->|x=2        |
 |           |      |y=3        |
 +-----------+      +-----------+

所以如果你设置p1.x = 6,它将是:

 +-----------+      +-----------+
 |Instance p2|      |Instance p1|
 |           |----->|x=6        |
 |           |      |y=3        |
 +-----------+      +-----------+

只要p2没有拥有 xy属性,它们就会始终引用恰好是{{{}的原型。 1}}。

答案 1 :(得分:1)

function Point(x, y) {
    this.x = x;
    this.y = y;
    this.clone = function () {
        var newPoint = {};
        for (var key in this) {
            newPoint[key] = this[key];
        }
        return newPoint;
    };
};

示例:http://jsfiddle.net/HPtmk/