Pregunta Nodejs: cómo clonar un objeto


Si clono una matriz, uso cloneArr = arr.slice()

Quiero saber cómo clonar un objeto en nodejs.


73
2018-05-22 15:53


origen


Respuestas:


Para utilidades y clases donde no hay necesidad de exprimir cada gota de rendimiento, a menudo hago trampa y solo uso JSON para realizar una copia profunda:

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

Esta no es la única respuesta o la respuesta más elegante; todas las demás respuestas deben considerarse para los cuellos de botella de producción. Sin embargo, esta es una solución rápida y sucia, bastante efectiva y útil en la mayoría de las situaciones en las que clonaría un simple hash de propiedades.


137
2017-10-10 19:21



Object.assign no se ha mencionado en ninguna de las respuestas anteriores.

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

Si usa ES6, puede usar el operador de propagación:

let cloned = { ... source };

Referencia: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign


20
2018-06-01 06:14



Hay algunos módulos de nodo por ahí si no desea "rodar el suyo". Este se ve bien: https://www.npmjs.com/package/clone

Parece que maneja todo tipo de cosas, incluidas referencias circulares. Desde el github página:

Maestros de clonación, clonación de objetos, matrices, objetos Date y RegEx   objetos. Todo se clona recursivamente, para que pueda clonar las fechas   en arreglos en objetos, por ejemplo. [...] ¿Referencias circulares? ¡Sí!


19
2017-12-01 15:02



Es difícil hacer una operación de clonación genérica pero útil porque lo que se debe clonar recursivamente y lo que se debe copiar depende de cómo se supone que debe funcionar el objeto específico.

Algo que puede ser útil es

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

En este código, la lógica es

  • en caso de null o undefined simplemente devuelva lo mismo (se necesita el caso especial porque es un error intentar ver si clone método está presente)
  • el objeto tiene un clone método? luego usa eso
  • es el objeto una matriz? a continuación, realice una operación de clonación recursiva
  • de lo contrario, devuelva el mismo valor

Esta función de clonación debería permitir la implementación de métodos de clonación personalizados fácilmente ... por ejemplo

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

Cuando en el objeto sabe que una operación de clonación correcta para una matriz específica es solo una copia superficial, puede llamar values.slice() en lugar de clone(values).

Por ejemplo, en el código anterior, exijo explícitamente que una clonación de un objeto polígono clonará los puntos, pero compartirá el mismo objeto de estilo. Si también quiero clonar el objeto de estilo, puedo pasar clone(this.style).


10
2018-05-22 16:28



No hay un método nativo para clonar objetos. Underscore implementa _.clone que es un clon superficial

_.clone = function(obj) {
  return _.isArray(obj) ? obj.slice() : _.extend({}, obj);
};

Lo corta o lo extiende.

Aquí está _.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;
};

Extender simplemente itera a través de todos los elementos y crea un nuevo objeto con los elementos que contiene.

Puede implementar su propia implementación ingenua si lo desea

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

Hay buenas razones para evitar la clonación profunda porque los cierres no se pueden clonar.

Personalmente, he hecho una pregunta sobre deep cloning objects before y la conclusión a la que llegué es que simplemente no lo haces.

Mi recomendación es usar underscore y es _.clone método para clones superficiales


9
2018-05-22 15:57



Para una copia poco profunda, me gusta usar el patrón de reducción (generalmente en un módulo o similar), así:

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

Aquí hay un jsperf para un par de opciones: http://jsperf.com/shallow-copying


9
2018-04-09 17:31



Una vieja pregunta, pero hay una respuesta más elegante que la sugerida hasta ahora; use las utilidades incorporadas. extienda

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

Tenga en cuenta el uso del primer parámetro con un objeto vacío {} - esto le dice a extender que los objetos copiados deben ser copiados a un nuevo objeto. Si utiliza un objeto existente como primer parámetro, entonces el segundo (y todos los posteriores) se copiarán profundamente en la primera variable de parámetro.

Usando las variables de ejemplo anteriores, también puede hacer esto:

var anotherMergeVar = { foo: "bar" };

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

console.log(copiedObject);

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

Utilidad muy útil, especialmente cuando estoy acostumbrado a extender en AngularJS y jQuery.

Espero que esto ayude a alguien más; las sobreescrituras de referencia de objetos son una miseria, ¡y esto lo resuelve todo el tiempo!


6
2017-07-07 14:37



Puedes usar lodash también. Tiene un clon y cloneDeep métodos.

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

5
2018-03-07 17:35



Dependiendo de lo que quiera hacer con su objeto clonado, puede utilizar el mecanismo de herencia prototípico de javascript y lograr un objeto clonado en cierta medida a través de:

var clonedObject = Object.create(originalObject);

Solo recuerde que este no es un clon completo, para bien o para mal.

Algo bueno de eso es que en realidad no ha duplicado el objeto, por lo que la huella de memoria será baja.

Sin embargo, algunas cosas difíciles de recordar acerca de este método es que la iteración de propiedades definidas en la cadena de prototipos a veces funciona un poco diferente y el hecho de que cualquier cambio en el objeto original afectará también al objeto clonado, a menos que esa propiedad también se haya establecido en sí misma. .


2
2018-06-27 21:01



Implementé una copia completa. Creo que es la mejor opción para un método de clonación genérico, pero no maneja referencias cíclicas.

Ejemplo de uso:

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

El código en sí:

Este código copia objetos con sus prototipos, también copia funciones (puede ser útil para alguien).

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

Con esta copia no puedo encontrar ninguna diferencia entre el original y el copiado, excepto si el original utilizó cierres en su construcción, por lo que creo que es una buena implementación.

Espero que ayude


1
2017-08-05 18:50