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ならMarshal
のload
とdump
を使って)、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
var a = [0,1,2,3];
var a2 = JSON.parse(JSON.stringify(a));
a2[4] = 4;
alert(a);
alert(a2);