Якщо я клоную масив, я використовую cloneArr = arr.slice()
Я хочу знати, як клонувати об'єкт у nodejs.
Відповіді:
Для утиліт та класів, де немає необхідності вичавлювати кожну краплю продуктивності, я часто обманюю і просто використовую JSON для глибокої копії:
function clone(a) {
return JSON.parse(JSON.stringify(a));
}
Це не єдина відповідь чи найелегантніша відповідь; всі інші відповіді слід розглядати як вузькі місця у виробництві. Однак це швидке та брудне рішення, досить ефективне та корисне в більшості ситуацій, коли я клоную простий хеш властивостей.
newObj = obj.clone(args...);
Object.assign не згадувалося в жодній із наведених вище відповідей.
let cloned = Object.assign({}, source);
Якщо ви використовуєте ES6, ви можете використовувати оператор поширення:
let cloned = { ... source };
Посилання: 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);
Існує кілька модулів Node, якщо ви не хочете "прокручувати свої". Це добре виглядає: https://www.npmjs.com/package/clone
Схоже, він обробляє будь-які речі, включаючи циркулярні посилання. Зі сторінки github :
клонування майстрів клонування об'єктів, масивів, об'єктів дати та об'єктів RegEx. Все клонується рекурсивно, так що ви можете клонувати дати в масивах в об'єктах, наприклад. [...] Циркулярні посилання? Так!
Важко зробити загальну, але корисну операцію клонування, оскільки те, що слід клонувати рекурсивно, а що слід просто скопіювати, залежить від того, як повинен працювати конкретний об’єкт.
Щось, що може бути корисним, це
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;
}
У цьому коді логіка така
nullабо undefinedпросто повернути те саме (потрібен особливий випадок, оскільки помилка спроби з’ясувати, чи є cloneметод)clone метод? то використовуйте цеЦя функція клонування повинна дозволяти легко реалізовувати власні методи клонування ... наприклад
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);
};
Коли в об’єкті ви знаєте, що правильна операція клонування для певного масиву - це лише неглибока копія, тоді ви можете зателефонувати values.slice()замість clone(values).
Наприклад, у наведеному вище коді я чітко вимагаю, щоб клонування об'єкта багатокутника клонувало точки, але поділяло той самий об'єкт стилю. Якщо я хочу замість цього клонувати об'єкт стилю, я можу просто передати його clone(this.style).
.cloneсамі реалізовувати метод. Це найкращий спосіб боротьби з клонуванням об’єктів.
if (x.clone)повинно бутиif (typeof x.clone === 'function')
Не існує власного методу клонування об'єктів. Підкреслюйте знаряддя, _.cloneщо представляють собою неглибокий клон.
_.clone = function(obj) {
return _.isArray(obj) ? obj.slice() : _.extend({}, obj);
};
Він або нарізає його, або розширює.
Ось _.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;
};
Розширення просто перебирає всі елементи та створює новий об’єкт з елементами в ньому.
Ви можете розгорнути свою власну наївну реалізацію, якщо хочете
function clone(o) {
var ret = {};
Object.keys(o).forEach(function (val) {
ret[val] = o[val];
});
return ret;
}
Є вагомі причини уникати глибокого клонування, оскільки закриття не можна клонувати.
Я особисто задав питання, deep cloning objects beforeі висновок, до якого я прийшов, полягає в тому, що ти просто не робиш цього.
Моя рекомендація - використовувати underscoreі це _.cloneметод для неглибоких клонів
Для дрібної копії мені подобається використовувати шаблон зменшення (зазвичай у модулі або подібному), наприклад:
var newObject = Object.keys(original).reduce(function (obj, item) {
obj[item] = original[item];
return obj;
},{});
Ось jsperf для декількох варіантів: http://jsperf.com/shallow-copying
Старе питання, але є більш елегантна відповідь, ніж те, що пропонувалось дотепер; використовуйте вбудований utils._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 } }
Зверніть увагу на використання першого параметра з порожнім об’єктом {} - це говорить про те, що скопійовані об’єкти потрібно скопіювати в новий об’єкт. Якщо ви використовуєте існуючий об'єкт як перший параметр, тоді другий (і всі наступні) параметри будуть скопійовані в глибину через першу змінну параметра.
Використовуючи наведені вище приклади змінних, ви також можете зробити це:
var anotherMergeVar = { foo: "bar" };
extend(copiedObject, { anotherParam: 'value' }, anotherMergeVar);
console.log(copiedObject);
// outputs:
// { test: 12345, nested: { val: 6789 }, anotherParam: 'value', foo: 'bar' }
Дуже зручна утиліта, особливо там, де я звик розширювати свої функції в AngularJS та jQuery.
Сподіваюся, це допомагає комусь іншому; перезаписування посилань на об’єкти - це біда, і це вирішує це щоразу!
Залежно від того, що ви хочете зробити з вашим клонованим об'єктом, ви можете використовувати прототипний механізм успадкування javascript і досягти дещо клонованого об'єкта за допомогою:
var clonedObject = Object.create(originalObject);
Тільки пам’ятайте, що це не повноцінний клон - на краще чи гірше.
Хороша річ у тому, що ви насправді не дублювали об’єкт, тому обсяг пам'яті буде низьким.
Деякі хитрі речі, які слід пам’ятати щодо цього методу, полягає в тому, що ітерація властивостей, визначених у ланцюжку прототипів, іноді працює дещо по-іншому, і той факт, що будь-які зміни у вихідному об’єкті також вплинуть на клонований об’єкт, якщо ця властивість також не встановлена сама .
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";Звичайно, слід знати, що зміни в оригінальному об'єкті будуть відображені в "клоні", а зміни в "клоні" не будуть відображені в оригінальному об'єкті - але я б не називав це небезпечним - все залежить від того, що ви хочете зробити зі своїм клоном
Я реалізував повну глибоку копію. Я вважаю, що це найкращий вибір для загального методу клонування, але він не обробляє циклічні посилання.
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
Цей код копіює об'єкти з їх прототипами, а також копіює функції (може бути корисним для когось).
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;
}
За допомогою цієї копії я не можу знайти жодної різниці між оригіналом та скопійованою, за винятком випадків, коли оригінал використовував закриття для його побудови, тому я вважаю, що це хороша реалізація.
Сподіваюся, це допоможе
Об'єкти та масиви в JavaScript використовують виклик за посиланням, якщо ви оновите скопійоване значення, це може відобразитися на вихідному об'єкті. Щоб запобігти цьому, ви можете глибоко клонувати об'єкт, запобігти передачі посилання, використовуючи команду запуску методу бібліотеки lodash cloneDeep
npm встановити lodash
const ld = require('lodash')
const objectToCopy = {name: "john", age: 24}
const clonedObject = ld.cloneDeep(objectToCopy)