문제

무엇을 가장 효율적인 방법 복제 JavaScript object?내가 본 obj = eval(uneval(o)); 사용되지만, 는 비표준과만 지원하는 파이어 폭스.

나는 같은 것들 obj = JSON.parse(JSON.stringify(o)); 하지만 질문의 효율성이다.

나는 또한 본 재귀 복사 기능을 가진 다양한 결함이 있습니다.
놀랐어요 아무 표준 솔루션이 존재합니다.

도움이 되었습니까?

해결책

2019-June 참고: 이것은 원래 답변을 또 다른 대답하지 않는 적절한 응답을 이 질문입니다.는 왜 그것이 되었으로 정답이 있습니다.하지만 이후 늦게 집에 가서 만들에 급증과 그에 의해 지금까지 1 이 질문에 대한 답은,그것을 요구하는 솔루션으로 위키의 대답이다.

Native 깊은 복제

그것은"구조적 복제",작품에서 실험적으로 노드의 11 이상,희망이 땅에서는 브라우저입니다.보 이 답변 자세한 내용은.

빠르게 복제하여 데이터 손실-JSON.석/변환

을 사용하지 않는 경우 Dates,함수 undefined, Infinity,RegExps,지도,집합,Blob,FileLists,ImageDatas,스파 배열을 입력한 어레이 또는 기타 복잡한 유형에서 당신의 개체,매우 간단 하나이 딥 클론 개체:

JSON.parse(JSON.stringify(object))

const a = {
  string: 'string',
  number: 123,
  bool: false,
  nul: null,
  date: new Date(),  // stringified
  undef: undefined,  // lost
  inf: Infinity,  // forced to 'null'
  re: /.*/,  // lost
}
console.log(a);
console.log(typeof a.date);  // Date object
const clone = JSON.parse(JSON.stringify(a));
console.log(clone);
console.log(typeof clone.date);  // result of .toISOString()

Corban 의 응답 에 대한 벤치마크.

신뢰할 수 있는 복제는 라이브러리를 사용하여

때문에 복제 개체지 않은 사소한(복잡한 형태,원형 참조,기능 등) 가장 중요한 라이브러리는 기능을 제공하 clone 개체입니다. 바퀴를 재발견하지 마십시오 -이미 사용하고 있는 경우에는 도서관,체크가 있는 경우 객체를 복제하는 기능입니다.예를 들어,

ES6

완전성을 위해 참고하는 ES6 제공하는 두 개의 얕은 복사 메커니즘: Object.assign()확산 연산자.

다른 팁

이 벤치 마크 확인 : http://jsben.ch/#/bwfk9

속도가 내가 찾은 주요 관심사 인 이전 테스트에서

JSON.parse(JSON.stringify(obj))

물체를 복제하는 가장 느린 방법이 되려면 jQuery.extend ~와 함께 deep 플래그 설정은 10-20%로 맞습니다).

jQuery.extend는 꽤 빠릅니다 deep 깃발이 설정됩니다 false (얕은 클론). 유형 검증에 대한 추가 논리가 포함되어 있고 정의되지 않은 속성 등을 복사하지 않기 때문에 좋은 옵션입니다. 그러나 이렇게하면 약간 느려집니다.

복제하려고하거나 깊은 중첩 어레이를 피할 수있는 물체의 구조를 알고 있다면 간단한 것을 쓸 수 있습니다. for (var i in obj) HasOwnProperty를 확인하는 동안 객체를 복제하는 루프는 jQuery보다 훨씬 빠릅니다.

마지막으로 핫 루프에서 알려진 객체 구조를 복제하려는 경우 클론 절차를 중단하고 수동으로 객체를 구성하여 훨씬 더 많은 성능을 얻을 수 있습니다.

JavaScript 추적 엔진은 최적화에 빨다 for..in 루프 및 확인 hasownproperty도 속도가 느려집니다. 속도가 절대적인 경우 수동 복제.

var clonedObject = {
  knownProp: obj.knownProp,
  ..
}

그것을 사용하여 조심하십시오 JSON.parse(JSON.stringify(obj)) 메소드 켜짐 Date 사물 - JSON.stringify(new Date()) 날짜의 문자열 표현을 ISO 형식으로 반환합니다. JSON.parse() 그렇지 않습니다 다시 변환 Date 물체. 자세한 내용은이 답변을 참조하십시오.

또한 Chrome 65에서 최소한 원시 복제는 갈 길이 아닙니다. 에 따르면 이 jsperf, 새로운 기능을 만들어 기본 클로닝을 수행하는 것은 거의 800x json.stringify를 사용하는 것보다 느리게 보존합니다.

ES6에 대한 업데이트

JavaScript ES6을 사용하는 경우 복제 또는 얕은 사본을위한이 기본 방법을 사용해보십시오.

Object.assign({}, obj);

변수 만 있다고 가정하면 객체의 기능이 없다고 가정하면 사용할 수 있습니다.

var newObject = JSON.parse(JSON.stringify(oldObject));

구조적 복제

HTML 표준이 포함됩 내부 구조적 복제/직렬화 알고리즘 을 만들 수 있는 깊이 클론의 개체입니다.그것은 여전히 제한하는 특정 제공 형식이지만,또한 몇 가지 유형에 의해 지원되 JSON 그것은 또한 지원날짜,RegExps,지도,집합,Blob,FileLists,ImageDatas,스파 배열을 입력한 어레이,그리고 아마도 미래에 더 많은.그것은 또한 유지 참조에 복제,데이터 수 있도록 지원하는 순환적이고 재귀적 구조는 원인에 대한 오류 JSON.

지원 Node.js:실험🙂

v8 모듈 Node.js 현재(으로의 노드에 11) 노출하는 구조화된 API 를 직접 serialization, 지만,이 기능은 아직으로 표시된"시험"며,변경 또는 제거할 수 있습니다.를 사용하는 경우에는 호환되는 버전,복제하는 개체는 간단하다:

const v8 = require('v8');

const structuredClone = obj => {
  return v8.deserialize(v8.serialize(obj));
};

직접 지원 브라우저에서:어쩌면 결국?😐

브라우저하지 않는 현재 제공하는 직접적인 인터페이스에 대한 구조화된 복제,알고리즘,하지만 글로벌 structuredClone() 기능 에서 논의되었습니다. whatwg/html#793on GitHub.으로 현재를 제안하여,그것은 대부분의 목적을 위해 것으로 간단하다:

const clone = structuredClone(original);

지 않으면 이것은 배송,브라우저의 구조적 복제 구현에만 노출되는 간접적으로.

비동기 방법:용할 수 있습니다.😕

낮은 오버헤드를 만들 수 있는 방법 구조적 복제와 기존 Api 에 게시 데이터를 통해 하나의 포트 MessageChannels.다른 포트를 방출합니다 message 이벤트 구조의 복제본을 첨부 .data.불행하게도,듣기,이러한 이벤트에 대한 반드시 비동기식과 동기 대안 적은 실용적이다.

class StructuredCloner {
  constructor() {
    this.pendingClones_ = new Map();
    this.nextKey_ = 0;

    const channel = new MessageChannel();
    this.inPort_ = channel.port1;
    this.outPort_ = channel.port2;

    this.outPort_.onmessage = ({data: {key, value}}) => {
      const resolve = this.pendingClones_.get(key);
      resolve(value);
      this.pendingClones_.delete(key);
    };
    this.outPort_.start();
  }

  cloneAsync(value) {
    return new Promise(resolve => {
      const key = this.nextKey_++;
      this.pendingClones_.set(key, resolve);
      this.inPort_.postMessage({key, value});
    });
  }
}

const structuredCloneAsync = window.structuredCloneAsync =
    StructuredCloner.prototype.cloneAsync.bind(new StructuredCloner);

를 들어 사용:

const main = async () => {
  const original = { date: new Date(), number: Math.random() };
  original.self = original;

  const clone = await structuredCloneAsync(original);

  // They're different objects:
  console.assert(original !== clone);
  console.assert(original.date !== clone.date);

  // They're cyclical:
  console.assert(original.self === original);
  console.assert(clone.self === clone);

  // They contain equivalent values:
  console.assert(original.number === clone.number);
  console.assert(Number(original.date) === Number(clone.date));

  console.log("Assertions complete.");
};

main();

동기식 방법:다.🤢

기 좋은 옵션을 만들기 위한 구조화된 클론 동시에.다음과 같은 허무 해킹을 대신 합니다.

history.pushState()history.replaceState() 모두를 만들 구조적 복제는 그들의 첫 번째 인수 값을 지정 history.state.당신이 사용할 수 있습을 만드는 구조화제의 모든 개체가 이:

const structuredClone = obj => {
  const oldState = history.state;
  history.replaceState(obj, null);
  const clonedObj = history.state;
  history.replaceState(oldState, null);
  return clonedObj;
};

를 들어 사용:

'use strict';

const main = () => {
  const original = { date: new Date(), number: Math.random() };
  original.self = original;

  const clone = structuredClone(original);
  
  // They're different objects:
  console.assert(original !== clone);
  console.assert(original.date !== clone.date);

  // They're cyclical:
  console.assert(original.self === original);
  console.assert(clone.self === clone);

  // They contain equivalent values:
  console.assert(original.number === clone.number);
  console.assert(Number(original.date) === Number(clone.date));
  
  console.log("Assertions complete.");
};

const structuredClone = obj => {
  const oldState = history.state;
  history.replaceState(obj, null);
  const clonedObj = history.state;
  history.replaceState(oldState, null);
  return clonedObj;
};

main();

지만 동시에 이해할 수 있다.그것이 발생하는 모든의 오버헤드 조작과 관련된 브라우저의 역사입니다.이 메소드를 호출하면 반복적으로 발생할 수 있습니다 크롬이 될 일시적으로 응답하지 않습니다.

Notification 생성자 를 만듭 구조적의 복제에 관련된 데이터입니다.그것은 또한 시도를 표시하려면 브라우저는 사용자에게 알림을,그러나 이것은 자동으로 실패하지 않는 한 당신이 통지를 요청 권한이 있습니다.경우에는 권한이 있는 다른 목적을 위해,우리는 즉시 알림을 닫습니다.

const structuredClone = obj => {
  const n = new Notification('', {data: obj, silent: true});
  n.onshow = n.close.bind(n);
  return n.data;
};

를 들어 사용:

'use strict';

const main = () => {
  const original = { date: new Date(), number: Math.random() };
  original.self = original;

  const clone = structuredClone(original);
  
  // They're different objects:
  console.assert(original !== clone);
  console.assert(original.date !== clone.date);

  // They're cyclical:
  console.assert(original.self === original);
  console.assert(clone.self === clone);

  // They contain equivalent values:
  console.assert(original.number === clone.number);
  console.assert(Number(original.date) === Number(clone.date));
  
  console.log("Assertions complete.");
};

const structuredClone = obj => {
  const n = new Notification('', {data: obj, silent: true});
  n.close();
  return n.data;
};

main();

내장 된 것이 없다면 시도 할 수 있습니다.

function clone(obj) {
    if (obj === null || typeof (obj) !== 'object' || 'isActiveClone' in obj)
        return obj;

    if (obj instanceof Date)
        var temp = new obj.constructor(); //or new Date(obj);
    else
        var temp = obj.constructor();

    for (var key in obj) {
        if (Object.prototype.hasOwnProperty.call(obj, key)) {
            obj['isActiveClone'] = null;
            temp[key] = clone(obj[key]);
            delete obj['isActiveClone'];
        }
    }
    return temp;
}

한 줄의 코드에서 객체를 복제하는 효율적인 방법

an Object.assign 방법은 ECMAScript 2015 (ES6) 표준의 일부이며 필요한 것을 정확하게 수행합니다.

var clone = Object.assign({}, obj);

Object.Assign () 메소드는 하나 이상의 소스 개체에서 대상 개체로 열거 가능한 모든 자체 속성의 값을 복사하는 데 사용됩니다.

더 읽기 ...

그만큼 폴리 필 구형 브라우저를 지원하려면 :

if (!Object.assign) {
  Object.defineProperty(Object, 'assign', {
    enumerable: false,
    configurable: true,
    writable: true,
    value: function(target) {
      'use strict';
      if (target === undefined || target === null) {
        throw new TypeError('Cannot convert first argument to object');
      }

      var to = Object(target);
      for (var i = 1; i < arguments.length; i++) {
        var nextSource = arguments[i];
        if (nextSource === undefined || nextSource === null) {
          continue;
        }
        nextSource = Object(nextSource);

        var keysArray = Object.keys(nextSource);
        for (var nextIndex = 0, len = keysArray.length; nextIndex < len; nextIndex++) {
          var nextKey = keysArray[nextIndex];
          var desc = Object.getOwnPropertyDescriptor(nextSource, nextKey);
          if (desc !== undefined && desc.enumerable) {
            to[nextKey] = nextSource[nextKey];
          }
        }
      }
      return to;
    }
  });
}

암호:

// extends 'from' object with members from 'to'. If 'to' is null, a deep clone of 'from' is returned
function extend(from, to)
{
    if (from == null || typeof from != "object") return from;
    if (from.constructor != Object && from.constructor != Array) return from;
    if (from.constructor == Date || from.constructor == RegExp || from.constructor == Function ||
        from.constructor == String || from.constructor == Number || from.constructor == Boolean)
        return new from.constructor(from);

    to = to || new from.constructor();

    for (var name in from)
    {
        to[name] = typeof to[name] == "undefined" ? extend(from[name], null) : to[name];
    }

    return to;
}

테스트:

var obj =
{
    date: new Date(),
    func: function(q) { return 1 + q; },
    num: 123,
    text: "asdasd",
    array: [1, "asd"],
    regex: new RegExp(/aaa/i),
    subobj:
    {
        num: 234,
        text: "asdsaD"
    }
}

var clone = extend(obj);

이것이 제가 사용하는 것입니다.

function cloneObject(obj) {
    var clone = {};
    for(var i in obj) {
        if(typeof(obj[i])=="object" && obj[i] != null)
            clone[i] = cloneObject(obj[i]);
        else
            clone[i] = obj[i];
    }
    return clone;
}

성능 별 딥 카피 :최고에서 최악의 순위

  • 재 할당 "="(문자열 배열, 숫자 배열 - 만)
  • 슬라이스 (문자열 배열, 숫자 배열 - 만)
  • 연결 (문자열 배열, 번호 배열 - 만)
  • 사용자 정의 기능 : 루프 또는 재귀 사본
  • jQuery의 $ .extend
  • json.parse (문자열 배열, 번호 배열, 객체 배열 - 만)
  • aUNDSCORE.JS's _.clone (문자열 배열, 숫자 배열 - 만)
  • lo-dash의 _.clonedeep

딥 카피 문자열 또는 숫자 배열 (한 레벨 - 참조 포인터 없음) :

배열에 숫자와 문자열이 포함 된 경우 -slice (), .concat (), .splice (), 할당 연산자 "="및 indercore.js의 클론 함수와 같은 함수; 배열 요소의 깊은 사본을 만들 것입니다.

재 할인이 가장 빠른 성능을 갖는 경우

var arr1 = ['a', 'b', 'c'];
var arr2 = arr1;
arr1 = ['a', 'b', 'c'];

.slice ()는 .concat ()보다 성능이 향상됩니다.http://jsperf.com/duplicate-array-slice-vs-concat/3

var arr1 = ['a', 'b', 'c'];  // Becomes arr1 = ['a', 'b', 'c']
var arr2a = arr1.slice(0);   // Becomes arr2a = ['a', 'b', 'c'] - deep copy
var arr2b = arr1.concat();   // Becomes arr2b = ['a', 'b', 'c'] - deep copy

딥 카피 객체 배열 (둘 이상의 레벨 - 참조 포인터) :

var arr1 = [{object:'a'}, {object:'b'}];

사용자 정의 함수를 작성합니다 ($ .extend () 또는 JSON.PARSE보다 성능이 빠릅니다) :

function copy(o) {
   var out, v, key;
   out = Array.isArray(o) ? [] : {};
   for (key in o) {
       v = o[key];
       out[key] = (typeof v === "object" && v !== null) ? copy(v) : v;
   }
   return out;
}

copy(arr1);

타사 유틸리티 기능 사용 :

$.extend(true, [], arr1); // Jquery Extend
JSON.parse(arr1);
_.cloneDeep(arr1); // Lo-dash

jQuery의 $ .Extend가 더 나은 성능을 갖는 경우 :

var clone = function() {
    var newObj = (this instanceof Array) ? [] : {};
    for (var i in this) {
        if (this[i] && typeof this[i] == "object") {
            newObj[i] = this[i].clone();
        }
        else
        {
            newObj[i] = this[i];
        }
    }
    return newObj;
}; 

Object.defineProperty( Object.prototype, "clone", {value: clone, enumerable: false});

거기에 도서관 ( "클론"이라고 함), 이것이 꽤 잘합니다. 그것은 내가 아는 임의의 개체의 가장 완전한 재귀 복제/복사를 제공합니다. 또한 다른 답변으로 덮여 있지 않은 원형 참조도 지원합니다.

당신은 할 수 있습니다 NPM에서 찾으십시오, 도. Node.js뿐만 아니라 브라우저에도 사용할 수 있습니다.

다음은 사용 방법에 대한 예입니다.

설치하십시오

npm install clone

또는 포장하십시오 엔더.

ender build clone [...]

소스 코드를 수동으로 다운로드 할 수도 있습니다.

그런 다음 소스 코드에서 사용할 수 있습니다.

var clone = require('clone');

var a = { foo: { bar: 'baz' } };  // inital value of a
var b = clone(a);                 // clone a -> b
a.foo.bar = 'foo';                // change a

console.log(a);                   // { foo: { bar: 'foo' } }
console.log(b);                   // { foo: { bar: 'baz' } }

(면책 조항 : 저는 도서관의 저자입니다.)

나는 이것이 오래된 게시물이라는 것을 알고 있지만, 나는 이것이 걸려 넘어지는 다음 사람에게 도움이 될 것이라고 생각했다.

객체를 할당하지 않는 한 메모리에서 참조를 유지하지 않습니다. 따라서 다른 객체를 공유하려는 객체를 만들려면 다음과 같은 공장을 만들어야합니다.

var a = function(){
    return {
        father:'zacharias'
    };
},
b = a(),
c = a();
c.father = 'johndoe';
alert(b.father);

Cloning 객체는 항상 JS의 관심사 였지만 ES6 이전에 관한 것이 었습니다. 아래의 javaScript에서 객체를 복사하는 다른 방법을 나열하고 아래의 개체가 있고 그에 대한 깊은 사본을 갖고 싶다고 상상해보십시오.

var obj = {a:1, b:2, c:3, d:4};

원점을 변경하지 않고이 객체를 복사하는 방법에는 몇 가지가 있습니다.

1) ES5+, 간단한 기능을 사용하여 사본을 수행합니다.

function deepCopyObj(obj) {
    if (null == obj || "object" != typeof obj) return obj;
    if (obj instanceof Date) {
        var copy = new Date();
        copy.setTime(obj.getTime());
        return copy;
    }
    if (obj instanceof Array) {
        var copy = [];
        for (var i = 0, len = obj.length; i < len; i++) {
            copy[i] = cloneSO(obj[i]);
        }
        return copy;
    }
    if (obj instanceof Object) {
        var copy = {};
        for (var attr in obj) {
            if (obj.hasOwnProperty(attr)) copy[attr] = cloneSO(obj[attr]);
        }
        return copy;
    }
    throw new Error("Unable to copy obj this object.");
}

2) json.parse 및 json.stringify를 사용하는 ES5+.

var  deepCopyObj = JSON.parse(JSON.stringify(obj));

3) Angularjs :

var  deepCopyObj = angular.copy(obj);

4) jQuery :

var deepCopyObj = jQuery.extend(true, {}, obj);

5) coundscorejs & loadash :

var deepCopyObj = _.cloneDeep(obj); //latest version UndescoreJs makes shallow copy

이 도움을 바랍니다 ...

당신이 그것을 사용하는 경우, aUNDSCORE.JS 도서관은 다음과 같습니다 클론 방법.

var newObject = _.clone(oldObject);

JavaScript의 깊은 복사 객체 (나는 가장 좋고 가장 간단하다고 생각합니다)

1. JSON.PARSE 사용 (json.stringify (Object));

var obj = { 
  a: 1,
  b: { 
    c: 2
  }
}
var newObj = JSON.parse(JSON.stringify(obj));
obj.b.c = 20;
console.log(obj); // { a: 1, b: { c: 20 } }
console.log(newObj); // { a: 1, b: { c: 2 } } 

2. 생성 된 방법을 사용합니다

function cloneObject(obj) {
    var clone = {};
    for(var i in obj) {
        if(obj[i] != null &&  typeof(obj[i])=="object")
            clone[i] = cloneObject(obj[i]);
        else
            clone[i] = obj[i];
    }
    return clone;
}

var obj = { 
  a: 1,
  b: { 
    c: 2
  }
}
var newObj = cloneObject(obj);
obj.b.c = 20;

console.log(obj); // { a: 1, b: { c: 20 } }
console.log(newObj); // { a: 1, b: { c: 2 } } 

3. lo-dash의 _.clonedeep 사용 링크 Lodash

var obj = { 
  a: 1,
  b: { 
    c: 2
  }
}

var newObj = _.cloneDeep(obj);
obj.b.c = 20;
console.log(obj); // { a: 1, b: { c: 20 } }
console.log(newObj); // { a: 1, b: { c: 2 } } 

4. Object.Assign () 메소드 사용

var obj = { 
  a: 1,
  b: 2
}

var newObj = _.clone(obj);
obj.b = 20;
console.log(obj); // { a: 1, b: 20 }
console.log(newObj); // { a: 1, b: 2 }  

그러나 언제 잘못

var obj = { 
  a: 1,
  b: { 
    c: 2
  }
}

var newObj = Object.assign({}, obj);
obj.b.c = 20;
console.log(obj); // { a: 1, b: { c: 20 } }
console.log(newObj); // { a: 1, b: { c: 20 } } --> WRONG
// Note: Properties on the prototype chain and non-enumerable properties cannot be copied.

5. usscore.js _.clone 링크 aUNDSCORE.JS

var obj = { 
  a: 1,
  b: 2
}

var newObj = _.clone(obj);
obj.b = 20;
console.log(obj); // { a: 1, b: 20 }
console.log(newObj); // { a: 1, b: 2 }  

그러나 언제 잘못

var obj = { 
  a: 1,
  b: { 
    c: 2
  }
}

var newObj = _.cloneDeep(obj);
obj.b.c = 20;
console.log(obj); // { a: 1, b: { c: 20 } }
console.log(newObj); // { a: 1, b: { c: 20 } } --> WRONG
// (Create a shallow-copied clone of the provided plain object. Any nested objects or arrays will be copied by reference, not duplicated.)

참조 medium.com

JSBEN.CH 퍼포먼스 벤치마킹 놀이터 1 ~ 3 http://jsben.ch/kvqld Performance Deep copying objects in JavaScript

다음은 생성자가 매개 변수가 필요한 경우에도 작동하는 Conroyp의 답변 버전입니다.

//If Object.create isn't already defined, we just do the simple shim,
//without the second argument, since that's all we need here
var object_create = Object.create;
if (typeof object_create !== 'function') {
    object_create = function(o) {
        function F() {}
        F.prototype = o;
        return new F();
    };
}

function deepCopy(obj) {
    if(obj == null || typeof(obj) !== 'object'){
        return obj;
    }
    //make sure the returned object has the same prototype as the original
    var ret = object_create(obj.constructor.prototype);
    for(var key in obj){
        ret[key] = deepCopy(obj[key]);
    }
    return ret;
}

이 기능은 내에서도 사용할 수 있습니다 간단한 도서관.

편집하다:

다음은 더 강력한 버전입니다 (Justin McCandless 덕분에 지금은 주기적 참조도 지원합니다).

/**
 * Deep copy an object (make copies of all its object properties, sub-properties, etc.)
 * An improved version of http://keithdevens.com/weblog/archive/2007/Jun/07/javascript.clone
 * that doesn't break if the constructor has required parameters
 * 
 * It also borrows some code from http://stackoverflow.com/a/11621004/560114
 */ 
function deepCopy(src, /* INTERNAL */ _visited, _copiesVisited) {
    if(src === null || typeof(src) !== 'object'){
        return src;
    }

    //Honor native/custom clone methods
    if(typeof src.clone == 'function'){
        return src.clone(true);
    }

    //Special cases:
    //Date
    if(src instanceof Date){
        return new Date(src.getTime());
    }
    //RegExp
    if(src instanceof RegExp){
        return new RegExp(src);
    }
    //DOM Element
    if(src.nodeType && typeof src.cloneNode == 'function'){
        return src.cloneNode(true);
    }

    // Initialize the visited objects arrays if needed.
    // This is used to detect cyclic references.
    if (_visited === undefined){
        _visited = [];
        _copiesVisited = [];
    }

    // Check if this object has already been visited
    var i, len = _visited.length;
    for (i = 0; i < len; i++) {
        // If so, get the copy we already made
        if (src === _visited[i]) {
            return _copiesVisited[i];
        }
    }

    //Array
    if (Object.prototype.toString.call(src) == '[object Array]') {
        //[].slice() by itself would soft clone
        var ret = src.slice();

        //add it to the visited array
        _visited.push(src);
        _copiesVisited.push(ret);

        var i = ret.length;
        while (i--) {
            ret[i] = deepCopy(ret[i], _visited, _copiesVisited);
        }
        return ret;
    }

    //If we've reached here, we have a regular object

    //make sure the returned object has the same prototype as the original
    var proto = (Object.getPrototypeOf ? Object.getPrototypeOf(src): src.__proto__);
    if (!proto) {
        proto = src.constructor.prototype; //this line would probably only be reached by very old browsers 
    }
    var dest = object_create(proto);

    //add this object to the visited array
    _visited.push(src);
    _copiesVisited.push(dest);

    for (var key in src) {
        //Note: this does NOT preserve ES5 property attributes like 'writable', 'enumerable', etc.
        //For an example of how this could be modified to do so, see the singleMixin() function
        dest[key] = deepCopy(src[key], _visited, _copiesVisited);
    }
    return dest;
}

//If Object.create isn't already defined, we just do the simple shim,
//without the second argument, since that's all we need here
var object_create = Object.create;
if (typeof object_create !== 'function') {
    object_create = function(o) {
        function F() {}
        F.prototype = o;
        return new F();
    };
}

다음은 동일한 객체의 두 인스턴스를 만듭니다. 나는 그것을 발견하고 현재 그것을 사용하고 있습니다. 간단하고 사용하기 쉽습니다.

var objToCreate = JSON.parse(JSON.stringify(cloneThis));

Lodash는 좋은 것을 가지고 있습니다 _.clonedeep (값) 방법:

var objects = [{ 'a': 1 }, { 'b': 2 }];

var deep = _.cloneDeep(objects);
console.log(deep[0] === objects[0]);
// => false
function clone(obj)
 { var clone = {};
   clone.prototype = obj.prototype;
   for (property in obj) clone[property] = obj[property];
   return clone;
 }

Crockford는이 기능을 사용하여 다음을 제안합니다.

function object(o) {
    function F() {}
    F.prototype = o;
    return new F();
}

var newObject = object(oldObject);

그것은 간결하고 예상대로 작동하며 라이브러리가 필요하지 않습니다.


편집하다:

이것은 폴리 필입니다 Object.create, 당신은 이것을 사용할 수 있습니다.

var newObject = Object.create(oldObject);

노트: 이 중 일부를 사용하는 경우 사용하는 일부 반복에 문제가있을 수 있습니다. hasOwnProperty. 왜냐하면, create 상속받는 새 빈 개체를 만듭니다 oldObject. 그러나 여전히 유용하고 실용적입니다.

예를 들어 IF oldObject.a = 5;

newObject.a; // is 5

하지만:

oldObject.hasOwnProperty(a); // is true
newObject.hasOwnProperty(a); // is false

얕은 사본 1 라이너 (ECMAScript 5th Edition):

var origin = { foo : {} };
var copy = Object.keys(origin).reduce(function(c,k){c[k]=origin[k];return c;},{});

console.log(origin, copy);
console.log(origin == copy); // false
console.log(origin.foo == copy.foo); // true

그리고 얕은 사본 1 라이너 (ECMAScript 6th edition, 2015):

var origin = { foo : {} };
var copy = Object.assign({}, origin);

console.log(origin, copy);
console.log(origin == copy); // false
console.log(origin.foo == copy.foo); // true

내가 보지 못했기 때문에 Angularjs 사람들이 알고 싶어한다고 언급하고 생각했습니다 ...

angular.copy 또한 객체와 배열을 심층 복사하는 방법을 제공합니다.

어레이와 같은 객체에는 아직 이상적인 딥 클론 연산자가없는 것 같습니다. 아래 코드에서 알 수 있듯이 John Resig의 JQuery Cloner는 비수막 특성을 가진 배열을 배열이 아닌 객체로 바꾸고 Regdwight의 JSON Cloner는 비수체 특성을 떨어 뜨립니다. 다음 테스트는 여러 브라우저에서 이러한 점을 보여줍니다.

function jQueryClone(obj) {
   return jQuery.extend(true, {}, obj)
}

function JSONClone(obj) {
   return JSON.parse(JSON.stringify(obj))
}

var arrayLikeObj = [[1, "a", "b"], [2, "b", "a"]];
arrayLikeObj.names = ["m", "n", "o"];
var JSONCopy = JSONClone(arrayLikeObj);
var jQueryCopy = jQueryClone(arrayLikeObj);

alert("Is arrayLikeObj an array instance?" + (arrayLikeObj instanceof Array) +
      "\nIs the jQueryClone an array instance? " + (jQueryCopy instanceof Array) +
      "\nWhat are the arrayLikeObj names? " + arrayLikeObj.names +
      "\nAnd what are the JSONClone names? " + JSONCopy.names)

나는 당신의 목표가 "일반 오래된 JavaScript 객체"를 복제하는지 여부에 따라 두 가지 좋은 답변을 가지고 있습니다.

또한 귀하의 의도는 소스 개체에 대한 프로토 타입 참조가없는 완전한 클론을 만드는 것이라고 가정 해 봅시다. 완전한 클론에 관심이 없다면 다른 답변 (Crockford의 패턴)에 제공된 많은 Object.clone () 루틴을 사용할 수 있습니다.

평범한 오래된 JavaScript 객체의 경우, 현대적인 런타임에서 물체를 복제하는 시도적이고 진정한 좋은 방법은 매우 간단합니다.

var clone = JSON.parse(JSON.stringify(obj));

소스 객체는 순수한 JSON 객체 여야합니다. 즉, 모든 중첩 특성은 스칼라 (부울, 문자열, 배열, 개체 등)이어야합니다. regexp 또는 날짜와 같은 기능 또는 특수 개체는 복제되지 않습니다.

효율적입니까? 도대체 네. 우리는 모든 종류의 복제 방법을 시도했으며 이것이 가장 잘 작동합니다. 나는 일부 닌자가 더 빠른 방법을 불러 일으킬 수 있다고 확신합니다. 그러나 나는 우리가 한계 이익에 대해 이야기하고 있다고 생각합니다.

이 접근법은 단순하고 구현하기 쉽습니다. 편의 기능으로 싸서 실제로 이득을 짜야한다면 나중에 가십시오.

이제 비 배정 된 JavaScript 객체의 경우 간단한 대답이 없습니다. 실제로 JavaScript 함수와 내부 객체 상태의 동적 특성으로 인해 발생할 수 없습니다. 내부 기능으로 JSON 구조를 복제하려면 해당 기능과 내부 상황을 재현해야합니다. 그리고 JavaScript는 단순히 표준화 된 방법이 없습니다.

이 작업을 수행하는 올바른 방법은 코드 내에서 선언하고 재사용하는 편의 방법을 통한 것입니다. 편의 방법은 자신의 객체에 대한 이해로 부여하여 새 객체 내에서 그래프를 올바르게 재현 할 수 있습니다.

우리는 우리 자신의 글을 쓰고 있지만 내가 본 최고의 일반적인 접근 방식은 여기에 포함됩니다.

http://davidwalsh.name/javaScript-clone

이것이 올바른 아이디어입니다. 저자 (David Walsh)는 일반화 된 기능의 복제에 대해 언급했습니다. 사용 사례에 따라 선택할 수있는 일입니다.

주요 아이디어는 유형별로 기능의 인스턴스화 (또는 프로토 타입 클래스)를 특별하게 처리해야한다는 것입니다. 여기에서 그는 Regexp 및 날짜에 대한 몇 가지 예를 제공했습니다.

이 코드는 간단 할뿐만 아니라 매우 읽기 쉽습니다. 확장하기가 매우 쉽습니다.

이것이 효율적입니까? 도대체 네. 목표는 진정한 깊은 코피 클론을 생산하는 것이기 때문에 소스 객체 그래프의 멤버를 걸어야합니다. 이 접근법을 사용하면 어떤 어린이 회원을 치료할 것인지, 사용자 지정 유형을 수동으로 처리하는 방법을 정확하게 조정할 수 있습니다.

그래서 당신은 간다. 두 가지 접근법. 둘 다 내 견해에서 효율적입니다.

이것은 일반적으로 가장 효율적인 솔루션은 아니지만 필요한 작업을 수행합니다. 아래의 간단한 테스트 사례 ...

function clone(obj, clones) {
    // Makes a deep copy of 'obj'. Handles cyclic structures by
    // tracking cloned obj's in the 'clones' parameter. Functions 
    // are included, but not cloned. Functions members are cloned.
    var new_obj,
        already_cloned,
        t = typeof obj,
        i = 0,
        l,
        pair; 

    clones = clones || [];

    if (obj === null) {
        return obj;
    }

    if (t === "object" || t === "function") {

        // check to see if we've already cloned obj
        for (i = 0, l = clones.length; i < l; i++) {
            pair = clones[i];
            if (pair[0] === obj) {
                already_cloned = pair[1];
                break;
            }
        }

        if (already_cloned) {
            return already_cloned; 
        } else {
            if (t === "object") { // create new object
                new_obj = new obj.constructor();
            } else { // Just use functions as is
                new_obj = obj;
            }

            clones.push([obj, new_obj]); // keep track of objects we've cloned

            for (key in obj) { // clone object members
                if (obj.hasOwnProperty(key)) {
                    new_obj[key] = clone(obj[key], clones);
                }
            }
        }
    }
    return new_obj || obj;
}

순환 어레이 테스트 ...

a = []
a.push("b", "c", a)
aa = clone(a)
aa === a //=> false
aa[2] === a //=> false
aa[2] === a[2] //=> false
aa[2] === aa //=> true

기능 검사...

f = new Function
f.a = a
ff = clone(f)
ff === f //=> true
ff.a === a //=> false

Angularjs

글쎄, 당신이 Angular를 사용하고 있다면 당신도 이것도 할 수 있습니다

var newObject = angular.copy(oldObject);

나는 가장 큰 투표로 답에 동의하지 않습니다 여기. ㅏ 재귀 깊은 클론 ~이다 훨씬 더 빨리 보다 json.parse (json.stringify (OBJ)) 언급 된 접근.

그리고 다음은 빠른 참조 기능입니다.

function cloneDeep (o) {
  let newO
  let i

  if (typeof o !== 'object') return o

  if (!o) return o

  if (Object.prototype.toString.apply(o) === '[object Array]') {
    newO = []
    for (i = 0; i < o.length; i += 1) {
      newO[i] = cloneDeep(o[i])
    }
    return newO
  }

  newO = {}
  for (i in o) {
    if (o.hasOwnProperty(i)) {
      newO[i] = cloneDeep(o[i])
    }
  }
  return newO
}
// obj target object, vals source object
var setVals = function (obj, vals) {
    if (obj && vals) {
        for (var x in vals) {
            if (vals.hasOwnProperty(x)) {
                if (obj[x] && typeof vals[x] === 'object') {
                    obj[x] = setVals(obj[x], vals[x]);
                } else {
                    obj[x] = vals[x];
                }
            }
        }
    }
    return obj;
};

사용하려는 사람들을 위해 JSON.parse(JSON.stringify(obj)) 버전이지만 날짜 개체를 잃지 않고 두 번째 논쟁 parse 방법 문자열을 최신으로 변환하려면 :

function clone(obj) {
  var regExp = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/;
  return JSON.parse(JSON.stringify(x), function(k, v) {
    if (typeof v === 'string' && regExp.test(v))
      return new Date(v);
    return v;
  });
}

다음은 JavaScript 객체를 복제 할 수있는 포괄적 인 클론 () 메소드입니다. 거의 모든 경우를 처리합니다.

function clone(src, deep) {

    var toString = Object.prototype.toString;
    if (!src && typeof src != "object") {
        // Any non-object (Boolean, String, Number), null, undefined, NaN
        return src;
    }

    // Honor native/custom clone methods
    if (src.clone && toString.call(src.clone) == "[object Function]") {
        return src.clone(deep);
    }

    // DOM elements
    if (src.nodeType && toString.call(src.cloneNode) == "[object Function]") {
        return src.cloneNode(deep);
    }

    // Date
    if (toString.call(src) == "[object Date]") {
        return new Date(src.getTime());
    }

    // RegExp
    if (toString.call(src) == "[object RegExp]") {
        return new RegExp(src);
    }

    // Function
    if (toString.call(src) == "[object Function]") {

        //Wrap in another method to make sure == is not true;
        //Note: Huge performance issue due to closures, comment this :)
        return (function(){
            src.apply(this, arguments);
        });
    }

    var ret, index;
    //Array
    if (toString.call(src) == "[object Array]") {
        //[].slice(0) would soft clone
        ret = src.slice();
        if (deep) {
            index = ret.length;
            while (index--) {
                ret[index] = clone(ret[index], true);
            }
        }
    }
    //Object
    else {
        ret = src.constructor ? new src.constructor() : {};
        for (var prop in src) {
            ret[prop] = deep
                ? clone(src[prop], true)
                : src[prop];
        }
    }
    return ret;
};
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top