2007年11月26日 23:45 [Edit]

javascript - お伺い - Object.prototype.clone()

JavaScriptでオブジェクトのディープコピーをどうやってやるのか、これといったものがないようなので作ってCodeReposにおいておきました。


なぜこういうのが必要かというと、

var a = [0,1,2,3];
alert(a);   // 0,1,2,3
var a2 = a;
a2[4] = 4;  // a2を変えると...
alert(a2);  // 0,1,2,3,4 -- aも変わってしまう!

からです。参照でオブジェクトを実装しているものにはJavaScriptでなくてもこうなっていて、それでは不都合なときのため、たいていの言語ではDeep Copyを実装するクラスやモジュールが提供されていますが(例えばPerlではStorable::dclone()、RubyならMarshalloaddumpを使って)、JavaScriptにはこれといったものが見当たらないのです。

現バージョンのはこちら。

/*
 * $Id: clone.js,v 0.1 2007/11/26 14:17:22 dankogai Exp dankogai $
 */

(function(){
    // They are atomic already
    var atomic = [ Boolean, Number, String, Date, RegExp ];
    for (var i = 0, l = atomic.length; i < l; i++){
        atomic[i].prototype.clone = function(){ return this; }
    }
    // now the moment of truth!
    Object.prototype.clone = function(){
        if (this.prototype && this.prototype.clone 
            && this.prototype.clone !== Object.prototype.clone)
            return this.clone();
        var clone = new (this.constructor);
        for (var p in this) {
            clone[p] = typeof this[p] == 'object' ? this[p].clone() : this[p];
        }
        return clone;
    }
    // Array needs some special care
    Array.prototype.clone = function(){
        var clone = [];
        for (var i = 0, l = this.length; i < l; i++) {
            clone[i] = typeof this[i] == 'object' ? this[i].clone() : this[i];
        }
        return clone;
    }

})();

で、以下が実例。

Source:
stdout:
stderr:

オブジェクトの文字列化のため、KawaさんのJKL.Dumperを使わせていただいております。

見てのとおり、一つ嫌な問題があって、prototypeに割り当てているにも関わらず、for (k in object)clone自身が見えてしまうのです。これって何とかならないのかなあ....__proto__プロパティを使う方法だと新しすぎる?

Dan the JavaScripter


この記事へのトラックバックURL

この記事へのトラックバック
JavaScriptでオブジェクトをclone(ディープコピー)する方法を紹介する。 例えば、WebアプリのUIを作っていて、特定のタグ要素群を纏めてディープコピーしたいことも多々あるだろう。しかし、JavaScriptの標準APIではそれが実現出来ないようなので、今回はdankogai氏が作成…
JavaScriptでオブジェクトをクローンする方法。【俺の砂箱】at 2011年06月30日 17:30
世の中にはdeep cloneの需要がある 僕もある。某ライブラリで実装せにゃならない。スマートな方法は思いつかず。永遠ループでまわしつづけています。この前見つけたネタのエントリ。 404 Blog Not Found:javascript - お伺い - Object.prototype.clone() 最速インターフェー
[JavaScript]object=clone(object);【Thousand Years】at 2007年11月28日 22:28
404 Blog Not Found:javascript - お伺い - Object.prototype.clone()」でJKL.dumperを使ってみて、FirefoxのObject.toString()の挙動との不一致が気になったので、FireFoxでなくても使えるObject.toString()を作ってみました。 自分で言うのもなんですが、これは禿しく使え...
javascript - Object.toSource() for non-FireFox!【404 Blog Not Found】at 2007年11月27日 02:13
この記事へのコメント
prototype汚染気になる場合はこれでもいいかも。

var a = [0,1,2,3];
var a2 = JSON.parse(JSON.stringify(a));
a2[4] = 4;
alert(a);
alert(a2);
Posted by http://www.hatena.ne.jp/nacika_inscatolare/ at 2012年07月31日 22:28
a2を変更するとaも変更されるっていう例示なら、

s/alert(a2)/alert(a)/g

では? 
意味はもちろん、分かるんですが。
Posted by tmiz at 2007年11月27日 01:41
最初のコード 最終行
s/a2/a
Posted by at 2007年11月27日 01:38