Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/400.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 如何在深度复制时深度复制闭包对象(私有对象)_Javascript_Clone - Fatal编程技术网

Javascript 如何在深度复制时深度复制闭包对象(私有对象)

Javascript 如何在深度复制时深度复制闭包对象(私有对象),javascript,clone,Javascript,Clone,对于我正在使用的深度复制 参考: 我的需要: 我希望板上的单元格(构造函数的私人成员)被深度复制 问题: 但是,当我使用firebug进行调试时,我看到,deepCopy函数不能深度复制构造函数的私有对象。 我的案例: board.moveCell(1,2),这里单元格[1][2]也被移动到duplicateBoard 就是, 没有对单元格进行深度复制 电路板和duplicateBoard对单元[1][2]的引用相同 我追踪到了什么? 深度复制函数将构造函数视为一个函数,因此它忽略对函数的深度复

对于我正在使用的深度复制

参考:

我的需要:
我希望
板上的
单元格
(构造函数的私人成员)被深度复制

问题:
但是,当我使用firebug进行调试时,我看到,
deepCopy
函数不能深度复制构造函数的私有对象。

我的案例:
board.moveCell(1,2)
,这里单元格[1][2]也被移动到
duplicateBoard

就是, 没有对
单元格
进行深度复制 电路板和duplicateBoard对单元[1][2]的引用相同

我追踪到了什么?
深度复制函数将
构造函数
视为一个函数,因此它忽略对函数的深度复制,因为它将在
对象
的类型中失败。但是删除这个条件是没有用的,因为这样做,
duplicateBoard
没有函数,而所有函数都是
object{}
类型。

这是无法做到的,因为“private”变量是函数(构造函数)的局部变量。按照JS的工作方式,即使通过克隆函数,您仍然可以从原始对象()获得指针

如果不克隆函数,则会得到一组全新的私有变量,其中克隆了所有公共变量()

处理这个问题的最好方法是让私有变量可以公开访问,但要给它们一个不同的命名约定,比如“_myprivatevaluate”。这样,变量将被克隆,使用您的类的任何其他人都将知道这是一个私有变量

因此,在您的情况下,它将是:

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;  
}
Board=函数()
{
这个._单元格=[8];
/**
*使用数字格式初始化每个单元格。
* */

对于(var i=0;i这不是一个好的解决方案,因为访问“private”cells变量的所有函数都必须声明为this.someFunction而不是Board.prototype,因此每个Board实例都有自己的函数,而不是共享它们

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

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));
        }

                ....
}
[更新]

这是一个糟糕的设计,因为您不能将对象方法声明为原型:

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());
这迫使您在测试体中用“This.someFunction”声明所有方法语法。如果创建多个测试实例,则每个实例都有自己的一组方法来执行完全相同的操作。为了节省资源,您应该使用prototype,但是您不能在这些函数中访问closure varibales,因此您不能访问。请阅读关于prototype的基本知识:

也许如果你只有几个实例,这并不重要,但从技术上来说,你不能克隆这些对象。在上面的代码中,b的真正克隆是typeof Test,但在上面的代码中,被克隆的“b”实例称为“c”不是typeof Test,我无法在不破坏新设置的闭包变量“msg”的情况下设置它.

使用:

同样,您也应该将其用于电路板:

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
var板=函数(){
var单元格=[8];
/**
*使用数字格式初始化每个单元格。
* */

对于(var i=0;我可以使用jQuery吗?如果可以,也许你会尝试
copy=$.extend(true,{},board);
,但是Idk如果它真的有效(未测试),“private”属性的正确名称是closure,它们不会显示为对象实例属性,因为它们只能在函数体中使用。如何创建board实例,您是返回值还是使用新关键字?@LightStyle我认为jQuery无法复制closure中定义的属性。closure值不是对象实例的一部分,甚至在对象内部,您也不能将其称为。cells有趣的难题是,如果对象的私有变量不存在,外部函数如何复制该对象的私有变量如果在创建o和调用deepCopy之间更改了o中的单元格,则不会复制闭包值。更改不会反映在返回的新对象中。您是否尝试在创建“o”之间更改msg的值克隆它?让我们添加一个函数this.changeMsg(newMsg){msg=newMsg);调用它然后克隆它。添加一个函数this.sayMsg并选中“o”和克隆,我相信它们不会是一样的。@EAGER\u STUDENT啊,我知道那里发生了什么。.函数指针正在被复制。请查看我在哪里修改了函数,使其不复制新定义的函数指针。@EAGER\u STUDENT请忽略我上面的消息,这根本不起作用cases@MichaelCoxonI agr请注意不要使用private/closures,特别是在您计划创建大量实例的情况下。但是,如果您在克隆上破坏原型,您也可以复制private/closure变量,请参阅我的更新答案。但不确定这样做是否有正当理由。从技术上讲,克隆不是克隆,因为没有复制原型,只有属性以及它们的值。我认为这不会复制电路板项中的单元格闭包,如果它复制了,那么如果在创建电路板和克隆电路板之间更改了单元格,它会将更改复制到单元格中。请参阅新的FIDLE。它会更改闭包变量,并将其保存到克隆对象中。它工作得非常好。@EAGER\u STUDENT签出!克隆对象和返回的对象共享相同的消息,尝试将消息更改为数组和函数消息以推送消息中传递的变量,然后克隆它并调用其中一个对象上的消息以推送消息数组中的新值。您将看到另一个对象在消息中推送了相同的项。@lightstyle
var cells=cells
he脂多糖
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;  
}
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));
        }

                ....
}
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
}
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
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);