2
    Board = function()
    {
        var  cells = [8];


        /**
         * Initializing every cell using numeric format.
         * */
        for (var i=0 ; i<8; i++){
            cells[i] = [8];
            for (var j=0 ; j<8; j++)
                cells[i][j] = new Cell(new Position(i,j));
        }

                ....
}

別のコード GameManager.js で、

var duplicateBoard = Copy.deepCopy(board);
board.moveCell(1,2)

そして、私が使用しているディープコピーには、

参照: http://jsperf.com/deep-copy-vs-json-stringify-json-parse

 function deepCopy(o) {
        var copy = o,k;

        if (o && typeof o === 'object') {
            copy = Object.prototype.toString.call(o) === '[object Array]' ? [] : {};
            for (k in o) {
                copy[k] = deepCopy(o[k]);
            }
        }

        return copy;
    }

私の必要性:(
コンストラクcellsターのプライベートメンバー)をBoardディープコピーしたい。

問題 :
しかし、firebug でデバッグしたところ、関数がコンストラクターのプライベート オブジェクトをdeepCopyディープ コピーしていないことがわかりました。

私の場合:
board.moveCell(1,2)、ここで cell[1][2] も移動されduplicateBoardます。
つまりcell、ボードと複製ボードの両方がセル[1][2]への同じ参照を持っています。

私が追跡したものは何ですか? ディープ コピー関数は、 を関数として扱いconstructorます。したがって、関数のディープ コピーは無視されtypeof o === 'objectます。しかし、この条件を削除することは有用ではありません。そうすることで、duplicateBoardすべての関数が型になるのではなく、関数がなくなるからobject{}です。

4

3 に答える 3

2

「プライベート」変数は関数(コンストラクター)に対してローカルであるため、これは実行できません。JS の動作方法では、関数を複製しても、元のオブジェクト ( http://jsfiddle.net/kBzQP/ )からポインターを取得できます。

function deepCopy(o) {
    if(o == null || typeof(o) != 'object') {
        return o;
    }

    var newObj = new o.constructor();

    for(var key in o) {
        newObj[key] = deepCopy(o[key]);
    }

    return newObj;  
}

関数をクローンしないと、すべてのパブリック変数がクローンされた新しいプライベート変数のセットが得られます ( http://jsfiddle.net/kBzQP/3/ )。

function deepCopy(o) {

    if(o == null || typeof(o) != 'object') {
        return o;
    }

    var newObj = new o.constructor();

    for(var key in o) {
        if(typeof(o) != 'function') continue;
        newObj[key] = deepCopy(o[key]);
    }

    return newObj;  
}

これを処理する最善の方法は、プライベート変数をパブリックにアクセスできるようにし、"_myPrivateVariable" などの別の命名規則を与えることです。このようにして、変数が複製され、クラスを使用する他の人は、これがプライベート変数であることを知ることができます。

したがって、あなたの場合は次のようになります。

Board = function()
    {
        this._cells = [8];


        /**
         * Initializing every cell using numeric format.
         * */
        for (var i=0 ; i<8; i++){
            this._cells[i] = [8];
            for (var j=0 ; j<8; j++)
                this._cells[i][j] = new Cell(new Position(i,j));
        }

                ....
}

参考のためにここをチェックしてください:プライベートメンバーでjavascriptオブジェクトをコピーする

于 2013-05-26T14:54:48.893 に答える
1

「プライベート」セル変数にアクセスするすべての関数は、Board.prototype の代わりに this.someFunction として宣言する必要があるため、各 Board インスタンスはそれらを共有する代わりに独自の関数を持つため、これは良い解決策ではありません。

プロトタイプを壊すサンプルコードを次に示します (c instanceof b は true ではありません) が、関数内のクロージャー変数にアクセスする必要があるためプロトタイプを使用できないため、これは重要ではありません。

function Test(privates) { 
    var msg = [];
    if(privates!==undefined){
      msg=deepCopy(privates.msg,[]);
    }
    this.Message = function(newMsg) {
        if (newMsg) {
            msg.push(newMsg);
        } else {
            return msg;
        }
    }
    this.clone=function(){
      var orgMsg=msg
      var ret = function(){
        Test.call(this,{msg:orgMsg});
      }
      return deepCopy(this,new ret());
    }
}
// this does not set prototype correctly
function deepCopy(from,to) {
    if(from == null || typeof(from) != 'object') {
        return from;
    }
    for(var key in from) {
      // this.Message has closure ref to msg
      // you can't copy it because we've set a new
      // closure ref
      if(typeof from[key]!=="function"){
        to[key] = deepCopy(from[key]);
      }
    }
    return to;  
}

var b = new Test();
b.Message("Before cloning");
console.log("b message before cloning:",b.Message());
var c = b.clone();
console.log("c message after cloning:",c.Message());
b.Message("From BB after Clone");
console.log("c message after pushing new item in b:",c.Message());
c.Message("From CC after Clone");
console.log("b message after pushing new item in c:",b.Message());
console.log("c message after pushing new item in b:",c.Message());

[アップデート]

これが悪い設計である理由は、オブジェクト メソッドをプロトタイプとして宣言できないためです。

Test.prototype.Message(){
 //here the msg variable doesn't exist
}

これにより、「this.someFunction」構文を使用してテスト本体ですべてのメソッドを宣言することが強制されます。複数の Test インスタンスを作成すると、各インスタンスにはまったく同じことを行う独自のメソッド セットがあります。リソースを節約するには、プロトタイプを使用する必要がありますが、これらの関数でクロージャー変数にアクセスできないため、アクセスできません。プロトタイプの基本については、こちらをお読みください:プロトタイプの継承 - 書き上げ

インスタンスが数個しかない場合は問題にならないかもしれませんが、技術的にはこれらのオブジェクトを複製することはできません。上記のコードの b の実際のクローンは typeof Test になりますが、上記のコードでは、「c」と呼ばれる「b」のクローンインスタンスは typeof Test ではなく、新しく設定されたクロージャー変数を壊さずに設定を確認する方法はありません。 「メッセージ」。

于 2013-05-26T14:54:59.423 に答える
0

使用$.extend():

var testObj = function() {
    var rand = Math.random(0, 1);
    this.r = function() { 
        return rand; 
    };
    this.changeRand = function() {
        rand = Math.random(0, 1);
    };
};
var obj1 = new testObj();
alert(obj1.r());
obj1.changeRand();
alert(obj1.r());
var obj2 = $.extend(true, {}, obj1);
alert(obj2.r());
alert(obj1.r() === obj2.r()); // true

JSFiddle

同様に、ボードに使用する必要があります。

var Board = function() {
        var cells = [8];
        /**
         * Initializing every cell using numeric format.
         * */
        for (var i=0 ; i<8; i++){
            cells[i] = [8];
            for (var j=0 ; j<8; j++)
                cells[i][j] = new Cell(new Position(i,j));
        }
}
var board = new Board(),
    copy = $.extend(true, {}, board);

通常、私はjQueryの使用を避けようとしますが、この場合は完璧に思えます...

于 2013-05-26T14:56:54.823 に答える