Nodejs: как клонировать объект

Если я клонирую массив, я использую cloneArr = arr.slice()

Я хочу знать, как клонировать объект в nodejs.

77 голосов | спросил guilin 桂林 22 Maypm11 2011, 19:53:46

10 ответов


0

Для утилит и классов, где нет необходимости сжимать каждое падение производительности, я часто обманываю и просто использую JSON для глубокого копирования:

function clone(a) {
   return JSON.parse(JSON.stringify(a));
}

Это не единственный или самый элегантный ответ; все остальные ответы должны быть рассмотрены для узких мест производства. Однако это быстрое и грязное решение, довольно эффективное и полезное в большинстве ситуаций, когда я бы клонировал простой хэш свойств.

ответил Kato 10 +04002012-10-10T23:21:16+04:00312012bEurope/MoscowWed, 10 Oct 2012 23:21:16 +0400 2012, 23:21:16
0

Object.assign не упоминался ни в одном из приведенных выше ответов.

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

Если вы используете ES6, вы можете использовать оператор распространения:

let cloned = { ... source };

Ссылка: https: //разработчик. mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign

ответил Sam G 1 J0000006Europe/Moscow 2017, 09:14:16
0

Есть несколько Node-модулей, если вы не хотите «свернуть свои собственные». Это выглядит хорошо: https://www.npmjs.com/package/clone

Похоже, он обрабатывает все виды вещей, включая циклические ссылки. Со страницы github :

  

клон мастеров клонирования объектов, массивов, объектов Date и RegEx   объекты. Все клонируется рекурсивно, так что вы можете клонировать даты   в массивах в объектах, например. [...] Циркулярные ссылки? Да!

ответил Clint Harris 1 ThuEurope/Moscow2011-12-01T19:02:40+04:00Europe/Moscow12bEurope/MoscowThu, 01 Dec 2011 19:02:40 +0400 2011, 19:02:40
0

Трудно сделать общую, но полезную операцию клонирования, потому что то, что должно быть рекурсивно клонировано, а что нужно просто скопировать, зависит от того, как должен работать конкретный объект.

Что-то, что может быть полезно, это

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).

ответил 6502 22 Maypm11 2011, 20:28:25
0

Для мелкой копии мне нравится использовать шаблон сокращения (обычно в модуле или около того), например так:

var newObject = Object.keys(original).reduce(function (obj, item) {
    obj[item] = original[item];
    return obj;
},{});

Вот jsperf для нескольких вариантов: http://jsperf.com/shallow-copying

ответил Olli K 9 PMpWed, 09 Apr 2014 21:31:50 +040031Wednesday 2014, 21:31:50
0

Старый вопрос, но есть более элегантный ответ, чем предлагалось до сих пор; используйте встроенный 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.

Надеюсь, это поможет кому-то еще; Перезапись ссылки на объект - это беда, и это решает ее каждый раз!

ответил Scott Byers 7 J000000Thursday16 2016, 17:37:14
0

Вы также можете использовать lodash . У него есть клон и методы cloneDeep .

var _= require('lodash');

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

var shallow = _.clone(objects);
console.log(shallow[0] === objects[0]);
// => true

var deep = _.cloneDeep(objects);
console.log(deep[0] === objects[0]);
ответил Michal 7 MarpmTue, 07 Mar 2017 20:35:01 +03002017-03-07T20:35:01+03:0008 2017, 20:35:01
0

В зависимости от того, что вы хотите сделать со своим клонированным объектом, вы можете использовать механизм наследования прототипов javascript и получить несколько клонированный объект с помощью:

var clonedObject = Object.create(originalObject);

Просто помните, что это не полный клон - к лучшему или к худшему.

Хорошо, что вы на самом деле не дублировали объект, поэтому объем памяти будет низким.

Некоторые хитрости, которые следует помнить об этом методе, заключаются в том, что итерация свойств, определенных в цепочке прототипов, иногда работает немного по-другому, и тот факт, что любые изменения исходного объекта также будут влиять на клонированный объект, если только это свойство не было установлено на себя тоже.

ответил VoxPelli 28 J0000006Europe/Moscow 2013, 01:01:51
0

Я реализовал полную глубокую копию. Я считаю, что это лучший выбор для универсального метода клонирования, но он не обрабатывает циклические ссылки.

Пример использования:

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

С этой копией я не могу найти никакой разницы между оригиналом и копией, за исключением того, что оригинал использовал замыкания в своей конструкции, поэтому я думаю, что это хорошая реализация.

Надеюсь, это поможет

ответил VinGarcia 5 PM00000090000000731 2015, 21:50:07
0

для массива можно использовать

var arr = [1,2,3]; 
var arr_2 = arr ; 

print ( arr_2 ); 

обр = arr.slice (0);

print ( arr ); 

arr[1]=9999; 

print ( arr_2 ); 
ответил tlqtangok 12 MarpmSun, 12 Mar 2017 15:53:02 +03002017-03-12T15:53:02+03:0003 2017, 15:53:02

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132