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


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

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

11 74

11 ответов:

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

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

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

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

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

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

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

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

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 который является мелким клоном.

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

Extend просто перебирает все элементы и создает новый объект с элементами в нем.

вы можете самостоятельно готовить, если вы хотите

function clone(o) {
  var ret = {};
  Object.keys(o).forEach(function (val) {
    ret[val] = o[val];
  });
  return ret;
}

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

Я лично задал вопрос о deep cloning objects before и я пришел к выводу, что вы просто не делаете этого.

моя рекомендация-использовать underscore и _.clone метод для мелких клонов

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

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

обратите внимание на использование первого параметра с пустым объектом {} - это говорит extend, что скопированные объекты должны быть скопированы в новый объект. Если вы используете существующий объект в качестве первого параметра, то второй (и все последующие) параметры будут глубоко скопированы по первой переменной параметра.

на примере переменные выше, вы также можете сделать это:

var anotherMergeVar = { foo: "bar" };

extend(copiedObject, { anotherParam: 'value' }, anotherMergeVar);

console.log(copiedObject);

// outputs:
// { test: 12345, nested: { val: 6789 }, anotherParam: 'value', foo: 'bar' }

очень удобная утилита, особенно там, где я привык расширяться в AngularJS и jQuery.

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

можно использовать лодашь как хорошо. Он имеет клон и 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]);

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

var clonedObject = Object.create(originalObject);

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

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

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

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

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

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

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

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

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

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

print ( arr_2 ); 

arr=arr.slice (0);

print ( arr ); 

arr[1]=9999; 

print ( arr_2 );