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

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ż.


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

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

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


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;

Właśnie tego chciałem. Dziękuję Ci!
garrettmaring

let myTest = { test1, test3 } = myObject;nie działa
Eatdoku


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)

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

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

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


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"
}

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.


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' }

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.


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"}

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

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.