Node.js에서 객체 복제


203

node.js에서 객체를 복제하는 가장 좋은 방법은 무엇입니까

예를 들어 다음과 같은 상황을 피하고 싶습니다.

var obj1 = {x: 5, y:5};
var obj2 = obj1;
obj2.x = 6;
console.log(obj1.x); // logs 6

객체는 속성으로 복잡한 유형을 포함 할 수 있으므로 간단한 for (var x in obj1)로는 해결되지 않습니다. 재귀 복제본을 직접 작성해야합니까 아니면 보이지 않는 것이 내장되어 있습니까?


23
1. npm install underscore2. var _ = require('underscore')3 _.clone(objToClone).;
살만 폰 압바스

4
위의 @SalmanPK의 의견에서 이것은 얕은 복제본입니다. slifty의 예제에서는 작동하지만 중첩 된 배열이나 객체가 있으면 참조가됩니다. : /
Jesse

1
이 기사가 매우 유용 하다고 생각했습니다
Jordan Hudson

3
@Jordan Hudson-두 번째 예제에서 JSON을 아주 잘 사용합니다. var newObj = JSON.parse (JSON.stringify (oldObj)); // 이제 newObj는 복제본입니다. 유일한 문제는 stringify가 재귀 참조에서 작동하지 않으므로주의해야한다는 것입니다.
Kfir Erez

답변:


298

가능성 1

프릴이 적은 사본 :

var obj2 = JSON.parse(JSON.stringify(obj1));

가능성 2 (더 이상 사용되지 않음)

주의 : 이제이 솔루션은 Node.js 문서 에서 더 이상 사용되지 않는 것으로 표시됩니다 .

util._extend () 메소드는 내부 Node.js 모듈 외부에서 사용되도록 설계되지 않았습니다. 커뮤니티는 어쨌든 그것을 찾아서 사용했습니다.

더 이상 사용되지 않으며 새 코드에서 사용해서는 안됩니다. JavaScript는 Object.assign ()을 통해 매우 유사한 내장 기능을 제공합니다.

원래 답변 : :

얕은 사본의 경우 노드의 내장 util._extend()기능을 사용하십시오.

var extend = require('util')._extend;

var obj1 = {x: 5, y:5};
var obj2 = extend({}, obj1);
obj2.x = 6;
console.log(obj1.x); // still logs 5

노드 _extend기능 의 소스 코드 는 다음에 있습니다 : https://github.com/joyent/node/blob/master/lib/util.js

exports._extend = function(origin, add) {
  // Don't do anything if add isn't an object
  if (!add || typeof add !== 'object') return origin;

  var keys = Object.keys(add);
  var i = keys.length;
  while (i--) {
    origin[keys[i]] = add[keys[i]];
  }
  return origin;
};

5
이 질문은 구체적으로 재귀 클론을 요구했습니다. 얕은 복제본입니다.
Benjamin Atkin

28
이름 _*이 사적인 방법이라는 것을 의미한다고 생각되지 않습니까?
푹신한

7
모든 규모의 모든 JavaScript 프로젝트에는 extend () 구현이 하나 이상 있으며 Node도 예외는 아닙니다. Node.js 코어는이 기능을 광범위하게 사용합니다. Isaacs를 인용하자면, "언제나 아무데도 가지 않을 것입니다."
jimbo

2
나를 위해 완벽하게 일했습니다. 훨씬 더 IMO 개체 프로토 타입에 대해 장난 이상
마이클 Dausmann

12
이것은 잘못된 답변입니다. 노드 문서에 따라 : nodejs.org/api/util.html#util_util_extend_obj util._extend()메소드는 내부 Node.js 모듈 외부에서 사용되도록 의도되지 않았습니다. 커뮤니티는 어쨌든 그것을 찾아서 사용했습니다. 더 이상 사용되지 않으며 새 코드에서 사용해서는 안됩니다. 자바 스크립트가 내장 된 기능을 통해 매우 유사Object.assign().
Jordie

265

Object.assign언급되지 않은 것이 놀랍습니다 .

let cloned = Object.assign({}, source);

사용 가능한 경우 (예 : Babel) 객체 스프레드 연산자를 사용할 수 있습니다 .

let cloned = { ... source };

1
당신은 내 하루를 구했다! 감사합니다
wzr1337

2
타사 라이브러리를 가져 오거나 불완전한 JSON 해결 방법을 사용하는 것보다 훨씬 더 나은 솔루션입니다. 감사!
Neil S

75
이 얕은 사본입니다
요르단 데이비슨

14
딥 클론에 대한 경고, 딥 클론의 경우 여전히 다른 대안을 사용해야합니다. developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
gsalgadotoledo

1
객체 스프레드 연산자는 ES6이 아니라 3 단계 제안입니다. 그것은 당신이 babel과 함께 사용할 수는 있지만 내가 이해하는 것 없이는 사용할 수 없다는 것을 의미합니다. github.com/tc39/…
macdja38

24
Object.defineProperty(Object.prototype, "extend", {
    enumerable: false,
    value: function(from) {
        var props = Object.getOwnPropertyNames(from);
        var dest = this;
        props.forEach(function(name) {
            if (name in dest) {
                var destination = Object.getOwnPropertyDescriptor(from, name);
                Object.defineProperty(dest, name, destination);
            }
        });
        return this;
    }
});

사용할 수있는 확장 방법을 정의합니다. 이 기사에서 코드가 나온다 .


이것이 어떻게 작동하는지 보지 못합니다. 원본 객체를 수정합니다! 이 함수를 사용하여 객체의 클론을 얻으려면 어떻게해야합니까? 여기에 사용 코드를 추가 할 수 있습니까? 게시물과 블로그 게시물을 읽은 후에도 객체 복제에 어떻게 사용되는지 알아낼 수 없습니다.
Brad

3
이것이 실제로 작동합니까? "if (name in dest)"-속성이 이미 dest에있는 경우에만 속성을 변경합니다. 부정해야합니다.
Memical

8
Object.prototype을 수정하지 말아야합니까? 또한 해당 기사 링크가 손상되었습니다.
Daniel Schaffer

방금 기사 링크를 시도해 보았습니다. 시도했을 때 네트워크 문제 일 수 있습니다.
Michael Dillon

여러 의견을 바탕으로 객체의 프로토 타입에 추가되지 않는 변형을 포함하도록 답변을 업데이트했습니다.
Shamasis Bhattacharya

20
var obj2 = JSON.parse(JSON.stringify(obj1));

2
이것은 이미 존재하는 대답 에서 그것을 반복해도 아무런 의미가 없습니다.
Shadow Wizard는 당신을위한 귀입니다.

@ShadowWizard 이들은 다른 방법입니다. JSON 및 오브젝트로 간단히 변환이 한 대답의 사용을 연결하면서 Object.keys()객체를 통해 반복
mente

이 답변은 잘못되었습니다. JSON.stringify는 날짜 객체를 가져 와서 문자열로 축소 한 다음 구문 분석 한 후에는 객체 상태를 변경하여 객체의 상태를 변경하여 날짜의 경우 처음과 다른 객체로 남겨 둡니다.
twboc

13

JQuery에서 확장 기능을 사용할 수 있습니다.

var newClone= jQuery.extend({}, oldObject);  
var deepClone = jQuery.extend(true, {}, oldObject); 

Node.js 플러그인도 있습니다 :

https://github.com/shimondoodkin/nodejs-clone-extend

JQuery 또는 플러그인없이 수행하려면 여기를 읽으십시오.

http://my.opera.com/GreyWyvern/blog/show.dml/1725165


Node.js 플러그인이 완벽합니다. 감사!
Justin

좋은 대답입니다. 유용한 모듈이 거의 없습니다.
Chev


8

"자신의 롤"을 원하지 않는 경우 일부 노드 모듈이 있습니다. 이것은 좋아 보인다 : https://www.npmjs.com/package/clone

순환 참조를 포함하여 모든 종류의 물건을 처리하는 것처럼 보입니다. 로부터 github의의 페이지 :

복제 마스터는 개체, 배열, 날짜 개체 및 RegEx 개체를 복제합니다. 모든 것이 재귀 적으로 복제되므로 예를 들어 객체의 배열에서 날짜를 복제 할 수 있습니다. [...] 순환 참조? 네!


7

이 코드는 작동하는 원인이기도합니다. Object.create () 메서드는 지정된 프로토 타입 객체와 속성으로 새 객체를 만듭니다.

var obj1 = {x:5, y:5};

var obj2 = Object.create(obj1);

obj2.x; //5
obj2.x = 6;
obj2.x; //6

obj1.x; //5

4
이것은 얕은 사본이다
Radagast the Brown

6

NodeJS에서 객체를 복제하는 간단하고 빠른 방법은 Object.keys (obj) 메소드를 사용하는 것입니다

var a = {"a": "a11", "b": "avc"};
var b;

for(var keys = Object.keys(a), l = keys.length; l; --l)
{
   b[ keys[l-1] ] = a[ keys[l-1] ];
}
b.a = 0;

console.log("a: " + JSON.stringify(a)); // LOG: a: {"a":"a11","b":"avc"} 
console.log("b: " + JSON.stringify(b)); // LOG: b: {"a":0,"b":"avc"}

Object.keys 메소드에는 JavaScript 1.8.5가 필요합니다. nodeJS v0.4.11은이 방법을 지원합니다

물론 중첩 객체의 경우 재귀 기능을 구현해야합니다.


다른 솔루션은 기본 JSON (JavaScript 1.7에서 구현)을 사용하는 것이지만 이전보다 훨씬 느립니다 (~ 10 배 느림).

var a = {"a": i, "b": i*i};
var b = JSON.parse(JSON.stringify(a));
b.a = 0;

5

Github에는보다 직접적인 포트를 목표로하는 프로젝트도 있습니다 jQuery.extend().

https://github.com/dreamerslab/node.extend

jQuery 문서 에서 수정 된 예 :

var extend = require('node.extend');

var object1 = {
    apple: 0,
    banana: {
        weight: 52,
        price: 100
    },
    cherry: 97
};

var object2 = {
    banana: {
        price: 200
    },
    durian: 100
};

var merged = extend(object1, object2);


4

모두 고통 받고 있지만 해결책은 간단합니다.

var obj1 = {x: 5, y:5};

var obj2 = {...obj1}; // 붐


3

진정한 클론 옵션을 찾고, 여기에 대한 ridcully의 링크를 우연히 발견했습니다.

http://my.opera.com/GreyWyvern/blog/show.dml/1725165

Object프로토 타입에 첨부 된 함수를 열거 할 수 없도록 해당 페이지의 솔루션을 수정했습니다 . 내 결과는 다음과 같습니다.

Object.defineProperty(Object.prototype, 'clone', {
    enumerable: false,
    value: function() {
        var newObj = (this instanceof Array) ? [] : {};
        for (i in this) {
        if (i == 'clone') continue;
            if (this[i] && typeof this[i] == "object") {
                newObj[i] = this[i].clone();
            } else newObj[i] = this[i]
        } return newObj;
    }
});

잘하면 이것은 다른 사람에게도 도움이됩니다. 특히 "clone"이라는 속성에는 몇 가지주의 사항이 있습니다. 이것은 나를 위해 잘 작동합니다. 나는 그것을 쓰는 것에 대한 신용을 얻지 않습니다. 다시, 나는 그것이 어떻게 정의되고 있는지를 바꾸었다.


이것은 잘못이다. 날짜 유형은 객체 이므로이 코드는 날짜를 빈 객체로 대체합니다 ... 이것을 사용하지 마십시오.
jtblin


0

커피 스크립트를 사용하는 경우 다음과 같이 쉽습니다.

newObject = {}
newObject[key] = value  for own key,value of oldObject

비록 이것이 깊은 클론은 아닙니다.


0

대답 중 어느 것도 나를 만족시키지 못했으며, 일부는 작동하지 않거나 얕은 클론입니다. @ clint-harris의 대답과 JSON.parse / stringify 사용은 좋지만 꽤 느립니다. 빠른 복제가 빠른 모듈을 찾았습니다 : https://github.com/AlexeyKupershtokh/node-v8-clone


0

node.js에는 객체의 실제 복제본 (딥 카피)을 수행하는 기본 제공 방법이 없습니다. 까다로운 경우가 있으므로 반드시 라이브러리를 사용해야합니다. 나는 simpleoo 라이브러리를 위해 그런 함수를 썼다 . deepCopy필요하지 않은 경우 라이브러리에서 다른 것을 사용하지 않고도 함수를 사용할 수 있습니다 (아주 작음). 이 함수는 배열, 날짜 및 정규 표현식을 포함한 여러 데이터 유형 복제를 지원하고 재귀 참조를 지원하며 생성자 함수에 매개 변수가 필요한 객체와도 작동합니다.

코드는 다음과 같습니다.

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

/**
 * 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 = function deepCopy(src, /* INTERNAL */ _visited) {
    if(src == null || typeof(src) !== 'object'){
        return src;
    }

    // Initialize the visited objects array if needed
    // This is used to detect cyclic references
    if (_visited == undefined){
        _visited = [];
    }
    // Ensure src has not already been visited
    else {
        var i, len = _visited.length;
        for (i = 0; i < len; i++) {
            // If src was already visited, don't try to copy it, just return the reference
            if (src === _visited[i]) {
                return src;
            }
        }
    }

    // Add this object to the visited array
    _visited.push(src);

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

    //Special cases:
    //Array
    if (Object.prototype.toString.call(src) == '[object Array]') {
        //[].slice(0) would soft clone
        ret = src.slice();
        var i = ret.length;
        while (i--){
            ret[i] = deepCopy(ret[i], _visited);
        }
        return ret;
    }
    //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);
    }

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

    //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 ret = object_create(proto);

    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
        ret[key] = deepCopy(src[key], _visited);
    }
    return ret;
};

0
npm install node-v8-clone

가장 빠른 복제기, node.js에서 기본 복제 방법을 엽니 다

var clone = require('node-v8-clone').clone;
var newObj = clone(obj, true); //true - deep recursive clone

0

또 다른 해결책은 다음을 사용하여 새 변수에 직접 캡슐화하는 것입니다. obj1= {...obj2}


이것은 얕은 사본입니다
Rémi Doolaeghe

0

복제 라이브러리를 사용하여 개체를 딥 복제 할 수도 있습니다 .

 npm install --save clone
const clone = require('clone');

const clonedObject = clone(sourceObject);

-2

객체를 프로토 타입 한 다음 객체를 사용하고 변경할 때마다 객체 인스턴스를 호출 할 수 있습니다.

function object () {
  this.x = 5;
  this.y = 5;
}
var obj1 = new object();
var obj2 = new object();
obj2.x = 6;
console.log(obj1.x); //logs 5

객체 생성자에 인수를 전달할 수도 있습니다

function object (x, y) {
   this.x = x;
   this.y = y;
}
var obj1 = new object(5, 5);
var obj2 = new object(6, 6);
console.log(obj1.x); //logs 5
console.log(obj2.x); //logs 6

이것이 도움이 되길 바랍니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.