English 中文(简体)
在Javascript中,在进行深度拷贝时,我如何避免循环,因为一个属性是“这个”?
原标题:In Javascript, when performing a deep copy, how do I avoid a cycle, due to a property being "this"?

我有一些图书馆代码 一直在我身上无休止地循环

I m not clear on how to best perform cycle detection and avoidance in javascript. i.e. there s no programmatic way of inspecting whether an object came from a "this" reference, is there?

Here s the code. Thanks!

setAttrs: function(config) {
    var go = Kinetic.GlobalObject;
    var that = this;

    // set properties from config
    if(config !== undefined) {
        function setAttrs(obj, c) {
            for(var key in c) {
                var val = c[key];

                /*
                 * if property is an object, then add an empty object
                 * to the node and then traverse
                 */
                if(go._isObject(val) && !go._isArray(val) && !go._isElement(val)) {
                    if(obj[key] === undefined) {
                        obj[key] = {};
                    }
                    setAttrs(obj[key], val);  // <--- offending code; 
                                              // one of my "val"s is a "this" reference
                                              // to an enclosing object
                }
最佳回答

我所知道的处理这种情况的“可靠和干净”方式是使用一组“访问”对象,然后根据当前对象是否已经“访问”而作出反应 -- -- 终止、插入符号参考等。

Crockford先生在cources.js 中使用了这种方法,他在收集中使用了Array。

// If the value is an object or array, look to see if we have already
// encountered it. If so, return a $ref/path object. This is a hard way,
// linear search that will get slower as the number of unique objects grows.

for (i = 0; i < objects.length; i += 1) {
    if (objects[i] === value) {
        return {$ref: paths[i]};
    }
}

不幸的是,在 JavaScript 中无法为此使用原始的“ Hash” 方法, 因为它缺乏身份映射。 虽然数组收藏的界限是 < code>O(n)2 , 但这里的“ hash” 并不比听起来的 < / em > 糟糕 :

这是因为, 如果“ 访问” 收藏只是个守护物, 那么 < code>n 的值只是堆叠的深度 : 只有循环才重要, 而复制同一个对象的多次并不重要 。 也就是说, “ 访问” 收藏中的对象可以在堆叠的反风中切换 。

在循环.js 代码中, “ 访问” 收藏无法被修剪, 因为它必须确保对给定对象总是使用相同的符号名称, 这样序列化就可以在恢复它时“ 保存引用 ” 。 但是, 即使在此情况下, < code>n 也是 < em> only 唯一的非原始值数量 。

我唯一能想到的其他方法就是在所穿越的物体上直接加上“参观财产”,我认为这是一个普遍不可取的特征。 (然而,见Bergi s 评论关于这一文物的[相对 容易清理。 )

快乐的编码。

问题回答

我对“访问”的属性@pst提到的属性可能长得像很感兴趣,

Object.copyCircular = function deepCircularCopy(o) {
    const gdcc = "__getDeepCircularCopy__";
    if (o !== Object(o))
        return o; // primitive value
    var set = gdcc in o,
        cache = o[gdcc],
        result;
    if (set && typeof cache == "function")
        return cache();
    // else
    o[gdcc] = function() { return result; }; // overwrite
    if (o instanceof Array) {
        result = [];
        for (var i=0; i<o.length; i++) {
            result[i] = deepCircularCopy(o[i]);
    } else {
        result = {};
        for (var prop in o)
            if (prop != gdcc)
                result[prop] = deepCircularCopy(o[prop]);
            else if (set)
                result[prop] = deepCircularCopy(cache);
    }
    if (set)
        o[gdcc] = cache; // reset
    else
        delete o[gdcc]; // unset again
    return result;
};

请注意,这只是一个例子。它不支持:

  • non-plain objects. Everything with a prototype (except arrays) will not be cloned but copied to a new Object! This includes functions!
  • cross-global-scope objects: it uses instanceof Array.
  • property descriptors like setters/getters, unwritable and nonenumerable properties

古德兹:

  • it does not use a big array which it needs to search each time it encounters an object.

补缺 :

  • does not work on objects which have a __getDeepCircularCopy__ method that does not what it claims. Although methods (properties with a function as value) are not supported anyway in this lightweight version.

此解决方案将在圆形引用对象上工作, 复制圆形结构, 但不以无限环 结束。 请注意, “ 循环” 是指此属性在“ 树” 中引用其“ 父母” 之一 :

   [Object]_            [Object]_
     /    |              /    |
   prop     |           prop    |
     \_____/             |      |
                        |/     |
                      [Object]  |
                               |
                         prop   |
                            \___/

分享一片叶子的树木结构不会被复制,

            [Object]                     [Object]
             /                           /    
            /                           /      
          |/_      _|                 |/_      _|  
      [Object]    [Object]   ===>  [Object]    [Object]
                   /                 |           |
                  /                  |           |
            _|  |/_                 |/         |/
            [Object]               [Object]    [Object]

除非你想跟踪所有复制的属性 。

但如果您确定每个属性都是 null 、字符串、数字、数组或简单对象, 您可以捕获 JSON.stringify explications explications 以查看是否有背引用, 例如 :

try {
    JSON.stringify(obj);
    // It s ok to make a deep copy of obj
} catch (e) {
    // obj has back references and a deep copy would generate an infinite loop
    // Or finite, i.e. until the stack space is full.
}

这只是一个想法,我对表演一无所知,恐怕大型物体的表演可能相当缓慢。

在此选择一个简单的递归克隆方法。与其他许多解决方案一样,大多数非基本属性将与原始对象(如函数)共享引用。

它通过保存被引用对象的地图来处理无穷环绕,这样以后的引用可以共享相同的克隆。

const georgeCloney = (originalObject, __references__ = new Map()) => {
  if(typeof originalObject !== "object" || originalObject === null) {
    return originalObject;
  }

  // If an object has already been cloned then return a
  // reference to that clone to avoid an infinite loop
  if(__references__.has(originalObject) === true) {
    return __references__.get(originalObject);
  }

  let clonedObject = originalObject instanceof Array ? [] : {};

  __references__.set(originalObject, clonedObject);

  for(let key in originalObject) {
    if(originalObject.hasOwnProperty(key) === false) {
      continue;
    }

    clonedObject[key] = georgeCloney(originalObject[key], __references__);
  }

  return clonedObject;
};

实例使用...

let foo = {};
foo.foo = foo;

let bar = georgeCloney(foo);
bar.bar = "Jello World!";

// foo output
// {
//   foo: {
//     foo: {...}
//   }
// }
// 
// bar output
// { 
//   foo: { 
//     foo: {...},
//     bar: "Jello World!"
//   }, 
//   bar: "Jello World!"
// }

我不得不为采访做这个 这就是我得到的:

Object.defineProperty(Object.prototype,  deepclone , { enumerable :false, configurable :true, value :function(){
  let map /*for replacement*/ =new Map(), rep ={} ;map.set(this, rep)
  let output = (function medclone(_, map){  let output ={..._}
    for(let k in _){  let v =_[k]
      let v2 ;if(!(v instanceof Object)) v2 =v ;else {
        if(map.has(v)) v2 =map.get(v) ;else {
          let rep ={}
          map.set(v, rep), v2 =medclone(v, map)
          Replace(rep, v2), map.set(v, v2)
        }
      }
      output[k] =v2
    }    return output
  })(this, map)
  Replace(rep, output)
  return output
  /*[*/ function Replace(rep/*resentative*/, proper, branch =proper, seens =new Set()){
    for(let k in branch){  let v =branch[k]
      if(v ===rep) branch[k] =proper
      else if(v instanceof Object &&!seens.has(v)) seens.add(v), Replace(rep, proper, v, seens)
    }
  }/*]*/
} })
                                                                                                                                  // Code is freely available for use for academia/scrutiny. As for development, contact author. 

使用的方法是“隐藏和斜线”, 而不是“在编码前有足够的时间规划”, 这样结果不会那么伟大, 但效果会很有效。





相关问题
selected text in iframe

How to get a selected text inside a iframe. I my page i m having a iframe which is editable true. So how can i get the selected text in that iframe.

How to fire event handlers on the link using javascript

I would like to click a link in my page using javascript. I would like to Fire event handlers on the link without navigating. How can this be done? This has to work both in firefox and Internet ...

How to Add script codes before the </body> tag ASP.NET

Heres the problem, In Masterpage, the google analytics code were pasted before the end of body tag. In ASPX page, I need to generate a script (google addItem tracker) using codebehind ClientScript ...

Clipboard access using Javascript - sans Flash?

Is there a reliable way to access the client machine s clipboard using Javascript? I continue to run into permissions issues when attempting to do this. How does Google Docs do this? Do they use ...

javascript debugging question

I have a large javascript which I didn t write but I need to use it and I m slowely going trough it trying to figure out what does it do and how, I m using alert to print out what it does but now I ...

Parsing date like twitter

I ve made a little forum and I want parse the date on newest posts like twitter, you know "posted 40 minutes ago ","posted 1 hour ago"... What s the best way ? Thanx.