Node.js'de Bir Nesneyi Klonlama


203

Node.js dosyasındaki bir nesneyi kopyalamanın en iyi yolu nedir?

Örneğin, aşağıdaki durumdan kaçınmak istiyorum:

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

Nesne, öznitelik olarak karmaşık türler içerebilir, bu nedenle basit (obj1 içindeki x var) çözemez. Kendim özyinelemeli bir klon yazmam gerekiyor mu yoksa görmediğim bir şey var mı?


23
1. npm install underscore2. var _ = require('underscore')3 _.clone(objToClone).;
Salman von Abbas

4
Yukarıdaki SalmanPK'nın yorumunda, bunun sığ bir klon olduğuna dikkat edin . bu yüzden asansör örneği için çalışacaktır, ancak iç içe diziler veya nesneler varsa, bunlar referans olacaktır. : /
Jesse


3
@Jordan Hudson - İkinci örnekte JSON'un çok güzel kullanımı. var newObj = JSON.parse (JSON.stringify (oldObj)); // Şimdi newObj bir klon. Tek sorun, stringify'ın özyinelemeli referans üzerinde çalışmayacağı için dikkatli olmanız gerekir.
Kfir Erez

Yanıtlar:


298

Olasılık 1

Düşük fırfırlı derin kopya:

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

Olasılık 2 (kullanımdan kaldırıldı)

Dikkat: Bu çözüm artık Node.js belgelerinde kullanımdan kaldırıldı olarak işaretlendi :

Util._extend () yöntemi hiçbir zaman dahili Node.js modüllerinin dışında kullanılmak üzere tasarlanmamıştır. Topluluk yine de buldu ve kullandı.

Kullanımdan kaldırılmıştır ve yeni kodda kullanılmamalıdır. JavaScript, Object.assign () aracılığıyla çok benzer yerleşik işlevlerle birlikte gelir.

Orijinal cevap ::

Sığ bir kopya için Düğümün yerleşik util._extend()işlevini kullanın.

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

Düğüm _extendişlevinin kaynak kodu burada: 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
Soru özellikle tekrarlayan bir klon gerektiriyordu. Bu sığ bir klon.
Benjamin Atkin

28
_*Özel bir yöntem olduğu ve güvenilmemesi gerektiği anlamına gelen bir isim değil midir?
Fluffy

7
Herhangi bir boyuttaki her JavaScript projesinin, bir veya daha fazla expand () uygulaması vardır ve Node bir istisna değildir. Node.js çekirdeği bu işlevi kapsamlı olarak kullanır. Isaacs'a alıntı yapmak için, "Yakında hiçbir yere gitmeyecek."
jimbo

2
benim için mükemmel çalıştı. Object prototype imo ile
uğraşmaktan

12
Bu YANLIŞ cevap. Düğümün belgelerine gereğince: nodejs.org/api/util.html#util_util_extend_obj yöntem iç node.js modüllerin kullanılan dışında olması amaçlanmıştır değildi. Topluluk yine de buldu ve kullandı. Kullanımdan kaldırılmıştır ve yeni kodda kullanılmamalıdır. JavaScript ile çok benzer yerleşik işlevsellik ile geliyorutil._extend() Object.assign().
Jordie

266

Object.assignBelirtilmediğine şaşırdım .

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

Varsa (örn. Babel), nesne yayma işlecini kullanabilirsiniz :

let cloned = { ... source };

1
günümü kurtardın! Teşekkürler
wzr1337 15:09

2
bu, üçüncü taraf bir kitaplığı içe aktarmak veya eksik JSON geçici çözümünü kullanmaktan çok daha iyi bir çözümdür. Teşekkürler!
Neil S

75
Bu sığ bir kopya
Jordan Davidson

14
Derin Klon için uyarı, Derin klon için hala diğer alternatifleri kullanmanız gerekir. developer.mozilla.org/tr-TR/docs/Web/JavaScript/Reference/…
gsalgadotoledo

1
Ne diyebilirim ki nesne yayma operatörü bir ES6 değil, bir aşama 3 önerisidir. yani babil ile kullanabilirsiniz ama anladığım kadarıyla kullanamazsınız. 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;
    }
});

Bu, kullanabileceğiniz bir genişletme yöntemi tanımlayacaktır. Kod bu makaleden geliyor .


Bunun nasıl çalışması gerektiğini anlamıyorum. Orijinal Nesneyi değiştirir! Bir nesnenin klonunu almak için bu işlevi nasıl kullanmam gerekir? Buraya biraz kullanım kodu ekleyebilir misiniz? Gönderinizi ve blog gönderisini okuduktan sonra, bunun bir nesneyi klonlamak için nasıl kullanıldığını hala anlayamıyorum.
Brad

3
bu gerçekten işe yarıyor mu? "if (dest içinde ad)" - özelliği yalnızca hedefte zaten varsa değiştirir. reddedilmelidir.
Mart'ta

8
Object.prototype üzerinde değişiklik yapmanın verboten olması gerekmez mi? Ayrıca bu makale bağlantısı bozuk.
Daniel Schaffer

Sadece makale bağlantısını denedim ve benim için çalışıyor. Belki denediğinizde bir ağ patlamasıydı.
Michael Dillon

Bir dizi yoruma dayanarak, cevabı nesnenin prototipine eklemeyen bir varyantı içerecek şekilde güncelledim.
Shamasis Bhattacharya

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

2
Bu zaten var olan cevapta bunu tekrarlamanın bir anlamı yoktu.
Gölge Sihirbazı Sizin İçin

@ShadowWizard bunlar farklı yöntemlerdir. Bağlantılı cevap Object.keys()nesne üzerinden yineleme yapmak için kullanılırken, bu sadece json ve nesneye geri dönüşür
mente

Bu cevap yanlış. JSON.stringify bir tarih nesnesi alır ve onu bir dizeye indirir ve daha sonra ayrıştırdıktan sonra onu bir dize olarak bırakır, böylece nesnenin durumunu başlangıçta durumdan farklı bir nesne bırakarak değiştirir.
twboc



8

Eğer "kendiniz yuvarlamak" istemiyorsanız bazı Düğüm modülleri vardır. Bu iyi görünüyor: https://www.npmjs.com/package/clone

Dairesel referanslar da dahil olmak üzere her türlü şeyi işliyor gibi görünüyor. Gönderen github sayfasından:

klonlama master'ları nesneleri, dizileri, Date nesnelerini ve RegEx nesnelerini kopyalar. Her şey özyinelemeli olarak klonlanır, böylece örneğin nesnelerdeki dizilerdeki tarihleri ​​klonlayabilirsiniz. [...] Dairesel referanslar? Evet!


7

Bu kod da işe yaramaktadır Object.create () yöntemi belirtilen prototip nesnesi ve özellikleri ile yeni bir nesne oluşturur.

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

var obj2 = Object.create(obj1);

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

obj1.x; //5

4
Bu sığ bir kopya
Radagast Brown

6

NodeJS'de bir Nesneyi klonlamanın basit ve en hızlı yolu Object.keys (obj) yöntemini kullanmaktır

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 yöntemi için JavaScript 1.8.5 gerekir; nodeJS v0.4.11 bu yöntemi destekler

ama tabii ki iç içe nesneler için yinelemeli fonks


Diğer çözüm yerel JSON (JavaScript 1.7'de uygulanmaktadır) kullanmaktır, ancak öncekinden çok daha yavaştır (~ 10 kat daha yavaş)

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

5

Github'da aşağıdakilerin daha doğrudan bir limanı olmayı amaçlayan bir proje de var jQuery.extend():

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

JQuery belgelerinden değiştirilen bir örnek :

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

Hepiniz acı çekiyorsunuz, çözüm basit.

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

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


3

Gerçek bir klon seçeneği mi arıyorsunuz?

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

Bu sayfadaki çözümü, Objectprototipe eklenmiş fonksiyonun numaralandırılamayacağı şekilde değiştirdim. İşte benim sonuç:

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

Umarım bu başka birine de yardımcı olur. Bazı uyarılar olduğunu unutmayın ... özellikle "klon" adı verilen özelliklere sahip. Bu benim için iyi çalışıyor. Yazdığım için hiç kredi almıyorum. Yine, sadece nasıl tanımlandığını değiştirdim.


Bu yanlış. Tarih türü nesnedir, bu nedenle bu kod tarihleri ​​boş nesnelerle değiştirir ... Bunu kullanmayın.
jtblin


0

Kahve betiği kullanıyorsanız, bu kadar kolay:

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

Bu derin bir klon olmasa da.



0

Düğümde bir nesnenin gerçek bir klonunu (derin kopyası) yapmanın yerleşik bir yolu yoktur. Js. Bazı zor kenar durumlarda vardır, bu yüzden kesinlikle bunun için bir kütüphane kullanmalısınız. Basit kitaplığım için böyle bir işlev yazdım . KullanabilirsinizdeepCopy yoksa, kütüphaneden başka bir şey kullanmadan (oldukça küçük) işlevi . Bu işlev, diziler, tarihler ve normal ifadeler dahil olmak üzere birden çok veri türünü kopyalamayı destekler, özyinelemeli başvuruları destekler ve ayrıca yapıcı işlevlerinin gerekli parametrelere sahip olduğu nesnelerle de çalışır.

İşte kod:

//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

En hızlı klonlayıcı, node.js'den yerel klon yöntemini açar

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

0

Başka bir çözüm, aşağıdakileri kullanarak doğrudan yeni değişkenin içine kapsüllemektir: obj1= {...obj2}


Bu sığ bir kopya
Rémi Doolaeghe

0

Bu klon kütüphanesini ayrıca derin klonlama nesneleri için de kullanabilirsiniz .

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

const clonedObject = clone(sourceObject);

-2

Nesneyi prototipleştirebilir ve her nesneyi kullanmak ve değiştirmek istediğinizde nesne örneğini çağırabilirsiniz:

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

Ayrıca nesne yapıcısına argümanlar da iletebilirsiniz

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

Umarım bu yardımcı olur.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.