¿Es posible desestructurar sobre un objeto existente? (Javascript ES6)

135

Por ejemplo si tengo dos objetos:

var foo = {
  x: "bar",
  y: "baz"
}

y

var oof = {}

y quería transferir los valores x e y de foo a oof. ¿Hay alguna manera de hacerlo usando la sintaxis de desestructuración es6?

quizás algo como:

oof{x,y} = foo
majorBummer
fuente
10
Si desea copiar todas las propiedadesObject.assign(oof, foo)
elclanrs
Muchos ejemplos de destrucción aquí en MDN , pero no veo el que me preguntas.
jfriend00
Hmm, tampoco pude encontrar uno ..
majorBummer
Vea mi respuesta a continuación para una solución de dos líneas sinObject.assign
Zfalen

Respuestas:

115

Si bien feo y un poco repetitivo, puedes hacer

({x: oof.x, y: oof.y} = foo);

que leerá los dos valores del fooobjeto y los escribirá en sus ubicaciones respectivas en el oofobjeto.

Personalmente prefiero leer

oof.x = foo.x;
oof.y = foo.y;

o

['x', 'y'].forEach(prop => oof[prop] = foo[prop]);

aunque.

loganfsmyth
fuente
2
La alternativa ['x', 'y']. ForEach (prop => oof [prop] = foo [prop]); como veo, es el único SECO (no te repitas), hasta ahora. "DRY" sería realmente útil en el caso de que se asignen varias teclas. Solo necesitaría actualizar un lugar. Tal vez yo estoy equivocado. ¡Gracias de cualquier manera!
Vladimir Brasil
1
El tercer ejemplo es DRY, pero debe usar cadenas como claves, lo que normalmente hace JavaScript implícitamente. No estoy convencido de que eso sea menos molesto que: const {x, y} = foo; const oof = {x, y};
Jeff Lowery
¿Alguien puede mostrarme en jsfiddle dónde funciona la primera sugerencia? No funciona aquí en Chrome: jsfiddle.net/7mh399ow
techguy2000
@ techguy2000 Olvidó el punto y coma después var oof = {};.
loganfsmyth
En el primer código, ¿no debería ser ({x: oof.x, y: oof.y} = foo)? Creo que has puesto un f extra en oof .
Sornii
38

No, la desestructuración no admite expresiones de miembros en shorthands, sino solo nombres de propiedad simples en el momento actual. Se ha hablado de eso en esdiscuss, pero ninguna propuesta llegará a ES6.

Object.assignSin embargo, es posible que pueda usarlo : si no necesita todas las propiedades propias, aún puede hacerlo

var foo = …,
    oof = {};
{
    let {x, y} = foo;
    Object.assign(oof, {x, y})
}
Bergi
fuente
3
@loganfsmyth, su ejemplo no funciona para mí al menos en mis pruebas con el nodo 4.2.2. con --harmony_destructuringhabilitado. Veo "SyntaxError: token inesperado".
jpierson
@loganfsmyth debe enviar una respuesta adecuada, ya que este es un comentario muy útil.
Sulliwane
@Sulliwane: Lo ha hecho (ahora) . Bergi, probablemente sería mejor actualizar la respuesta para decir que puede usar expresiones miembro como lo muestra Logan. (¿Es realmente cierto que la especificación cambió tanto entre abril y junio de 2015?)
TJ Crowder
@TJCrowder No, no creo que haya cambiado, creo que estaba hablando {oof.x, oof.y} = foo. O tal vez realmente lo había extrañado.
Bergi
29

OMI, esta es la forma más fácil de lograr lo que estás buscando:

let { prop1, prop2, prop3 } = someObject;
let data = { prop1, prop2, prop3 };

  // data === { prop1: someObject.prop1, ... }

Básicamente, desestructurar en variables y luego usar la abreviatura inicializador para hacer un nuevo objeto. No hay necesidad deObject.assign

Creo que esta es la forma más legible, de todos modos. Por la presente, puede seleccionar los accesorios exactos de los someObjectque desea. Si tiene un objeto existente en el que solo desea fusionar los accesorios, haga algo como esto:

let { prop1, prop2, prop3 } = someObject;
let data = Object.assign(otherObject, { prop1, prop2, prop3 });
    // Makes a new copy, or...
Object.assign(otherObject, { prop1, prop2, prop3 });
    // Merges into otherObject

Otra forma, posiblemente más limpia, de escribirlo es:

let { prop1, prop2, prop3 } = someObject;
let newObject = { prop1, prop2, prop3 };

// Merges your selected props into otherObject
Object.assign(otherObject, newObject);

Lo uso POSTmucho para solicitudes en las que solo necesito algunos datos discretos. Pero, estoy de acuerdo en que debería haber una línea para hacer esto.

EDITAR: PD: ¡recientemente aprendí que puedes usar la ultradesestructuración en el primer paso para extraer valores anidados de objetos complejos! Por ejemplo...

let { prop1, 
      prop2: { somethingDeeper }, 
      prop3: { 
         nested1: {
            nested2
         } 
      } = someObject;
let data = { prop1, somethingDeeper, nested2 };

Además, puede usar el operador de propagación en lugar de Object.assign al hacer un nuevo objeto:

const { prop1, prop2, prop3 } = someObject;
let finalObject = {...otherObject, prop1, prop2, prop3 };

O...

const { prop1, prop2, prop3 } = someObject;
const intermediateObject = { prop1, prop2, prop3 };
const finalObject = {...otherObject, ...intermediateObject };
Zfalen
fuente
Me gusta este enfoque, pragmático.
Jesse
2
Esto es lo que hago pero no es muy seco. Creo que lo que mucha gente realmente necesita es solo una función de extracción de teclas.
jgmjgm
@jgmjgm sí, sería bueno tener uno incorporado, pero supongo que tampoco es demasiado difícil de escribir.
Zfalen
12

Además de Object.assignla sintaxis de propagación de objetos, que es una propuesta de Etapa 2 para ECMAScript.

var foo = {
  x: "bar",
  y: "baz"
}

var oof = { z: "z" }

oof =  {...oof, ...foo }

console.log(oof)

/* result 
{
  "x": "bar",
  "y": "baz",
  "z": "z"
}
*/

Pero para usar esta función, debe usar stage-2o transform-object-rest-spreadplugin para babel. Aquí hay una demostración en babel constage-2

gafi
fuente
9
En realidad, esto no establece las propiedades del objeto existente, sino que crea un nuevo objeto que contiene todas las propiedades de ambos.
Matt Browne
8

Complemento BabelJS

Si está utilizando BabelJS , ahora puede activar mi complemento babel-plugin-transform-object-from-destructuring( consulte el paquete npm para la instalación y el uso ).

Tuve el mismo problema descrito en este hilo y para mí fue muy agotador cuando creas un objeto a partir de una expresión destructiva, especialmente cuando tienes que cambiar el nombre, agregar o eliminar una propiedad. Con este complemento, mantener tales escenarios se vuelve mucho más fácil para usted.

Ejemplo de objeto

let myObject = {
  test1: "stringTest1",
  test2: "stringTest2",
  test3: "stringTest3"
};
let { test1, test3 } = myObject,
  myTest = { test1, test3 };

Se puede escribir como:

let myTest = { test1, test3 } = myObject;

Ejemplo de matriz

let myArray = ["stringTest1", "stringTest2", "stringTest3"];
let [ test1, , test3 ] = myArray,
  myTest = [ test1, test3 ];

Se puede escribir como:

let myTest = [ test1, , test3 ] = myArray;
Matthias Günter
fuente
Esto es precisamente lo que quería. ¡Gracias!
Garrettmaring
let myTest = { test1, test3 } = myObject;no funciona
Eatdoku
4

Es totalmente posible Simplemente no en una declaración.

var foo = {
    x: "bar",
    y: "baz"
};
var oof = {};
({x: oof.x, y: oof.y} = foo); // {x: "bar", y: "baz"}

(Tenga en cuenta el paréntesis en torno a la declaración.) Pero tenga en cuenta que la legibilidad es más importante que el golf de código :).

Fuente: http://exploringjs.com/es6/ch_destructuring.html#sec_assignment-targets

Hampus Ahlgren
fuente
3

Puede usar la reestructuración para eso de esta manera:

const foo = {x:"a", y:"b"};
const {...oof} = foo; // {x:"a", y:"b"} 

O combine ambos objetos si oof tiene valores:

const foo = {x:"a", y:"b"};
let oof = {z:"c"}
oof = Object.assign({}, oof, foo)
CampSafari
fuente
Creo que este primer caso es exactamente lo que estaba buscando. Lo probé en la consola de Chrome y parece funcionar. ¡Salud! @campsafari
majorBummer
1
@majorBummer Su llamada al final, pero consideraría un enfoque para no responder realmente a su pregunta, porque ambos crean nuevos objetos, en lugar de agregar propiedades a los objetos existentes como su título pregunta.
loganfsmyth
Ese es un buen punto @loganfsmyth. Creo que me entusiasmó el método que sacó CampSafari porque no me había dado cuenta de que eso era posible.
majorBummer
1
Si no le importa crear un nuevo objeto, simplemente podría hacerlooof = {...oof, ...foo}
Joshua Coady el
2

Puede devolver el objeto desestructurado en una función de flecha y usar Object.assign () para asignarlo a una variable.

const foo = {
  x: "bar",
  y: "baz"
}

const oof = Object.assign({}, () => ({ x, y } = foo));
Ben Copeland
fuente
1

SECO

var a = {a1:1, a2: 2, a3: 3};
var b = {b1:1, b2: 2, b3: 3};

const newVar = (() => ({a1, a2, b1, b2})).bind({...a, ...b});
const val = newVar();
console.log({...val});
// print: Object { a1: 1, a2: 2, b1: 1, b2: 2 }

o

console.log({...(() => ({a1, a2, b1, b2})).bind({...a, ...b})()});
usuario5733033
fuente
1

Puede destruir un objeto asignando directamente a otro atributo de objeto.

Ejemplo de trabajo:

let user = {};
[user.name, user.username] = "Stack Overflow".split(' ');
document.write(`
1st attr: ${user.name} <br /> 
2nd attr: ${user.username}`);

Puede trabajar con la destrucción utilizando variables con el mismo nombre de atributo de objeto que desea capturar, de esta manera no necesita hacer:

let user = { name: 'Mike' }
let { name: name } = user;

Use de esta manera:

let user = { name: 'Mike' }
let { name } = user;

De la misma manera, puede establecer nuevos valores para las estructuras de objetos si tienen el mismo nombre de atributo.

Mira este ejemplo de trabajo:

// The object to be destructed
let options = {
  title: "Menu",
  width: 100,
  height: 200
};

// Destructing
let {width: w, height: h, title} = options;

// Feedback
document.write(title + "<br />");  // Menu
document.write(w + "<br />");      // 100
document.write(h);                 // 200

RPichioli
fuente
0

Esto funciona en cromo 53.0.2785.89

let foo = {
  x: "bar",
  y: "baz"
};

let oof = {x, y} = foo;

console.log(`oof: ${JSON.stringify(oof)});

//prints
oof: {
  "x": "bar",
  "y": "baz"
}
usuario1577390
fuente
77
Lamentablemente, parece que oofsolo recibe una referencia fooy evita toda la desestructuración (al menos en Chrome). oof === fooy let oof = { x } = fooaún regresa{ x, y }
Theo.T
@ Theo.T buena captura. que es un fastidio, voy a tener que encontrar otra manera
user1577390
Vale la pena guardar estos solo para demostrar cómo JS puede ser confuso.
jgmjgm
0

Se me ocurrió este método:

exports.pick = function pick(src, props, dest={}) {
    return Object.keys(props).reduce((d,p) => {
        if(typeof props[p] === 'string') {
            d[props[p]] = src[p];
        } else if(props[p]) {
            d[p] = src[p];
        }
        return d;
    },dest);
};

Que puedes usar así:

let cbEvents = util.pick(this.props.events, {onFocus:1,onBlur:1,onCheck:'onChange'});
let wrapEvents = util.pick(this.props.events, {onMouseEnter:1,onMouseLeave:1});

es decir, puede elegir qué propiedades desea y colocarlas en un nuevo objeto. A diferencia _.pick, también puede cambiarles el nombre al mismo tiempo.

Si desea copiar los accesorios en un objeto existente, simplemente configure el destargumento.

mpen
fuente
0

Esto es una especie de trampa, pero puedes hacer algo como esto ...

const originalObject = {
  hello: 'nurse',
  meaningOfLife: 42,
  your: 'mom',
};

const partialObject = (({ hello, your }) => {
  return { hello, your };
})(originalObject);

console.log(partialObject); // ​​​​​{ hello: 'nurse', your: 'mom' }​​​​​

En la práctica, creo que raramente querrás usar eso. Lo siguiente es MUCHO más claro ... pero no tan divertido.

const partialObject = {
  hello: originalObject.hello,
  your: originalObject.your,
};

Otra ruta completamente diferente, que incluye mucking con el prototipo (cuidado ahora ...):

if (!Object.prototype.pluck) {
  Object.prototype.pluck = function(...props) {
    return props.reduce((destObj, prop) => {
      destObj[prop] = this[prop];

      return destObj;
    }, {});
  }
}

const originalObject = {
  hello: 'nurse',
  meaningOfLife: 42,
  your: 'mom',
};

const partialObject2 = originalObject.pluck('hello', 'your');

console.log(partialObject2); // { hello: 'nurse', your: 'mom' }
Bart
fuente
0

Esta es la solución más legible y más corta que se me ocurrió:

let props = { 
  isValidDate: 'yes',
  badProp: 'no!',
};

let { isValidDate } = props;
let newProps = { isValidDate };

console.log(newProps);

Saldrá { isValidDate: 'yes' }

Sería bueno algún día poder decir algo así, let newProps = ({ isValidDate } = props)pero desafortunadamente no es algo que ES6 admita.

Patrick Michaelsen
fuente
0

No es una manera hermosa, ni la recomiendo, pero es posible de esta manera, solo por conocimiento.

const myObject = {
  name: 'foo',
  surname: 'bar',
  year: 2018
};

const newObject = ['name', 'surname'].reduce(
  (prev, curr) => (prev[curr] = myObject[curr], prev),
  {},
);

console.log(JSON.stringify(newObject)); // {"name":"foo","surname":"bar"}
Sornii
fuente
0

Puede usar métodos de clase JSON para lograrlo de la siguiente manera

const foo = {
   x: "bar",
   y: "baz"
};

const oof = JSON.parse(JSON.stringify(foo, ['x','y']));
// output -> {x: "bar", y: "baz"}

Pase las propiedades que deben agregarse al objeto resultante como segundo argumento para stringifyfuncionar en un formato de matriz.

MDN Doc para JSON.stringify

Bharathvaj Ganesan
fuente