Czy można zniszczyć istniejący obiekt? (Javascript ES6)

142

Na przykład, jeśli mam dwa obiekty:

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

i

var oof = {}

i chciałem przenieść wartości xiy z foo do oof. Czy jest na to sposób za pomocą składni destrukturyzacji es6?

może coś takiego:

oof{x,y} = foo
majorBummer
źródło
10
Jeśli chcesz skopiować wszystkie nieruchomościObject.assign(oof, foo)
elclanrs
Wiele niszczycielskich przykładów tutaj na MDN , ale nie widzę tego, o który pytasz.
jfriend00
Hmm, ja też nie mogłem znaleźć ...
majorBummer
Zobacz moją odpowiedź poniżej na rozwiązanie dwuliniowe bezObject.assign
Zfalen

Odpowiedzi:

129

Chociaż brzydkie i nieco powtarzalne, możesz to zrobić

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

który odczyta dwie wartości fooobiektu i zapisze je w odpowiednich lokalizacjach w oofobiekcie.

Osobiście nadal wolałbym czytać

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

lub

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

chociaż.

loganfsmyth
źródło
3
Alternatywa ['x', 'y']. ForEach (prop => oof [prop] = foo [prop]); jak widzę to jedyny SUCHY (nie powtarzaj się), do tej pory. Opcja „DRY” byłaby rzeczywiście przydatna w przypadku mapowania kilku kluczy. Wystarczy zaktualizować jedno miejsce. Może się mylę. W każdym razie dzięki!
Vladimir Brasil,
1
Trzeci przykład to DRY, ale musisz użyć łańcuchów jako kluczy, co normalnie robi niejawnie javascript. Nie jestem przekonany, że to mniej uciążliwe niż: const {x, y} = foo; const oof = {x, y};
Jeff Lowery
Czy ktoś może mi pokazać w jsfiddle, gdzie działa pierwsza sugestia? Tutaj nie działa na chrome: jsfiddle.net/7mh399ow
techguy2000
@ techguy2000 Zapomniałeś średnika po var oof = {};.
loganfsmyth
Nie powinno być w pierwszym kodzie ({x: oof.x, y: oof.y} = foo)? Myślę, że włożyłeś dodatkowe f in oof .
Sornii
39

Nie, destrukturyzacja nie obsługuje obecnie wyrażeń składowych w skrótach, ale tylko zwykłe nazwy właściwości. Były o tym rozmowy w ramach esdiscussingu, ale żadne propozycje nie trafią do ES6.

Możesz Object.assignjednak użyć - jeśli nie potrzebujesz wszystkich własnych właściwości, nadal możesz to zrobić

var foo = …,
    oof = {};
{
    let {x, y} = foo;
    Object.assign(oof, {x, y})
}
Bergi
źródło
3
@loganfsmyth, Twój przykład nie działa dla mnie przynajmniej w moich testach z węzłem 4.2.2. z --harmony_destructuringwłączoną. Widzę „SyntaxError: Nieoczekiwany token”.
jpierson,
@loganfsmyth powinieneś przesłać poprawną odpowiedź, ponieważ jest to bardzo przydatny komentarz imo.
Sulliwane
@Sulliwane: Zrobił to (teraz) . BERGI, będzie prawdopodobnie najlepiej zaktualizować odpowiedź wołać, że można używać wyrażeń członka, jak pokazano przez Logana. (Czy to prawda, że ​​specyfikacja zmieniła się tak bardzo między kwietniem a czerwcem 2015?)
TJ Crowder
@TJCrowder Nie, nie sądzę, że to się zmieniło, chyba o tym mówiłem {oof.x, oof.y} = foo. A może naprawdę to przegapiłem.
Bergi
33

IMO to najłatwiejszy sposób na osiągnięcie tego, czego szukasz:

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

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

Zasadniczo, zniszczenie na zmienne, a następnie użyj skrótu inicjalizatora, aby utworzyć nowy obiekt. Nie ma potrzebyObject.assign

W każdym razie myślę, że jest to najbardziej czytelny sposób. Możesz tutaj wybrać dokładnie te rekwizyty, someObjectktóre chcesz. Jeśli masz istniejący obiekt, do którego chcesz po prostu scalić rekwizyty, zrób coś takiego:

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

Innym, prawdopodobnie czystszym sposobem zapisania tego jest:

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

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

Często używam tego do POSTżądań, w których potrzebuję tylko kilku fragmentów dyskretnych danych. Ale zgadzam się, że powinien istnieć jeden liniowiec do tego.

EDYCJA: PS - Niedawno dowiedziałem się, że w pierwszym kroku można użyć ultra destrukturyzacji, aby wyciągnąć zagnieżdżone wartości ze złożonych obiektów! Na przykład...

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

Dodatkowo, podczas tworzenia nowego obiektu możesz użyć operatora rozszerzania zamiast Object. assign:

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

Lub...

const { prop1, prop2, prop3 } = someObject;
const intermediateObject = { prop1, prop2, prop3 };
const finalObject = {...otherObject, ...intermediateObject };
Zfalen
źródło
Podoba mi się to podejście, pragmatyczne.
Jesse,
2
To właśnie robię, ale nie jest to zbyt suche. Myślę, że to, czego naprawdę potrzebuje wiele osób, to po prostu funkcja wyodrębniania kluczy.
jgmjgm
@jgmjgm tak, byłoby miło mieć wbudowany, ale myślę, że to też nie jest trudne do napisania.
Zfalen
13

Poza tym Object.assignistnieje składnia rozprzestrzeniania obiektów, która jest propozycją etapu 2 dla ECMAScript.

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

var oof = { z: "z" }

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

console.log(oof)

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

Ale aby skorzystać z tej funkcji, musisz użyć wtyczki stage-2lub transform-object-rest-spreadwtyczki do babel. Oto demo na Babel zstage-2

gafi
źródło
9
W rzeczywistości nie ustawia to właściwości istniejącego obiektu, ale raczej tworzy nowy obiekt zawierający wszystkie właściwości obu.
Matt Browne,
9

Wtyczka BabelJS

Jeśli używasz BabelJS , możesz teraz aktywować moją wtyczkę babel-plugin-transform-object-from-destructuring( zobacz pakiet npm do instalacji i użytkowania ).

Miałem ten sam problem opisany w tym wątku i było to dla mnie bardzo męczące, kiedy tworzyłeś obiekt z destrukturyzującej wyrażenia, szczególnie gdy musisz zmienić nazwę, dodać lub usunąć właściwość. Dzięki tej wtyczce utrzymanie takich scenariuszy stanie się znacznie łatwiejsze.

Przykład obiektu

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

można zapisać jako:

let myTest = { test1, test3 } = myObject;

Przykład tablicy

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

można zapisać jako:

let myTest = [ test1, , test3 ] = myArray;
Matthias Günter
źródło
Właśnie tego chciałem. Dziękuję Ci!
garrettmaring
let myTest = { test1, test3 } = myObject;nie działa
Eatdoku
4

Jest to całkowicie możliwe. Tylko nie w jednym oświadczeniu.

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

(Zwróć uwagę na nawiasy wokół zdania). Pamiętaj jednak, że czytelność jest ważniejsza niż gra w kodowanie :).

Źródło: http://exploringjs.com/es6/ch_destruising.html#sec_assignment-targets

Hampus Ahlgren
źródło
3

Możesz po prostu użyć do tego restrukturyzacji:

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

Lub scal oba obiekty, jeśli oof ma wartości:

const foo = {x:"a", y:"b"};
let oof = {z:"c"}
oof = Object.assign({}, oof, foo)
CampSafari
źródło
Myślę, że ten pierwszy przypadek jest dokładnie tym, czego szukałem. Wypróbowałem to w konsoli chrome i wydaje się, że działa. Twoje zdrowie! @campsafari
majorBummer
1
@majorBummer Twoje wywołanie w końcu, ale rozważałbym podejście, aby nie odpowiadać na Twoje pytanie, ponieważ oba te elementy tworzą nowe obiekty, zamiast dodawać właściwości do istniejących obiektów, takich jak twój tytuł.
loganfsmyth
To dobra uwaga @loganfsmyth. Myślę, że byłem po prostu podekscytowany metodą, którą wychował CampSafari, ponieważ nie zdawałem sobie sprawy, że to możliwe.
majorBummer
1
Jeśli nie masz nic przeciwko stworzeniu nowego obiektu, możesz po prostu zrobićoof = {...oof, ...foo}
Joshua Coady
2

Możesz zwrócić zniszczony obiekt w funkcji strzałkowej i użyć Object. assign (), aby przypisać go do zmiennej.

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

const oof = Object.assign({}, () => ({ x, y } = foo));
Ben Copeland
źródło
1

SUCHY

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 }

lub

console.log({...(() => ({a1, a2, b1, b2})).bind({...a, ...b})()});
user5733033
źródło
1

Możesz zniszczyć obiekt przypisując go bezpośrednio do innego atrybutu obiektu.

Przykład pracy:

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

Możesz pracować z niszczeniem używając zmiennych o tej samej nazwie atrybutu obiektu, który chcesz przechwycić, w ten sposób nie musisz tego robić:

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

Użyj w ten sposób:

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

W ten sam sposób można ustawić nowe wartości w strukturach obiektów, jeśli mają one tę samą nazwę atrybutu.

Spójrz na ten działający przykład:

// 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
źródło
0

Działa to w przeglądarce 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
źródło
7
Niestety wygląda na to, że oofpo prostu otrzymuje odniesienie fooi omija całą destrukturyzację (przynajmniej w Chrome). oof === fooa let oof = { x } = foojednak wraca{ x, y }
Theo.T
@ Theo.T dobry chwyt. to bummer, będę musiał znaleźć inny sposób
user1577390
Warto je zachować tylko po to, aby pokazać, jak JS może być mylący.
jgmjgm
0

Wymyśliłem tę metodę:

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

Którego możesz użyć w ten sposób:

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

tj. możesz wybrać właściwości, które chcesz uzyskać i umieścić je w nowym obiekcie. W przeciwieństwie do tego _.pickmożesz również zmienić ich nazwę w tym samym czasie.

Jeśli chcesz skopiować właściwości do istniejącego obiektu, po prostu ustaw destargument.

mpen
źródło
0

To trochę oszustwo, ale możesz zrobić coś takiego ...

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

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

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

W praktyce myślę, że rzadko będziesz chciał tego używać. Poniższy tekst jest ZNACZNIE bardziej jasny ... ale nie tak zabawny.

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

Kolejna zupełnie inna trasa, która obejmuje grzebanie w prototypie (teraz ostrożnie ...):

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
źródło
0

To najbardziej czytelne i najkrótsze rozwiązanie, jakie mogłem wymyślić:

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

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

console.log(newProps);

To wyjdzie { isValidDate: 'yes' }

Byłoby miło, gdybyśmy kiedyś mogli coś takiego powiedzieć, let newProps = ({ isValidDate } = props)ale niestety nie jest to coś, co obsługuje ES6.

Patrick Michaelsen
źródło
0

To nie jest piękny sposób, ani go nie polecam, ale jest to możliwe, tylko dla wiedzy.

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
źródło
0

Aby to osiągnąć, możesz użyć metod klasy JSON w następujący sposób

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

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

Przekaż właściwości, które należy dodać do wynikowego obiektu jako drugi argument, aby stringifydziałać w formacie tablicy.

Dokument MDN dla JSON.stringify

Bharathvaj Ganesan
źródło