Có thể phá hủy cấu trúc trên một đối tượng hiện có? (Javascript ES6)


135

Ví dụ: nếu tôi có hai đối tượng:

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

var oof = {}

và tôi muốn chuyển các giá trị x và y từ foo sang oof. Có cách nào để làm điều đó bằng cách sử dụng cú pháp phá hủy es6 không?

có lẽ một cái gì đó như:

oof{x,y} = foo

10
Nếu bạn muốn sao chép tất cả các thuộc tínhObject.assign(oof, foo)
elclanrs

Rất nhiều ví dụ phá hủy ở đây trên MDN , nhưng tôi không thấy cái nào bạn đang hỏi về.
jfriend00

Hmm, tôi cũng không thể tìm thấy một ..
MajorBummer

Xem câu trả lời của tôi dưới đây để biết giải pháp hai dòng mà không cóObject.assign
Zfalen

Câu trả lời:


115

Mặc dù xấu xí và một chút lặp đi lặp lại, bạn có thể làm

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

sẽ đọc hai giá trị của foođối tượng và ghi chúng vào vị trí tương ứng của chúng trên oofđối tượng.

Cá nhân tôi vẫn thích đọc

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

hoặc là

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

Tuy nhiên.


2
Thay thế ['x', 'y']. ForEach (prop => oof [prop] = foo [prop]); như tôi thấy, là người duy nhất DRY (không lặp lại chính mình), cho đến bây giờ. "DRY" sẽ thực sự hữu ích trong trường hợp một số phím được ánh xạ. Bạn sẽ chỉ cần cập nhật một nơi. Có lẽ tôi đã sai lầm. Dẫu sao cũng xin cảm ơn!
Vladimir Brasil

1
Ví dụ thứ ba là DRY, nhưng bạn phải sử dụng các chuỗi làm khóa, mà javascript thường làm ngầm. Không tin rằng điều đó ít gây phiền toái hơn: const {x, y} = foo; const oof = {x, y};
Jeff Lowery

Ai đó có thể chỉ cho tôi trong jsfiddle nơi đề xuất đầu tiên hoạt động không? Nó không hoạt động ở đây trên chrome: jsfiddle.net/7mh399ow
techguy2000

@ techguy2000 Bạn đã quên dấu chấm phẩy sau var oof = {};.
loganfsmyth

Trong mã đầu tiên, không nên ({x: oof.x, y: oof.y} = foo)? Tôi nghĩ rằng bạn đã đặt thêm một f trong oof .
Sornii

38

Không, phá hủy không hỗ trợ các biểu thức thành viên trong các tốc ký mà chỉ có các thuộc tính đơn giản tại thời điểm hiện tại. Đã có những cuộc nói chuyện về esdiscuss như vậy, nhưng không có đề xuất nào được đưa vào ES6.

Object.assignTuy nhiên, bạn có thể sử dụng - nếu bạn không cần tất cả các thuộc tính riêng, bạn vẫn có thể làm

var foo = …,
    oof = {};
{
    let {x, y} = foo;
    Object.assign(oof, {x, y})
}

3
@loganfsmyth, ví dụ của bạn không hoạt động với tôi ít nhất là trong các thử nghiệm của tôi với nút 4.2.2. với --harmony_destructuringkích hoạt. Tôi thấy "SyntaxError: Mã thông báo bất ngờ."
jpierson 17/2/2016

@loganfsmyth bạn nên gửi câu trả lời thích hợp vì đây là một nhận xét rất hữu ích.
Sulliwane

@Sulliwane: Anh ấy đã làm như vậy (bây giờ) . Bergi, có lẽ tốt nhất nên cập nhật câu trả lời để gọi ra rằng bạn có thể sử dụng các biểu thức thành viên như được hiển thị bởi Logan. (Có thực sự là thông số kỹ thuật đã thay đổi nhiều như vậy giữa tháng 4 và tháng 6 năm 2015 không?)
TJ Crowder

@TJCrowder Không, tôi không nghĩ nó đã thay đổi, tôi đoán tôi đang nói về {oof.x, oof.y} = foo. Hoặc có lẽ tôi thực sự đã bỏ lỡ nó.
Bergi

29

IMO đây là cách dễ nhất để thực hiện những gì bạn đang tìm kiếm:

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

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

Về cơ bản, cấu trúc thành các biến và sau đó sử dụng tốc ký khởi tạo để tạo một đối tượng mới. Không cầnObject.assign

Tôi nghĩ rằng đây là cách dễ đọc nhất, dù sao đi nữa. Bạn có thể chọn các đạo cụ chính xác someObjectmà bạn muốn. Nếu bạn có một đối tượng hiện có mà bạn chỉ muốn hợp nhất các đạo cụ vào, hãy làm một cái gì đó như thế này:

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

Một cách khác, được cho là sạch hơn, cách viết là:

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

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

Tôi sử dụng điều này cho POSTcác yêu cầu rất nhiều trong đó tôi chỉ cần một vài dữ liệu rời rạc. Nhưng, tôi đồng ý nên có một lớp lót để làm điều này.

EDIT: PS - Gần đây tôi đã biết rằng bạn có thể sử dụng siêu phá hủy trong bước đầu tiên để kéo các giá trị lồng nhau ra khỏi các đối tượng phức tạp! Ví dụ...

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

Ngoài ra, bạn có thể sử dụng toán tử trải rộng thay vì Object.assign khi tạo một đối tượng mới:

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

Hoặc là...

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

Tôi thích cách tiếp cận này, thực dụng.
Jesse

2
Đây là những gì tôi làm nhưng nó không khô lắm. Tôi nghĩ rằng những gì nhiều người thực sự cần chỉ là một chức năng giải nén.
jgmjgm

@jgmjgm yeah, thật tuyệt khi có một cái được xây dựng nhưng tôi đoán rằng nó cũng không quá khó để viết.
Zfalen

12

Khác với Object.assignđó là các đối tượng lây lan cú pháp mà là một đề nghị Giai đoạn 2 cho ECMAScript.

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

var oof = { z: "z" }

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

console.log(oof)

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

Nhưng để sử dụng tính năng này, bạn cần sử dụng stage-2hoặc transform-object-rest-spreadplugin cho babel. Dưới đây là bản demo về babel vớistage-2


9
Điều này không thực sự đặt các thuộc tính trên đối tượng hiện có, mà là tạo ra một đối tượng mới chứa tất cả các thuộc tính của cả hai.
Matt Browne

8

Plugin BabelJS

Nếu bạn đang sử dụng BabelJS, bây giờ bạn có thể kích hoạt plugin của tôi babel-plugin-transform-object-from-destructuring( xem gói npm để cài đặt và sử dụng ).

Tôi đã có cùng một vấn đề được mô tả trong chủ đề này và đối với tôi, nó rất mệt mỏi khi bạn tạo một đối tượng từ một biểu thức phá hủy, đặc biệt là khi bạn phải đổi tên, thêm hoặc xóa một thuộc tính. Với plugin này, việc duy trì các kịch bản như vậy sẽ dễ dàng hơn cho bạn.

Ví dụ đối tượng

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

có thể được viết như:

let myTest = { test1, test3 } = myObject;

Ví dụ mảng

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

có thể được viết như:

let myTest = [ test1, , test3 ] = myArray;

Đây chính xác là những gì tôi muốn. Cảm ơn bạn!
garrettmaring

let myTest = { test1, test3 } = myObject;không hoạt động
Eatdoku


3

Bạn chỉ có thể sử dụng tái cấu trúc cho điều đó như thế này:

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

Hoặc hợp nhất cả hai đối tượng nếu oof có giá trị:

const foo = {x:"a", y:"b"};
let oof = {z:"c"}
oof = Object.assign({}, oof, foo)

Tôi nghĩ rằng trường hợp đầu tiên này là chính xác những gì tôi đang tìm kiếm. Tôi đã thử nó trong giao diện điều khiển chrome và nó dường như hoạt động. Chúc mừng! @campafari
MajorBummer

1
@majorBummer Cuộc gọi của bạn cuối cùng, nhưng tôi xem xét cách tiếp cận để không thực sự trả lời câu hỏi của bạn, bởi vì cả hai đều tạo đối tượng mới , thay vì thêm thuộc tính vào các đối tượng hiện tại như tiêu đề của bạn yêu cầu.
loganfsmyth

Đó là một điểm tốt @loganfsmyth. Tôi nghĩ rằng tôi đã rất phấn khích với phương pháp campSafari đưa ra bởi vì tôi đã không nhận ra rằng điều đó là có thể.
MajorBummer

1
Nếu bạn không ngại tạo một đối tượng mới, bạn có thể làmoof = {...oof, ...foo}
Joshua Coady

2

Bạn có thể trả về đối tượng bị phá hủy trong hàm mũi tên và sử dụng Object.assign () để gán nó cho một biến.

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

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

1

KHÔ

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 }

hoặc là

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

1

Bạn có thể hủy một đối tượng gán trực tiếp cho thuộc tính đối tượng khác.

Ví dụ làm việc:

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

Bạn có thể làm việc với việc hủy bằng cách sử dụng các biến có cùng tên thuộc tính đối tượng bạn muốn bắt, theo cách này bạn không cần phải làm:

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

Sử dụng theo cách này:

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

Giống như cách bạn có thể đặt giá trị mới cho cấu trúc đối tượng nếu chúng có cùng tên thuộc tính.

Nhìn ví dụ làm việc này:

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

Điều này hoạt động trong 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
Đáng buồn thay, có vẻ như oofchỉ nhận được một tài liệu tham khảo foovà bỏ qua toàn bộ sự phá hủy (ít nhất là trong Chrome). oof === foolet oof = { x } = foovẫn quay trở lại{ x, y }
Theo.T

@ Theo.T bắt tốt. đó là một người lập dị, tôi sẽ phải tìm một cách khác
user1577390

Những cái này đáng để giữ chỉ để chứng minh làm thế nào JS có thể gây nhầm lẫn.
jgmjgm

0

Tôi đã đưa ra phương pháp này:

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

Mà bạn có thể sử dụng như thế này:

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

tức là, bạn có thể chọn thuộc tính nào bạn muốn và đặt chúng vào một đối tượng mới. không giống_.pick bạn cũng có thể đổi tên chúng cùng một lúc.

Nếu bạn muốn sao chép các đạo cụ vào một đối tượng hiện có, chỉ cần đặt destarg.


0

Đây là một loại gian lận, nhưng bạn có thể làm một cái gì đó như thế này ...

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

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

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

Trong thực tế, tôi nghĩ rằng bạn hiếm khi muốn sử dụng điều đó mặc dù. Sau đây là rõ ràng hơn ... nhưng gần như không vui vẻ.

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

Một tuyến đường hoàn toàn khác, bao gồm mucking với nguyên mẫu (cẩn thận ngay bây giờ ...):

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

Đây là giải pháp dễ đọc và ngắn gọn nhất tôi có thể nghĩ ra:

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

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

console.log(newProps);

Nó sẽ xuất { isValidDate: 'yes' }

Sẽ thật tốt nếu một ngày nào đó có thể nói điều gì đó như thế let newProps = ({ isValidDate } = props)nhưng thật không may, đó không phải là thứ ES6 hỗ trợ.


0

Đó không phải là một cách hay, tôi cũng không khuyên bạn, nhưng nó có thể theo cách này, chỉ vì kiến ​​thức.

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

Bạn có thể sử dụng các phương thức lớp JSON để đạt được nó như sau

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

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

Truyền các thuộc tính cần được thêm vào đối tượng kết quả dưới dạng đối số thứ hai để stringifyhoạt động ở định dạng mảng.

MDN Doc cho JSON.opesify

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.