É possível desestruturar em um objeto existente? (Javascript ES6)

135

Por exemplo, se eu tiver dois objetos:

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

e

var oof = {}

e eu queria transferir os valores xey de foo para oof. Existe uma maneira de fazer isso usando a sintaxe de desestruturação es6?

talvez algo como:

oof{x,y} = foo
majorBummer
fonte
10
Se você deseja copiar todas as propriedadesObject.assign(oof, foo)
elclanrs
Muitos exemplos destrutivos aqui no MDN , mas não vejo o que você está perguntando.
jfriend00
Hmm eu não poderia encontrar um quer ..
majorBummer
Veja abaixo a minha resposta para uma solução de dois linha semObject.assign
Zfalen

Respostas:

115

Enquanto feio e um pouco repetitivo, você pode fazer

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

que lerá os dois valores do fooobjeto e os gravará em seus respectivos locais no oofobjeto.

Pessoalmente, eu ainda prefiro ler

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

ou

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

Apesar.

loganfsmyth
fonte
2
A alternativa ['x', 'y']. ForEach (prop => oof [prop] = foo [prop]); como eu vejo, é o único seco (não se repita), até agora. "DRY" seria realmente útil no caso de várias chaves serem mapeadas. Você só precisaria atualizar um local. Talvez eu esteja errado. Obrigado mesmo assim!
Vladimir Brasil
1
O terceiro exemplo é DRY, mas você precisa usar strings como chaves, o que o javascript normalmente usa implicitamente. Não estou convencido de que isso seja menos incômodo do que: const {x, y} = foo; const oof = {x, y};
Jeff Lowery
Alguém pode me mostrar no jsfiddle onde a primeira sugestão funciona? Não está funcionando aqui no chrome: jsfiddle.net/7mh399ow
techguy2000
@ techguy2000 Você esqueceu o ponto e vírgula depois var oof = {};.
Loganfsmyth
No primeiro código, não deveria ser ({x: oof.x, y: oof.y} = foo)? Eu acho que você colocou um f extra no oof .
Sornii
38

Não, a desestruturação não suporta expressões de membros em atalhos, mas apenas nomes de propriedades simples no momento atual. Houve conversas sobre esse assunto no esdiscuss, mas nenhuma proposta chegará ao ES6.

Object.assignNo entanto, você pode usar - se não precisar de todas as propriedades, ainda poderá fazer

var foo = …,
    oof = {};
{
    let {x, y} = foo;
    Object.assign(oof, {x, y})
}
Bergi
fonte
3
@loganfsmyth, seu exemplo não está funcionando para mim, pelo menos nos meus testes com o nó 4.2.2. com --harmony_destructuringativado. Eu vejo "SyntaxError: token inesperado".
jpierson
@loganfsmyth, você deve enviar uma resposta adequada, pois este é um comentário muito útil.
Sulliwane
@ Sulliwane: Ele fez isso (agora) . Bergi, provavelmente seria melhor atualizar a resposta para destacar que você pode usar expressões de membro, como mostra Logan. (É verdade que a especificação mudou muito entre abril e junho de 2015?)
TJ Crowder
@TJCrowder Não, acho que não mudou, acho que estava falando {oof.x, oof.y} = foo. Ou talvez eu realmente tivesse perdido.
Bergi 26/03/19
29

Na IMO, essa é a maneira mais fácil de realizar o que você está procurando:

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

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

Basicamente, desestruture em variáveis ​​e use a abreviação do inicializador para criar um novo objeto. Não há necessidade deObject.assign

Eu acho que essa é a maneira mais legível, de qualquer maneira. Você pode selecionar os adereços exatos someObjectque deseja. Se você já possui um objeto no qual deseja mesclar os objetos, faça algo assim:

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

Outra maneira, sem dúvida mais limpa, de escrevê-lo é:

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

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

Eu uso muito isso para POSTsolicitações em que preciso apenas de alguns dados discretos. Mas, eu concordo que deve haver uma linha para fazer isso.

EDIT: PS - Eu aprendi recentemente que você pode usar a ultra-desestruturação na primeira etapa para extrair valores aninhados de objetos complexos! Por exemplo...

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

Além disso, você pode usar o operador spread em vez do Object.assign ao criar um novo objeto:

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

Ou...

const { prop1, prop2, prop3 } = someObject;
const intermediateObject = { prop1, prop2, prop3 };
const finalObject = {...otherObject, ...intermediateObject };
Zfalen
fonte
Eu gosto dessa abordagem, pragmática.
Jesse
2
É isso que eu faço, mas não é muito seco. Eu acho que o que muitas pessoas realmente precisam é apenas uma função de extrair chaves.
Jgmjgm
@jgmjgm sim, seria bom ter um incorporado, mas acho que também não é difícil escrever.
Zfalen 03/04
12

Além Object.assignda sintaxe de propagação do objeto, que é uma proposta do Estágio 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"
}
*/

Mas, para usar esse recurso, você precisa usar stage-2ou transform-object-rest-spreadplug-in para o babel. Aqui está uma demonstração sobre babel comstage-2

gafi
fonte
9
Na verdade, isso não define as propriedades do objeto existente, mas cria um novo objeto contendo todas as propriedades de ambos.
Matt Browne
8

Plugin BabelJS

Se você estiver usando o BabelJS, agora poderá ativar meu plug-in babel-plugin-transform-object-from-destructuring( consulte o pacote npm para instalação e uso ).

Eu tive o mesmo problema descrito neste tópico e, para mim, foi muito desgastante quando você cria um objeto a partir de uma expressão destruturante, especialmente quando é necessário renomear, adicionar ou remover uma propriedade. Com este plug-in, manter esses cenários fica muito mais fácil para você.

Exemplo de objeto

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

pode ser escrito como:

let myTest = { test1, test3 } = myObject;

Exemplo de matriz

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

pode ser escrito como:

let myTest = [ test1, , test3 ] = myArray;
Matthias Günter
fonte
Era exatamente isso que eu queria. Obrigado!
Garrettmaring 05/11/19
let myTest = { test1, test3 } = myObject;não funciona
Eatdoku 28/07
4

É totalmente possível. Apenas não em uma declaração.

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

(Observe os parênteses em torno da declaração.) Mas lembre-se de que a legibilidade é mais importante do que o código de golfe :).

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

Hampus Ahlgren
fonte
3

Você pode apenas usar a reestruturação para isso assim:

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

Ou mescle os dois objetos se oof tiver valores:

const foo = {x:"a", y:"b"};
let oof = {z:"c"}
oof = Object.assign({}, oof, foo)
CampSafari
fonte
Eu acho que esse primeiro caso é exatamente o que eu estava procurando. Eu tentei no console do chrome e parece funcionar. Felicidades! @campsafari
majorBummer
1
@majorBummer Sua ligação no final, mas eu consideraria uma abordagem para não responder à sua pergunta, porque ambos criam novos objetos, em vez de adicionar propriedades a objetos existentes , como o seu título pede.
Loganfsmyth 03/10/19
Esse é um bom ponto @loganfsmyth. Acho que fiquei empolgado com o método que o Safari criou porque não tinha percebido que isso era possível.
majorBummer
1
Se você não mente a criação de um novo objeto, você poderia apenas fazeroof = {...oof, ...foo}
Joshua Coady
2

Você pode retornar o objeto destruído em uma função de seta e usar Object.assign () para atribuí-lo a uma variável.

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

const oof = Object.assign({}, () => ({ x, y } = foo));
Ben Copeland
fonte
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 }

ou

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

Você pode destruir um objeto atribuindo diretamente a outro atributo do objeto.

Exemplo de trabalho:

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

Você pode trabalhar com a destruição usando variáveis ​​com o mesmo nome de atributo de objeto que deseja capturar, desta forma não é necessário:

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

Use desta maneira:

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

Da mesma maneira que você pode definir novos valores para estruturas de objetos, se eles tiverem o mesmo nome de atributo.

Veja este exemplo de trabalho:

// 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
fonte
0

Isso funciona no chrome 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"
}
user1577390
fonte
7
Infelizmente, parece que oofapenas recebe uma referência fooe ignora toda a desestruturação (pelo menos no Chrome). oof === fooe let oof = { x } = fooainda retorna{ x, y }
Theo.T
@ Theo.T boa captura. que é uma chatice, eu vou ter que encontrar outra maneira
user1577390
Vale a pena guardar apenas para demonstrar como o JS pode ser confuso.
Jgmjgm 21/0318
0

Eu vim com 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 você pode usar assim:

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

ou seja, você pode escolher quais propriedades deseja e colocá-las em um novo objeto. Ao contrário, _.pickvocê também pode renomeá-los ao mesmo tempo.

Se você deseja copiar os objetos em um objeto existente, basta definir o destargumento

mpen
fonte
0

Isso é meio que trapaça, mas você pode fazer algo assim ...

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

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

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

Na prática, acho que você raramente iria querer usar isso. O que se segue é MUITO mais claro ... mas não tão divertido.

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

Outra rota completamente diferente, que inclui sujeira com o protótipo (cuidado agora ...):

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
fonte
0

Esta é a solução mais legível e mais curta que eu poderia encontrar:

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

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

console.log(newProps);

Irá produzir { isValidDate: 'yes' }

Seria bom algum dia poder dizer algo como, let newProps = ({ isValidDate } = props)mas infelizmente não é algo que o ES6 suporte.

Patrick Michaelsen
fonte
0

Não é uma maneira bonita, nem eu recomendo, mas é possível assim, apenas pelo conhecimento.

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
fonte
0

Você pode usar métodos de classe JSON para alcançá-lo da seguinte maneira

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

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

Passe as propriedades que precisam ser adicionadas ao objeto resultante como segundo argumento para stringifyfuncionar em um formato de matriz.

Documento MDN para JSON.stringify

Bharathvaj Ganesan
fonte