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)

对于我正在使用的 Deepcopying,

参考: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发生深拷贝 board 和 duplicateBoard 对 cell[1][2] 的引用相同。

我追踪了什么? deep-copy 函数将 视为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));
        }

                ....
}

为了参考,请在此处查看:Copy javascript object with private member

于 2013-05-26T14:54:48.893 回答
1

这不是一个好的解决方案,因为所有访问“私有”单元格变量的函数都必须声明为 this.someFunction 而不是 Board.prototype,因此每个 Board 实例都将拥有自己的函数而不是共享它们。

这是一些会破坏原型的示例代码(c instanceof b 不正确),但是由于您需要访问函数中无关紧要的闭包变量,因此您不能使用原型。

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 但在上面的代码中,克隆的“b”实例称为“c”不是 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 回答