three propagacion operator operador dots javascript ecmascript-6 redux spread-syntax

javascript - propagacion - rest operator



Copia profunda en ES6 utilizando la sintaxis de propagaciĆ³n (7)

Estoy tratando de crear un método de mapa de copia profunda para mi proyecto Redux que funcione con objetos en lugar de matrices. Leí que en Redux cada estado no debería cambiar nada en los estados anteriores.

export const mapCopy = (object, callback) => { return Object.keys(object).reduce(function (output, key) { output[key] = callback.call(this, {...object[key]}); return output; }, {}); }

Funciona:

return mapCopy(state, e => { if (e.id === action.id) { e.title = ''new item''; } return e; })

Sin embargo, no copia en profundidad los elementos internos, así que necesito modificarlo para:

export const mapCopy = (object, callback) => { return Object.keys(object).reduce(function (output, key) { let newObject = {...object[key]}; newObject.style = {...newObject.style}; newObject.data = {...newObject.data}; output[key] = callback.call(this, newObject); return output; }, {}); }

Esto es menos elegante ya que requiere saber qué objetos se pasan. ¿Hay alguna manera en ES6 de usar la sintaxis de propagación para copiar en profundidad un objeto?


A menudo uso esto:

function deepCopy(obj) { if(typeof obj !== ''object'' || obj === null) { return obj; } if(obj instanceof Date) { return new Date(obj.getTime()); } if(obj instanceof Array) { return obj.reduce((arr, item, i) => { arr[i] = deepCopy(item); return arr; }, []); } if(obj instanceof Object) { return Object.keys(obj).reduce((newObj, key) => { newObj[key] = deepCopy(obj[key]); return newObj; }, {}) } }


En su lugar, use esto para una copia profunda

var newObject = JSON.parse(JSON.stringify(oldObject))

var oldObject = { name: ''A'', address: { street: ''Station Road'', city: ''Pune'' } } var newObject = JSON.parse(JSON.stringify(oldObject)); newObject.address.city = ''Delhi''; console.log(''newObject''); console.log(newObject); console.log(''oldObject''); console.log(oldObject);


No existe tal funcionalidad integrada en ES6. Creo que tienes un par de opciones dependiendo de lo que quieras hacer.

Si realmente quieres copiar en profundidad:

  1. Usa una biblioteca. Por ejemplo, lodash tiene un método cloneDeep .
  2. Implemente su propia función de clonación.

Solución alternativa a su problema específico (sin copia profunda)

Sin embargo, creo que si estás dispuesto a cambiar un par de cosas, puedes ahorrarte algo de trabajo. Supongo que controlas todos los sitios de llamadas según tu función.

  1. Especifique que todas las devoluciones de llamada pasadas a mapCopy deben devolver nuevos objetos en lugar de mutar el objeto existente. Por ejemplo:

    mapCopy(state, e => { if (e.id === action.id) { return Object.assign({}, e, { title: ''new item'' }); } else { return e; } });

    Esto utiliza Object.assign para crear un nuevo objeto, establece las propiedades de e en ese nuevo objeto, luego establece un nuevo título en ese nuevo objeto. Esto significa que nunca mutará objetos existentes y solo creará nuevos cuando sea necesario.

  2. mapCopy puede ser realmente simple ahora:

    export const mapCopy = (object, callback) => { return Object.keys(object).reduce(function (output, key) { output[key] = callback.call(this, object[key]); return output; }, {}); }

Esencialmente, mapCopy confía en que sus llamantes hagan lo correcto. Es por eso que dije que esto supone que controlas todos los sitios de llamadas.


De MDN

Nota: La sintaxis extendida efectivamente va un nivel más profundo al copiar una matriz. Por lo tanto, puede no ser adecuado para copiar matrices multidimensionales como se muestra en el siguiente ejemplo (es lo mismo con Object.assign () y sintaxis extendida).

Personalmente, sugiero usar la función cloneDeep de Lodash para la clonación de objetos / matrices de varios niveles.

Aquí hay un ejemplo de trabajo:

const arr1 = [{ ''a'': 1 }]; const arr2 = [...arr1]; const arr3 = _.clone(arr1); const arr4 = arr1.slice(); const arr5 = _.cloneDeep(arr1); const arr6 = [...{...arr1}]; // a bit ugly syntax but it is working! // first level console.log(arr1 === arr2); // false console.log(arr1 === arr3); // false console.log(arr1 === arr4); // false console.log(arr1 === arr5); // false console.log(arr1 === arr6); // false // second level console.log(arr1[0] === arr2[0]); // true console.log(arr1[0] === arr3[0]); // true console.log(arr1[0] === arr4[0]); // true console.log(arr1[0] === arr5[0]); // false console.log(arr1[0] === arr6[0]); // false

<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.js"></script>


// use: clone( <thing to copy> ) returns <new copy> // untested use at own risk function clone(o, m){ // return non object values if(''object'' !==typeof o) return o // m: a map of old refs to new object refs to stop recursion if(''object'' !==typeof m || null ===m) m =new WeakMap() var n =m.get(o) if(''undefined'' !==typeof n) return n // shallow/leaf clone object var c =Object.getPrototypeOf(o).constructor // TODO: specialize copies for expected built in types i.e. Date etc switch(c) { // shouldn''t be copied, keep reference case Boolean: case Error: case Function: case Number: case Promise: case String: case Symbol: case WeakMap: case WeakSet: n =o break; // array like/collection objects case Array: m.set(o, n =o.slice(0)) // recursive copy for child objects n.forEach(function(v,i){ if(''object'' ===typeof v) n[i] =clone(v, m) }); break; case ArrayBuffer: m.set(o, n =o.slice(0)) break; case DataView: m.set(o, n =new (c)(clone(o.buffer, m), o.byteOffset, o.byteLength)) break; case Map: case Set: m.set(o, n =new (c)(clone(Array.from(o.entries()), m))) break; case Int8Array: case Uint8Array: case Uint8ClampedArray: case Int16Array: case Uint16Array: case Int32Array: case Uint32Array: case Float32Array: case Float64Array: m.set(o, n =new (c)(clone(o.buffer, m), o.byteOffset, o.length)) break; // use built in copy constructor case Date: case RegExp: m.set(o, n =new (c)(o)) break; // fallback generic object copy default: m.set(o, n =Object.assign(new (c)(), o)) // recursive copy for child objects for(c in n) if(''object'' ===typeof n[c]) n[c] =clone(n[c], m) } return n }


const cloneData = (dataArray) => { newData= [] dataArray.forEach((value) => { newData.push({...value}) }) return newData }

  • a = [{nombre: "siva"}, {nombre: "siva1"}];
  • b = myCopy (a)
  • b === a // falso`

function deepclone(obj) { let newObj = {}; if (typeof obj === ''object'') { for (let key in obj) { let property = obj[key], type = typeof property; switch (type) { case ''object'': if( Object.prototype.toString.call( property ) === ''[object Array]'' ) { newObj[key] = []; for (let item of property) { newObj[key].push(this.deepclone(item)) } } else { newObj[key] = deepclone(property); } break; default: newObj[key] = property; break; } } return newObj } else { return obj; } }