Jeśli sklonuję tablicę, używam cloneArr = arr.slice()
Chcę wiedzieć, jak sklonować obiekt w nodejs.
Odpowiedzi:
W przypadku narzędzi i klas, w których nie ma potrzeby wyciskania każdej kropli wydajności, często oszukuję i po prostu używam JSON do wykonania głębokiej kopii:
function clone(a) {
return JSON.parse(JSON.stringify(a));
}
To nie jest jedyna odpowiedź ani najbardziej elegancka odpowiedź; wszystkie pozostałe odpowiedzi należy wziąć pod uwagę w przypadku wąskich gardeł produkcyjnych. Jest to jednak szybkie i brudne rozwiązanie, dość skuteczne i przydatne w większości sytuacji, w których sklonowałbym prosty skrót właściwości.
newObj = obj.clone(args...);
W żadnej z powyższych odpowiedzi nie wspomniano o Object. assign.
let cloned = Object.assign({}, source);
Jeśli korzystasz z ES6, możesz użyć operatora spreadu:
let cloned = { ... source };
Źródła: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/ assign
let a = {x:1}; let b = Object.assign({}, a); a.x = 2; a.y = 1; console.log(a, b);
Istnieje kilka modułów Node, jeśli nie chcesz „tworzyć własnych”. Ten wygląda dobrze: https://www.npmjs.com/package/clone
Wygląda na to, że obsługuje różne rzeczy, w tym odwołania cykliczne. Ze strony github :
clone masters klonuje obiekty, tablice, obiekty Date i obiekty RegEx. Wszystko jest klonowane rekurencyjnie, dzięki czemu można na przykład klonować daty w tablicach w obiektach. [...] Okólnik? Tak!
Trudno jest wykonać ogólną, ale użyteczną operację klonowania, ponieważ to, co powinno być klonowane rekurencyjnie, a co powinno zostać skopiowane, zależy od tego, jak powinien działać określony obiekt.
Coś, co może być przydatne, to
function clone(x)
{
if (x === null || x === undefined)
return x;
if (typeof x.clone === "function")
return x.clone();
if (x.constructor == Array)
{
var r = [];
for (var i=0,n=x.length; i<n; i++)
r.push(clone(x[i]));
return r;
}
return x;
}
W tym kodzie logika jest
nulllub undefinedpo prostu zwróć to samo (potrzebny jest specjalny przypadek, ponieważ próba sprawdzenia, czy clonemetoda jest obecna, jest błędem )clonemetodę? następnie użyj tegoTa funkcja klonowania powinna umożliwiać łatwe wdrażanie niestandardowych metod klonowania ... na przykład
function Point(x, y)
{
this.x = x;
this.y = y;
...
}
Point.prototype.clone = function()
{
return new Point(this.x, this.y);
};
function Polygon(points, style)
{
this.points = points;
this.style = style;
...
}
Polygon.prototype.clone = function()
{
return new Polygon(clone(this.points),
this.style);
};
Kiedy w obiekcie wiesz, że poprawna operacja klonowania dla określonej tablicy to tylko płytka kopia, możesz wywołać values.slice()zamiast clone(values).
Na przykład w powyższym kodzie wyraźnie wymagam, aby klonowanie obiektu wielokąta sklonowało punkty, ale będzie miało ten sam obiekt stylu. Jeśli zamiast tego chcę sklonować również obiekt stylu, mogę po prostu przejść clone(this.style).
.clonesame zaimplementować metodę. To najlepszy sposób radzenia sobie z klonowaniem obiektów.
if (x.clone)powinno byćif (typeof x.clone === 'function')
Nie ma natywnej metody klonowania obiektów. Podkreślone narzędzia, _.clonektóre są płytkim klonem.
_.clone = function(obj) {
return _.isArray(obj) ? obj.slice() : _.extend({}, obj);
};
Tnie go lub wydłuża.
Tutaj jest _.extend
// extend the obj (first parameter)
_.extend = function(obj) {
// for each other parameter
each(slice.call(arguments, 1), function(source) {
// loop through all properties of the other objects
for (var prop in source) {
// if the property is not undefined then add it to the object.
if (source[prop] !== void 0) obj[prop] = source[prop];
}
});
// return the object (first parameter)
return obj;
};
Rozszerz po prostu iteruje po wszystkich elementach i tworzy nowy obiekt z zawartymi w nim elementami.
Jeśli chcesz, możesz wdrożyć własną naiwną implementację
function clone(o) {
var ret = {};
Object.keys(o).forEach(function (val) {
ret[val] = o[val];
});
return ret;
}
Istnieją dobre powody, aby unikać głębokiego klonowania, ponieważ nie można klonować zamknięć.
Osobiście zadałem pytanie deep cloning objects beforei doszedłem do wniosku, że po prostu tego nie robisz.
Moją rekomendacją jest użycie underscorei jest to _.clonemetoda na płytkie klony
W przypadku płytkiej kopii lubię używać wzoru redukcji (zwykle w module lub takim), na przykład:
var newObject = Object.keys(original).reduce(function (obj, item) {
obj[item] = original[item];
return obj;
},{});
Oto plik jsperf dla kilku opcji: http://jsperf.com/shallow-copying
Stare pytanie, ale istnieje bardziej elegancka odpowiedź niż to, co sugerowano do tej pory; użyj wbudowanych narzędzi ._extend:
var extend = require("util")._extend;
var varToCopy = { test: 12345, nested: { val: 6789 } };
var copiedObject = extend({}, varToCopy);
console.log(copiedObject);
// outputs:
// { test: 12345, nested: { val: 6789 } }
Zwróć uwagę na użycie pierwszego parametru z pustym obiektem {} - mówi to rozszerzeniu, że skopiowany obiekt (y) muszą zostać skopiowane do nowego obiektu. Jeśli użyjesz istniejącego obiektu jako pierwszego parametru, to drugi (i wszystkie kolejne) parametry zostaną głęboko scalone i skopiowane na pierwszą zmienną parametru.
Korzystając z przykładowych zmiennych powyżej, możesz również zrobić to:
var anotherMergeVar = { foo: "bar" };
extend(copiedObject, { anotherParam: 'value' }, anotherMergeVar);
console.log(copiedObject);
// outputs:
// { test: 12345, nested: { val: 6789 }, anotherParam: 'value', foo: 'bar' }
Bardzo przydatne narzędzie, szczególnie tam, gdzie jestem przyzwyczajony do rozszerzania w AngularJS i jQuery.
Mam nadzieję, że to pomoże komuś innemu; nadpisywanie odniesień do obiektów jest nieszczęściem, a to rozwiązuje je za każdym razem!
W zależności od tego, co chcesz zrobić ze sklonowanym obiektem, możesz wykorzystać prototypowy mechanizm dziedziczenia javascript i uzyskać sklonowany obiekt poprzez:
var clonedObject = Object.create(originalObject);
Pamiętaj tylko, że to nie jest pełny klon - na dobre lub na złe.
Dobrą rzeczą jest to, że w rzeczywistości nie zduplikowałeś obiektu, więc zużycie pamięci będzie niskie.
Niektóre trudne rzeczy do zapamiętania w tej metodzie są takie, że iteracja właściwości zdefiniowanych w łańcuchu prototypów czasami działa nieco inaczej oraz fakt, że wszelkie zmiany w oryginalnym obiekcie wpłyną również na sklonowany obiekt, chyba że ta właściwość została również ustawiona na siebie .
var a = {foo: "bar"}, b = Object.create(a); a.foo = "broken"; console.log(b.foo); // "broken";
b.foo = "working"; console.log(a.foo); // still "broken";Trzeba oczywiście mieć świadomość, że zmiany w oryginalnym obiekcie zostaną odzwierciedlone w „klonie”, a zmiany w „klonie” nie zostaną odzwierciedlone w oryginalnym obiekcie - ale nie nazwałbym tego niebezpiecznym - wszystko zależy od tego, co chcesz zrobić ze swoim klonem
Zaimplementowałem pełną głęboką kopię. Uważam, że jest to najlepszy wybór dla ogólnej metody klonowania, ale nie obsługuje ona odwołań cyklicznych.
parent = {'prop_chain':3}
obj = Object.create(parent)
obj.a=0; obj.b=1; obj.c=2;
obj2 = copy(obj)
console.log(obj, obj.prop_chain)
// '{'a':0, 'b':1, 'c':2} 3
console.log(obj2, obj2.prop_chain)
// '{'a':0, 'b':1, 'c':2} 3
parent.prop_chain=4
obj2.a = 15
console.log(obj, obj.prop_chain)
// '{'a':0, 'b':1, 'c':2} 4
console.log(obj2, obj2.prop_chain)
// '{'a':15, 'b':1, 'c':2} 4
Ten kod kopiuje obiekty wraz z ich prototypami, kopiuje również funkcje (może się to komuś przydać).
function copy(obj) {
// (F.prototype will hold the object prototype chain)
function F() {}
var newObj;
if(typeof obj.clone === 'function')
return obj.clone()
// To copy something that is not an object, just return it:
if(typeof obj !== 'object' && typeof obj !== 'function' || obj == null)
return obj;
if(typeof obj === 'object') {
// Copy the prototype:
newObj = {}
var proto = Object.getPrototypeOf(obj)
Object.setPrototypeOf(newObj, proto)
} else {
// If the object is a function the function evaluate it:
var aux
newObj = eval('aux='+obj.toString())
// And copy the prototype:
newObj.prototype = obj.prototype
}
// Copy the object normal properties with a deep copy:
for(var i in obj) {
if(obj.hasOwnProperty(i)) {
if(typeof obj[i] !== 'object')
newObj[i] = obj[i]
else
newObj[i] = copy(obj[i])
}
}
return newObj;
}
W przypadku tej kopii nie mogę znaleźć żadnej różnicy między oryginałem a skopiowanym, z wyjątkiem tego, czy oryginał używał zamknięć w swojej konstrukcji, więc myślę, że jest to dobra implementacja.
Mam nadzieję, że to pomoże
Obiekty i tablice w JavaScript używają wywołania przez odniesienie, jeśli zaktualizujesz skopiowaną wartość, może to odzwierciedlać oryginalny obiekt. Aby temu zapobiec, możesz głęboko sklonować obiekt, aby zapobiec przekazaniu odniesienia, używając lodash biblioteki cloneDeep metoda uruchom polecenie
npm zainstaluj lodash
const ld = require('lodash')
const objectToCopy = {name: "john", age: 24}
const clonedObject = ld.cloneDeep(objectToCopy)