programing

자바스크립트로 딥클론하는 방법

bestprogram 2023. 9. 19. 21:18

자바스크립트로 딥클론하는 방법

자바스크립트 객체를 어떻게 딥클론합니까?

처럼 으로 알고 있습니다.JSON.parse(JSON.stringify(o))그리고.$.extend(true, {}, o)하지만 그런 틀은 사용하고 싶지 않습니다.

딥 클론을 만드는 가장 우아하거나 효율적인 방법은 무엇입니까?

우리는 어레이 복제와 같은 엣지 케이스에 신경을 씁니다.프로토타입 체인을 끊지 않고 자기 참조를 다루고 있습니다.

는 DOM 이기 하는 것은 신경 않습니다. 왜냐하면..cloneNode그런 이유로 존재합니다.

에 사용하고 싶기 입니다.node.jsV8 엔진의 ES5 기능을 사용해도 좋습니다.

[편집]

누가 제안하기 전에 개체에서 원형을 이어받아 복사본을 만드는 것과 복제하는 것에는 분명한 차이가 있음을 말씀드리겠습니다.전자는 프로토타입 체인을 엉망으로 만듭니다.

[추가 편집]

당신의 답변을 읽고 난 후, 저는 사물 전체를 복제하는 것은 매우 위험하고 어려운 게임이라는 짜증나는 발견을 하게 되었습니다.다음 폐쇄 기반 개체를 예로 들어보겠습니다.

var o = (function() {
     var magic = 42;

     var magicContainer = function() {
          this.get = function() { return magic; };
          this.set = function(i) { magic = i; };
     }

      return new magicContainer;
}());

var n = clone(o); // how to implement clone to support closures

시 하지만 의 할 수 할 수 있는 ?oJS에 JS 파서를 쓰지 않고도 말입니다.

더 이상 그러한 기능에 대한 현실적인 필요가 없어야 합니다.이것은 단지 학문적인 흥미일 뿐입니다.

아주 간단한 방법, 어쩌면 너무 간단할지도 모릅니다.

var cloned = JSON.parse(JSON.stringify(objectToClone));

복제할 내용에 따라 다릅니다.이것은 정말 JSON 객체입니까 아니면 자바스크립트의 어떤 객체입니까?복제를 원하는 경우 문제가 발생할 수 있습니다.무슨 문제?아래에서 설명하겠지만 우선 객체 리터럴, 프리미티브, 어레이 및 DOM 노드를 복제하는 코드 예시입니다.

function clone(item) {
    if (!item) { return item; } // null, undefined values check

    var types = [ Number, String, Boolean ], 
        result;

    // normalizing primitives if someone did new String('aaa'), or new Number('444');
    types.forEach(function(type) {
        if (item instanceof type) {
            result = type( item );
        }
    });

    if (typeof result == "undefined") {
        if (Object.prototype.toString.call( item ) === "[object Array]") {
            result = [];
            item.forEach(function(child, index, array) { 
                result[index] = clone( child );
            });
        } else if (typeof item == "object") {
            // testing that this is DOM
            if (item.nodeType && typeof item.cloneNode == "function") {
                result = item.cloneNode( true );    
            } else if (!item.prototype) { // check that this is a literal
                if (item instanceof Date) {
                    result = new Date(item);
                } else {
                    // it is an object literal
                    result = {};
                    for (var i in item) {
                        result[i] = clone( item[i] );
                    }
                }
            } else {
                // depending what you would like here,
                // just keep the reference, or create new object
                if (false && item.constructor) {
                    // would not advice to do that, reason? Read below
                    result = new item.constructor();
                } else {
                    result = item;
                }
            }
        } else {
            result = item;
        }
    }

    return result;
}

var copy = clone({
    one : {
        'one-one' : new String("hello"),
        'one-two' : [
            "one", "two", true, "four"
        ]
    },
    two : document.createElement("div"),
    three : [
        {
            name : "three-one",
            number : new Number("100"),
            obj : new function() {
                this.name = "Object test";
            }   
        }
    ]
})

이제 실제 개체 복제를 시작할 때 나타날 수 있는 문제에 대해 살펴보겠습니다.내가 지금 말하는 것은, 당신이 무언가를 함으로써 창조하는 물체들에 대해, 다음과 같은 것을 함으로써.

var User = function(){}
var newuser = new User();

물론 복제는 문제가 되지 않으며 모든 개체는 생성자 속성을 노출하고 개체를 복제하는 데 사용할 수 있지만 항상 작동하지는 않습니다.합니다도 할 수 .for in이 물체에는 문제가 있지만 같은 방향으로 가고 있습니다.시켰지만,if( false )진술.

그렇다면, 왜 복제가 고통스러울 수 있을까요?우선, 모든 사물/인스턴스에는 어떤 상태가 있을 수 있습니다.개체에 예를 들어 개인 변수가 없다는 것을 결코 확신할 수 없으며, 개체를 복제하면 상태가 깨집니다.

주(州)가 없다고 상상해 보세요, 괜찮습니다.그럼 우리에겐 또 다른 문제가 있습니다."건설자" 방식으로 복제하는 것은 우리에게 또 다른 장애물을 줄 것입니다.그것은 논쟁 의존성입니다.당신은 이 물체를 만든 사람이 그렇지 않았다는 것을 결코 확신할 수 없습니다.

new User({
   bike : someBikeInstance
});

이런 경우라면 운이 없는 거예요, 바이크.인스턴스는 일부 컨텍스트에서 생성되었을 수 있으며 해당 컨텍스트는 클론 메서드에 대해 알 수 없습니다.

그래서 어떻게 해야 할까요?그래도 할 수 있습니다.for in해결책, 그리고 그러한 물체를 일반적인 물체 리터럴처럼 취급하지만, 아마도 그러한 물체를 복제하지 않고, 단지 이 물체의 참조를 통과시키는 것이 아이디어일지도 모릅니다.

또 다른 해결책은 복제해야 하는 모든 개체가 이 부분을 자체적으로 구현하고 적절한 API 메서드(cloneObject 등)를 제공하는 규칙을 설정할 수 있습니다.가인 것.cloneNodeDOM을 위해 하고 있습니다.

당신이 결정하라.

JSON.parse(JSON.stringify())자바스크립트 객체를 딥 복사하기 위한 결합은 JSON 데이터를 위한 것이었기 때문에 효과적이지 않은 해킹입니다.다의 .undefined아니면function () {}입니다)을 무시할 입니다.null그들)은 자바스크립트 객체를 JSON으로 "스트링"(marshalling)할 때.

더 나은 해결책은 딥 카피 기능을 사용하는 것입니다.아래 기능은 개체를 복사하며, 타사 라이브러리(jQuery, LoDash 등)를 필요로 하지 않습니다.

function copy(aObject) {
  // Prevent undefined objects
  // if (!aObject) return aObject;

  let bObject = Array.isArray(aObject) ? [] : {};

  let value;
  for (const key in aObject) {

    // Prevent self-references to parent object
    // if (Object.is(aObject[key], aObject)) continue;
    
    value = aObject[key];

    bObject[key] = (typeof value === "object") ? copy(value) : value;
  }

  return bObject;
}

참고: 이 코드는 간단한 자체 참조를 확인할 수 있습니다(섹션 주석 해제).// Prevent self-references to parent object), 그러나 가능한 경우 자체 refe이 있는 개체를 만들지 않아야 합니다.참고하시기 바랍니다: https://softwareengineering.stackexchange.com/questions/11856/whats-wrong-with-circular-references

structuredClone()을 사용하여 딥 클론을 달성할 수 있습니다.

const original = { name: "stack overflow" };


// Clone it
const clone = structuredClone(original);

이제 Web API에 structuredClone이 있으며 이는 순환 참조로도 작동합니다.


기답

순환 참조가 있는 개체에 대해서도 작동하는 ES6 기능은 다음과 같습니다.

function deepClone(obj, hash = new WeakMap()) {
    if (Object(obj) !== obj) return obj; // primitives
    if (hash.has(obj)) return hash.get(obj); // cyclic reference
    const result = obj instanceof Set ? new Set(obj) // See note about this!
                 : obj instanceof Map ? new Map(Array.from(obj, ([key, val]) => 
                                        [key, deepClone(val, hash)])) 
                 : obj instanceof Date ? new Date(obj)
                 : obj instanceof RegExp ? new RegExp(obj.source, obj.flags)
                 // ... add here any specific treatment for other classes ...
                 // and finally a catch-all:
                 : obj.constructor ? new obj.constructor() 
                 : Object.create(null);
    hash.set(obj, result);
    return Object.assign(result, ...Object.keys(obj).map(
        key => ({ [key]: deepClone(obj[key], hash) }) ));
}

// Sample data
var p = {
  data: 1,
  children: [{
    data: 2,
    parent: null
  }]
};
p.children[0].parent = p;

var q = deepClone(p);

console.log(q.children[0].parent.data); // 1

세트 및 지도에 대한 참고 사항

집합과 지도의 키를 다루는 방법은 논쟁의 여지가 있습니다. 이러한 키는 종종 기본 키이지만(이 경우에는 논쟁의 여지가 없음) 객체가 될 도 있습니다.이 경우 문제는 다음과 같습니다. 이러한 키를 복제해야 할까요?

누군가는 이 작업을 수행해야 한다고 주장할 수 있습니다. 그러면 복사본에서 개체가 변형되면 원본에 있는 개체는 영향을 받지 않게 되고, 그 반대의 경우도 마찬가지입니다.

에 세트 / 입니다인 입니다.has둘 중 에 말입니다.키,다. 적어도 둘 중 하나를 변경하기 전에 말입니다.복사본이 이전에 발생한 적이 없는 키(복제 프로세스 중에 생성된 키)가 있는 Set/Map이라면 이상할 것입니다. 특정 개체가 해당 Set/Map의 키인지 여부를 알아야 하는 코드에는 그다지 유용하지 않습니다.

당신이 알아차리셨듯이, 저는 두 번째 의견에 더 가깝습니다: 집합과 지도의 키는 동일하게 유지되어야 하는 값(아마도 참조)입니다.

이러한 선택사항은 종종 다른(사용자 정의) 개체들과도 마주치게 됩니다.복제된 개체가 특정한 경우에 어떻게 동작할지에 따라 달라지기 때문에 일반적인 해결책은 없습니다.

언더스코어.js 기여 라이브러리에는 객체를 딥 클론하는 스냅샷이라는 기능이 있습니다.

소스의 스니펫:

snapshot: function(obj) {
  if(obj == null || typeof(obj) != 'object') {
    return obj;
  }

  var temp = new obj.constructor();

  for(var key in obj) {
    if (obj.hasOwnProperty(key)) {
      temp[key] = _.snapshot(obj[key]);
    }
  }

  return temp;
}

라이브러리가 프로젝트에 연결되면 단순히 다음을 사용하여 함수를 호출합니다.

_.snapshot(object);

현재 Underscore.js의 상위 집합인 Lo-Dash는 몇 가지 딥 클론 기능을 가지고 있습니다.

저자 자신의 답변에서:

lodash underscore빌드는 최신 안정 버전의 언더스코어와의 호환성을 보장하기 위해 제공됩니다.

다른 사람들이 이와 비슷한 질문에 대해 언급했듯이, 일반적인 의미에서 "객체"를 복제하는 것은 자바스크립트에서 의심스럽습니다.

즉 에서 가 "" , 가 개체의 .{ ... }복제를 원하는 것이 합리적인 JSON에서 리터럴 및/또는 단순 속성 할당 또는 역직렬화.오늘 저는 대용량 데이터 세트에 대해 어떤 일이 일어나는지 테스트하기 위해 서버로부터 받은 데이터를 인위적으로 5배 부풀리고 싶었지만, 데이터가 올바르게 작동하려면 개체(어레이)와 하위 개체가 서로 다른 개체여야 했습니다.클로닝을 통해 데이터 세트를 확장할 수 있었습니다.

return dta.concat(clone(dta),clone(dta),clone(dta),clone(dta));

데이터 개체를 복제하는 또 다른 방법은 데이터를 전송하기 전에 데이터 모델의 개체에서 상태 필드를 제거하고자 하는 호스트에 데이터를 다시 제출하는 것입니다.예를 들어 개체가 복제될 때 "_"로 시작하는 모든 필드를 개체에서 제거할 수 있습니다.

이 코드는 어레이를 지원하고 복제할 멤버를 선택하는 선택기(컨텍스트를 결정하기 위해 "경로" 문자열을 사용함)를 포함하여 일반적으로 작성하게 된 코드입니다.

function clone(obj,sel) {
    return (obj ? _clone("",obj,sel) : obj);
    }

function _clone(pth,src,sel) {
    var ret=(src instanceof Array ? [] : {});

    for(var key in src) {
        if(!src.hasOwnProperty(key)) { continue; }

        var val=src[key], sub;

        if(sel) {
            sub+=pth+"/"+key;
            if(!sel(sub,key,val)) { continue; }
            }

        if(val && typeof(val)=='object') {
            if     (val instanceof Boolean) { val=Boolean(val);        }
            else if(val instanceof Number ) { val=Number (val);        }
            else if(val instanceof String ) { val=String (val);        }
            else                            { val=_clone(sub,val,sel); }
            }
        ret[key]=val;
        }
    return ret;
    }

null이 아닌 루트 객체를 가정하고 멤버를 선택하지 않는 가장 단순하고 합리적인 딥 클론 솔루션은 다음과 같습니다.

function clone(src) {
    var ret=(src instanceof Array ? [] : {});
    for(var key in src) {
        if(!src.hasOwnProperty(key)) { continue; }
        var val=src[key];
        if(val && typeof(val)=='object') { val=clone(val);  }
        ret[key]=val;
        }
    return ret;
    }

이것이 내가 사용하는 딥 복제 방법입니다. 대단하다고 생각합니다. 당신이 제안을 해주길 바랍니다.

function deepClone (obj) {
    var _out = new obj.constructor;

    var getType = function (n) {
        return Object.prototype.toString.call(n).slice(8, -1);
    }

    for (var _key in obj) {
        if (obj.hasOwnProperty(_key)) {
            _out[_key] = getType(obj[_key]) === 'Object' || getType(obj[_key]) === 'Array' ? deepClone(obj[_key]) : obj[_key];
        }
    }
    return _out;
}

아래 기능은 자바스크립트 객체를 딥클론하는 가장 효율적인 방법입니다.

function deepCopy(obj){
    if (!obj || typeof obj !== "object") return obj;

    var retObj = {};

    for (var attr in obj){
        var type = obj[attr];

        switch(true){
            case (type instanceof Date):
                var _d = new Date();
                _d.setDate(type.getDate())
                retObj[attr]= _d;
                break;

            case (type instanceof Function):
                retObj[attr]= obj[attr];
                break;

            case (type instanceof Array):
                var _a =[];
                for (var e of type){
                    //_a.push(e);
                    _a.push(deepCopy(e));
                }
                retObj[attr]= _a;
                break;

            case (type instanceof Object):
                var _o ={};
                for (var e in type){
                    //_o[e] = type[e];
                    _o[e] = deepCopy(type[e]);
                }
                retObj[attr]= _o;
                break;

            default:
                retObj[attr]= obj[attr];
        }
    }
    return retObj;
}

var obj = {
    string: 'test',
    array: ['1'],
    date: new Date(),
    object:{c: 2, d:{e: 3}},
    function: function(){
        return this.date;
    }
};

var copyObj = deepCopy(obj);

console.log('object comparison', copyObj === obj); //false
console.log('string check', copyObj.string === obj.string); //true
console.log('array check', copyObj.array === obj.array); //false
console.log('date check', copyObj2.date === obj.date); //false
console.log('object check', copyObj.object === obj.object); //false
console.log('function check', copyObj.function() === obj.function()); //true

이 방법 사용 안 함

let cloned = JSON.parse(JSON.stringify(objectToClone));

이 는 ''를으)로 합니다. 이 메서드는 '함수, 정의되지 않음'을(를) 변환합니다.null

const myObj = [undefined, null, function () {}, {}, '', true, false, 0, Symbol];

const IsDeepClone = JSON.parse(JSON.stringify(myObj));

console.log(IsDeepClone); //[null, null, null, {…}, "", true, false, 0, null]

deepClone 함수를 사용해 보십시오.위에 몇 가지가 있습니다.

개체의 심층 클로닝은 여러 가지 방법으로 수행할 수 있지만 각각은 아래에 언급된 대로 고유한 제한을 가집니다.따라서 구조화된 Clone 알고리즘을 사용하는 것을 제안하겠습니다.

  • JSON.parse(JSON.stringify(object))되지 않은 것. -수,짜,다.

const obj = {
  name: 'alpha',
  printName: function() {
    console.log(this.name);
  }
};

console.log(JSON.parse(JSON.stringify(obj))); // function not copied

  • _.cloneDeep(object)은 좋은 필요합니다 -합니다.

const obj = {
  name: 'alpha',
  printName: function() {
    console.log(this.name);
  }
};

filteredArray = _.cloneDeep(obj);
console.log(filteredArray)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/1.2.1/lodash.min.js"></script>

  • structuredClone(object) - Browser Native API (JSON.parse()와 JSON.stringify()나 맵, 설정, 날짜, RegEx다)

const a = { x: 20, date: new Date() };
a.c = a;

console.log(structuredClone(a)); // { x: 20, date: <date object>, c: <circular ref> }

console.log(JSON.parse(JSON.stringify(a))); // throwing a TypeError

더 이상 그러한 기능에 대한 현실적인 필요가 없어야 합니다.이것은 단지 학문적인 흥미일 뿐입니다.

순수한 운동으로서, 이것은 더 기능적인 방법입니다.@tfmontague의 답변을 확장한 것입니다. 거기에 가드 블록을 추가하는 것을 제안했습니다.하지만 ES6를 사용하고 모든 기능을 작동시켜야 한다고 생각하기 때문에, 여기 제 핌프 버전이 있습니다.배열을 매핑하고 개체를 축소해야 하기 때문에 논리가 복잡해지지만 돌연변이는 피할 수 있습니다.

const cloner = (x) => {
    const recurseObj = x => (typeof x === 'object') ? cloner(x) : x
    const cloneObj = (y, k) => {
        y[k] = recurseObj(x[k])
        return y
    }
    // Guard blocks
    // Add extra for Date / RegExp if you want
    if (!x) {
        return x
    }
    if (Array.isArray(x)) {
        return x.map(recurseObj)
    }
    return Object.keys(x).reduce(cloneObj, {})
}
const tests = [
    null,
    [],
    {},
    [1,2,3],
    [1,2,3, null],
    [1,2,3, null, {}],
    [new Date('2001-01-01')], // FAIL doesn't work with Date
    {x:'', y: {yx: 'zz', yy: null}, z: [1,2,3,null]},
    {
        obj : new function() {
            this.name = "Object test";
        }
    } // FAIL doesn't handle functions
]
tests.map((x,i) => console.log(i, cloner(x)))

나의 모든 답변에 추가.

function deepCopy(arr) {
  if (typeof arr !== 'object') return arr
  if (Array.isArray(arr)) return [...arr].map(deepCopy)
  for (const prop in arr) 
    copy[prop] = deepCopy(arr[prop])
  return copy
}

내 솔루션, 딥 클론 개체, 어레이 및 기능.

let superClone = (object) => {
  let cloning = {};

  Object.keys(object).map(prop => {
     if(Array.isArray(object[prop])) {
        cloning[prop] = [].concat(object[prop])
    } else if(typeof  object[prop] === 'object') {
      cloning[prop] = superClone(object[prop])
    } else cloning[prop] = object[prop]
  })

  return cloning
}

let obj = {
  a: 'a',
  b: 'b',
  c: {
    deep: 'try and copy me',
    d: {
      deeper: 'try me again',
      callDeeper() {
       return this.deeper
     }
    },
    arr: [1, 2, 3]
  },
  hi() {
    return this.a
  }
};


const cloned = superClone(obj)
obj.a = 'A' 
obj.c.deep = 'i changed'
obj.c.arr = [45,454]
obj.c.d.deeper = 'i changed'

console.log(cloned) // unchanged object

개체에 메서드가 포함되어 있는 경우 JSON을 사용하여 심층 복제하지 않는 경우 JSON 심층 복제는 메서드를 복제하지 않습니다.

가.person2이름만 복제하고 이름은 복제하지 않습니다.person1인사법.


const person1 = {
  name: 'John',
  greet() {
    return `HI, ${this.name}`
  }
}
 
const person2 = JSON.parse(JSON.stringify(person1))
 
console.log(person2)  // { name: 'John' }

structuredClone됩니다에서 됩니다.

주요 한계는 DONT 대처 기능에 관한 것입니다.수동으로 복사/이동하려면 추가 작업이 필요합니다.

나중에 프로토타입을 추가하면 수업을 쉽게 복사할 수 있습니다.

const proto = Object.getPrototypeOf(object)
const newObject = structuredClone(object)
Object.setPrototypeOf(newObject, proto)

맵에 특별한 처리가 필요하다는 것을 알게 되었고, 따라서 이 스레드의 모든 제안과 함께 코드는 다음과 같습니다.

function deepClone( obj ) {
    if( !obj || true == obj ) //this also handles boolean as true and false
        return obj;
    var objType = typeof( obj );
    if( "number" == objType || "string" == objType ) // add your immutables here
        return obj;
    var result = Array.isArray( obj ) ? [] : !obj.constructor ? {} : new obj.constructor();
    if( obj instanceof Map )
        for( var key of obj.keys() )
            result.set( key, deepClone( obj.get( key ) ) );
    for( var key in obj )
        if( obj.hasOwnProperty( key ) )
            result[key] = deepClone( obj[ key ] );
    return result;
}

이는 배열, 객체 및 프리미티브에 적합합니다.두 개의 순회 방법 사이를 전환하는 이중 재귀 알고리즘:

const deepClone = (objOrArray) => {

  const copyArray = (arr) => {
    let arrayResult = [];
    arr.forEach(el => {
        arrayResult.push(cloneObjOrArray(el));
    });
    return arrayResult;
  }

  const copyObj = (obj) => {
    let objResult = {};
    for (key in obj) {
      if (obj.hasOwnProperty(key)) {
        objResult[key] = cloneObjOrArray(obj[key]);
      }
    }
    return objResult;
  }

  const cloneObjOrArray = (el) => {
    if (Array.isArray(el)) {
      return copyArray(el);
    } else if (typeof el === 'object') {
      return copyObj(el);
    } else {
      return el;
    }
  }

  return cloneObjOrArray(objOrArray);
}

deepCopy를 만드는 데 재귀를 사용할 수 있습니다.array, object, object의 array, object with 함수의 object 복사본을 만들 수 있습니다.당신이 원한다면, 당신은 지도 등과 같은 다른 형태의 데이터 구조에 대한 기능을 추가할 수 있습니다.

function deepClone(obj) {
         var retObj;
        _assignProps = function(obj, keyIndex, retObj) {
               var subType = Object.prototype.toString.call(obj[keyIndex]);
               if(subType === "[object Object]" || subType === "[object Array]") {
                    retObj[keyIndex] = deepClone(obj[keyIndex]);
               }
               else {
                     retObj[keyIndex] = obj[keyIndex];
               }
        };

        if(Object.prototype.toString.call(obj) === "[object Object]") {
           retObj = {};
           for(key in obj) {
               this._assignProps(obj, key, retObj);
           }
        }
        else if(Object.prototype.toString.call(obj) == "[object Array]") {
           retObj = [];
           for(var i = 0; i< obj.length; i++) {
              this._assignProps(obj, i, retObj);
            }
        };

        return retObj;
    };

불변 JS 사용

import { fromJS } from 'immutable';

// An object we want to clone
let objA = { 
   a: { deep: 'value1', moreDeep: {key: 'value2'} } 
};

let immB = fromJS(objA); // Create immutable Map
let objB = immB.toJS(); // Convert to plain JS object

console.log(objA); // Object { a: { deep: 'value1', moreDeep: {key: 'value2'} } }
console.log(objB); // Object { a: { deep: 'value1', moreDeep: {key: 'value2'} } }

// objA and objB are equalent, but now they and their inner objects are undependent
console.log(objA === objB); // false
console.log(objA.a === objB.a); // false
console.log(objA.moreDeep === objB.moreDeep); // false

오르로다시/합병

import merge from 'lodash/merge'

var objA = {
    a: [{ 'b': 2 }, { 'd': 4 }]
};
// New deeply cloned object:
merge({}, objA ); 

// We can also create new object from several objects by deep merge:
var objB = {
    a: [{ 'c': 3 }, { 'e': 5 }]
};
merge({}, objA , objB ); // Object { a: [{ 'b': 2, 'c': 3 }, { 'd': 4, 'e': 5 }] }

순환 참조를 사용하는 이 방법은 제게 도움이 됩니다.

 //a test-object with circular reference :
 var n1 = {   id:0,   text:"aaaaa",   parent:undefined} 
 var n2 = {  id:1,   text:"zzzzz",   parent:undefined } 
 var o = { arr:[n1,n2],   parent:undefined } 
 n1.parent = n2.parent = o;
 var obj = {   a:1,   b:2,   o:o }
 o.parent = obj;

 function deepClone(o,output){ 

     if(!output) output = {};  
     if(o.______clone) return o.______clone;
     o.______clone = output.______clone = output;

   for(var z in o){

     var obj = o[z];
     if(typeof(obj) == "object") output[z] = deepClone(obj)
     else output[z] = obj; 
    }

   return output;
}

console.log(deepClone(obj));

var newDate = newDate (this.oldDate);기능하기 위해 oldDate를 전달하고 이.oldDate에서 새Date를 생성하고 있었는데 이를 변경하고 있었습니다.oldDate도 변경하고 있었습니다.그래서 저는 그 해결책을 사용했고 효과가 있었습니다.

이 솔루션은 [...target] 또는 {...target}을(를) 사용할 때 재귀 문제를 방지합니다.

function shallowClone(target) {
  if (typeof a == 'array') return [...target]
  if (typeof a == 'object') return {...target}
  return target
}

/* set skipRecursion to avoid throwing an exception on recursive references */
/* no need to specify refs, or path -- they are used interally */
function deepClone(target, skipRecursion, refs, path) {
  if (!refs) refs = []
  if (!path) path = ''
  if (refs.indexOf(target) > -1) {
    if (skipRecursion) return null
    throw('Recursive reference at ' + path)
  }
  refs.push(target)
  let clone = shallowCopy(target)
  for (i in target) target[i] = deepClone(target, refs, path + '.' + i)
  return clone
}

안녕하세요 저는 그냥 제 답변을 올리고 싶었어요 왜냐하면 제 생각에 더 읽기 쉽거든요.참고: 제가 수업을 사용하지 않기 때문에 이것은 수업을 포함하지 않지만, 당신은 그것을 위한 조건을 쉽게 추가할 수 있습니다.

/** Copies any type of object/array of objects 
 * @param obj The object to be copied
 * @param customKeys A list of keys that are to be excluded from deepCopy (optional)
*/
export function deepCopyObject(obj: any, customKeys?: Array<string|number|symbol>) {
    if (obj == undefined)
        return;
    if (typeof obj !== 'object')
        return obj;
    if (typeof obj === 'function')
        return obj;
    
    const isArray = obj.length > -1;
    if (isArray)
        return copyArray(obj);
    
    const isObjectDate = obj instanceof Date;
    if(isObjectDate)
        return new Date(obj);
    
    const isDOM = obj.nodeType && typeof obj.cloneNode == "function";
    if (isDOM)
        return obj.cloneNode(true);
    
    const isHtmlComponent = obj.$$typeof != undefined; // you can pass html/react components and maybe setup a custom function to copy them
    if (isHtmlComponent)
        return obj;

    const newObject = <typeof obj>{};
    const keys = Object.keys(obj);
    keys.forEach((key: keyof (typeof obj)) => {
        newObject[key] = copyKeysOfTypeObject(obj, key, customKeys);
    })

    const cantAccessObjectKeys = keys.lenght ==0; // ex: window.navigator
    if (cantAccessObjectKeys)
        return obj;
    
    return newObject
}

function copyArray(arr: any) {
    const newArr = new Array(0);
    arr.forEach((obj: any) => {
        newArr.push(deepCopyObject(obj));
    })
    return newArr;
}

function copyKeysOfTypeObject(obj: any, key: string | number | symbol, customKeys?: Array<string | number | symbol>) {
    if (!key)
        return;
    if (customKeys && customKeys.includes(key))
        return obj[key];
    return deepCopyObject(obj[key]);
}
let obj1 = {
    a: 100,
    b: {
        c: 200,
        d: [1, { f: 5 }, 3],
        e: () => {}
    }
}

function deepClone(obj) {
    let newObj = {};

    for (let key in obj) {
        let val = obj[key];

        if (val instanceof Array) {
            //newObj[key] = [...val]
          newObj[key] = [];
          val.forEach((value, index) => {
            newObj[key][index] = (typeof value === 'object' ? deepClone(value) : value);
          });
          
        } else if (val instanceof Date) {
            newObj[key] = new Date(val)
        } else if (typeof val === 'object') {
            newObj[key] = deepClone(val)
        } else {
            newObj[key] = val;
        }
    }
    return newObj;
}

obj2 = deepClone(obj1);

obj1.b.d[1].f = 2;

console.log(obj1);
console.log(obj2);

언급URL : https://stackoverflow.com/questions/4459928/how-to-deep-clone-in-javascript