Apakah mungkin untuk merusak ke objek yang ada? (Javascript ES6)

136

Sebagai contoh jika saya memiliki dua objek:

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

dan

var oof = {}

dan saya ingin mentransfer nilai x dan y dari foo ke oof. Apakah ada cara untuk melakukan itu menggunakan sintaksis esstructuring es6?

mungkin sesuatu seperti:

oof{x,y} = foo
majorBummer
sumber
10
Jika Anda ingin menyalin semua propertiObject.assign(oof, foo)
elclanrs
Banyak contoh yang merusak di sini di MDN , tapi saya tidak melihat yang Anda tanyakan.
jfriend00
Hmm saya juga tidak bisa menemukan satu ..
majorBummer
Lihat jawaban saya di bawah ini untuk solusi dua jalur tanpaObject.assign
Zfalen

Jawaban:

116

Meski jelek dan sedikit berulang, Anda bisa melakukannya

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

yang akan membaca dua nilai fooobjek, dan menuliskannya ke lokasi masing-masing pada oofobjek.

Secara pribadi saya masih lebih suka membaca

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

atau

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

meskipun.

loganfsmyth
sumber
2
Alternatif ['x', 'y']. ForEach (prop => oof [prop] = foo [prop]); seperti yang saya lihat, adalah satu-satunya KERING (jangan ulangi sendiri), sampai sekarang. "KERING" akan sangat berguna dalam hal beberapa kunci yang akan dipetakan. Anda hanya perlu memperbarui satu tempat. Mungkin saya salah. Bagaimanapun, terima kasih!
Vladimir Brasil
1
Contoh ketiga adalah KERING, tetapi Anda harus menggunakan string sebagai kunci, yang biasanya dilakukan secara javascript. Tidak yakin itu kurang merepotkan daripada: const {x, y} = foo; const oof = {x, y};
Jeff Lowery
Dapatkah seseorang menunjukkan kepada saya di jsfiddle di mana saran pertama bekerja? Tidak berfungsi di sini di chrome: jsfiddle.net/7mh399ow
techguy2000
@ techguy2000 Anda lupa titik koma setelahnya var oof = {};.
loganfsmyth
Dalam kode pertama, seharusnya tidak ({x: oof.x, y: oof.y} = foo)? Saya pikir Anda telah menempatkan tambahan f di oof .
Sornii
38

Tidak, perusakan tidak mendukung ekspresi anggota di singkatan tetapi hanya propertynames biasa pada saat ini. Sudah ada pembicaraan tentang esdiscuss, tetapi tidak ada proposal yang akan masuk ke ES6.

Anda mungkin dapat menggunakan Object.assignnamun - jika Anda tidak membutuhkan semua properti sendiri, Anda masih bisa melakukannya

var foo = …,
    oof = {};
{
    let {x, y} = foo;
    Object.assign(oof, {x, y})
}
Bergi
sumber
3
@loganfsmyth, contoh Anda tidak berfungsi untuk saya setidaknya dalam pengujian saya dengan simpul 4.2.2. dengan --harmony_destructuringdiaktifkan. Saya melihat "SyntaxError: Token yang tidak terduga."
jpierson
@loganfsmyth Anda harus mengirimkan jawaban yang tepat karena ini adalah komentar yang sangat berguna.
Sulliwane
@Ulliwane: Dia melakukannya (sekarang) . Bergi, mungkin yang terbaik adalah memperbarui jawaban untuk memanggil bahwa Anda dapat menggunakan ekspresi anggota seperti yang ditunjukkan oleh Logan. (Apakah benar spek itu berubah banyak antara bulan April dan Juni 2015)
TJ Crowder
@ TJCrowder Tidak, saya tidak berpikir itu berubah, saya kira saya bicarakan {oof.x, oof.y} = foo. Atau mungkin aku benar-benar melewatkannya.
Bergi
29

IMO ini adalah cara termudah untuk mencapai apa yang Anda cari:

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

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

Pada dasarnya, perusakan menjadi variabel dan kemudian gunakan singkatan initializer untuk membuat objek baru. Tidak perluObject.assign

Saya pikir ini adalah cara yang paling mudah dibaca. Anda dapat memilih alat peraga yang tepat sesuai someObjectyang Anda inginkan. Jika Anda memiliki objek yang sudah ada dan ingin digabungkan dengan props, lakukan sesuatu seperti ini:

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

Cara lain, yang bisa dibilang lebih bersih, untuk menulisnya adalah:

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

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

Saya menggunakan ini untuk POSTbanyak permintaan di mana saya hanya perlu beberapa data diskrit. Tapi, saya setuju harus ada satu liner untuk melakukan ini.

EDIT: PS - Saya baru-baru ini belajar Anda dapat menggunakan ultra destrukturisasi pada langkah pertama untuk menarik nilai bersarang dari objek kompleks! Misalnya...

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

Plus, Anda bisa menggunakan operator spread alih-alih Object.assign ketika membuat objek baru:

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

Atau...

const { prop1, prop2, prop3 } = someObject;
const intermediateObject = { prop1, prop2, prop3 };
const finalObject = {...otherObject, ...intermediateObject };
Zfalen
sumber
Saya suka pendekatan ini, pragmatis.
Jesse
2
Ini yang saya lakukan tetapi tidak terlalu kering. Saya pikir apa yang benar-benar dibutuhkan banyak orang hanyalah fungsi ekstrak kunci.
jgmjgm
@ jgmjgm ya, akan menyenangkan untuk memiliki satu built in tapi kurasa itu tidak terlalu sulit untuk ditulis.
Zfalen
12

Selain Object.assignada sintaks penyebaran objek yang merupakan proposal Tahap 2 untuk ECMAScript.

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

var oof = { z: "z" }

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

console.log(oof)

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

Tetapi untuk menggunakan fitur ini, Anda perlu menggunakan stage-2atau transform-object-rest-spreadplugin untuk babel. Berikut ini adalah demo tentang babel denganstage-2

Gafi
sumber
9
Ini tidak benar-benar mengatur properti pada objek yang ada, melainkan membuat objek baru yang berisi semua properti keduanya.
Matt Browne
8

Plugin BabelJS

Jika Anda menggunakan BabelJS sekarang Anda dapat mengaktifkan plugin saya babel-plugin-transform-object-from-destructuring( lihat paket npm untuk instalasi dan penggunaan ).

Saya memiliki masalah yang sama yang dijelaskan di utas ini dan bagi saya itu sangat melelahkan ketika Anda membuat objek dari ekspresi yang merusak, terutama ketika Anda harus mengganti nama, menambah atau menghapus properti. Dengan plugin ini, mempertahankan skenario seperti itu akan jauh lebih mudah bagi Anda.

Contoh objek

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

dapat ditulis sebagai:

let myTest = { test1, test3 } = myObject;

Contoh array

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

dapat ditulis sebagai:

let myTest = [ test1, , test3 ] = myArray;
Matthias Günter
sumber
Inilah yang saya inginkan. Terima kasih!
garrettmaring
let myTest = { test1, test3 } = myObject;tidak berfungsi
Eatdoku
4

Sangat mungkin. Hanya saja tidak dalam satu pernyataan.

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

(Perhatikan tanda kurung di sekitar pernyataan.) Namun perlu diingat keterbacaan lebih penting daripada kode-golf :).

Sumber: http://exploringjs.com/es6/ch_destrukturisasi.html#sec_assignment-targets

Hampus Ahlgren
sumber
3

Anda bisa menggunakan restrukturisasi untuk itu seperti ini:

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

Atau menggabungkan kedua objek jika memiliki nilai:

const foo = {x:"a", y:"b"};
let oof = {z:"c"}
oof = Object.assign({}, oof, foo)
CampSafari
sumber
Saya pikir ini kasus pertama persis apa yang saya cari. Saya mencobanya di konsol chrome dan sepertinya berhasil. Bersulang! @campsafari
majorBummer
1
@majorBummer Panggilan Anda pada akhirnya, tetapi saya akan mempertimbangkan pendekatan untuk tidak benar-benar menjawab pertanyaan Anda, karena keduanya membuat objek baru , daripada menambahkan properti ke objek yang ada seperti judul Anda bertanya.
loganfsmyth
Itu poin yang bagus @loganfsmyth. Saya pikir saya hanya senang dengan metode camp yang dibesarkan Safari karena saya tidak menyadari bahwa itu mungkin.
majorBummer
1
Jika Anda tidak keberatan membuat objek baru yang bisa Anda lakukanoof = {...oof, ...foo}
Joshua Coady
2

Anda bisa mengembalikan objek yang dirusak dalam fungsi panah, dan menggunakan Object.assign () untuk menetapkannya ke variabel.

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

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

KERING

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 }

atau

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

Anda dapat merusak objek yang ditugaskan langsung ke atribut objek lain.

Contoh kerja:

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

Anda dapat bekerja dengan merusak menggunakan variabel dengan nama atribut objek yang sama yang ingin Anda tangkap, dengan cara ini Anda tidak perlu melakukannya:

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

Gunakan cara ini:

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

Cara yang sama Anda dapat mengatur nilai baru ke struktur objek jika mereka memiliki nama atribut yang sama.

Lihatlah contoh kerja ini:

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

Ini bekerja di 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"
}
pengguna1577390
sumber
7
Sayangnya sepertinya oofhanya menerima referensi foodan melewati seluruh perusakan (setidaknya di Chrome). oof === foodan let oof = { x } = foobelum mengembalikan{ x, y }
Theo.T
@ Theo.T tangkapan yang bagus. itu menyedihkan, saya harus mencari cara lain
user1577390
Yang ini layak disimpan hanya untuk menunjukkan bagaimana JS bisa membingungkan.
jgmjgm
0

Saya datang dengan metode ini:

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

Yang bisa Anda gunakan seperti ini:

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

yaitu, Anda dapat memilih properti mana yang Anda inginkan dan memasukkannya ke objek baru. Tidak seperti itu_.pick Anda, Anda juga dapat mengubah nama mereka secara bersamaan.

Jika Anda ingin menyalin alat peraga ke objek yang ada, cukup setel destarg.

Mpen
sumber
0

Ini agak curang, tetapi Anda dapat melakukan sesuatu seperti ini ...

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

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

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

Dalam praktiknya, saya pikir Anda jarang ingin menggunakannya. Berikut ini JAUH lebih jelas ... tetapi tidak menyenangkan.

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

Rute lain yang sama sekali berbeda, yang mencakup pengikatan dengan prototipe (hati-hati sekarang ...):

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

Ini adalah solusi yang paling mudah dibaca dan paling singkat yang bisa saya buat:

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

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

console.log(newProps);

Ini akan menampilkan { isValidDate: 'yes' }

Akan menyenangkan untuk suatu hari bisa mengatakan sesuatu seperti let newProps = ({ isValidDate } = props)tapi sayangnya itu bukan sesuatu yang didukung ES6.

Patrick Michaelsen
sumber
0

Ini bukan cara yang indah, saya juga tidak merekomendasikannya, tetapi mungkin seperti ini, hanya untuk pengetahuan.

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

Anda dapat menggunakan metode kelas JSON untuk mencapainya sebagai berikut

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

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

Pass properti yang perlu ditambahkan ke objek yang dihasilkan sebagai argumen kedua stringifyberfungsi dalam format array.

MDN Doc untuk JSON.stringify

Bharathvaj Ganesan
sumber