Làm cách nào tôi có thể sao chép một đối tượng JavaScript ngoại trừ một khóa?


308

Tôi có một đối tượng JS phẳng:

{a: 1, b: 2, c: 3, ..., z:26}

Tôi muốn sao chép đối tượng ngoại trừ một yếu tố:

{a: 1, c: 3, ..., z:26}

Cách dễ nhất để làm điều này (thích sử dụng es6 / 7 nếu có thể)?


Không thay đổi đối tượng ban đầu: JSON.parse (JSON.opesify ({... obj, 'key2': không xác định}))
infinite1975

Câu trả lời:


441

Nếu bạn sử dụng Babel, bạn có thể sử dụng cú pháp sau để sao chép thuộc tính b từ x vào biến b và sau đó sao chép phần còn lại của thuộc tính vào biến y :

let x = {a: 1, b: 2, c: 3, z:26};
let {b, ...y} = x;

nó sẽ được dịch vào:

"use strict";

function _objectWithoutProperties(obj, keys) {
  var target = {};
  for (var i in obj) {
    if (keys.indexOf(i) >= 0) continue;
    if (!Object.prototype.hasOwnProperty.call(obj, i)) continue;
    target[i] = obj[i];
  }
  return target;
}

var x = { a: 1, b: 2, c: 3, z: 26 };
var b = x.b;

var y = _objectWithoutProperties(x, ["b"]);

58
Nếu bạn lint mã của bạn cho các biến không được sử dụng, điều này sẽ dẫn đến một "biến không sử dụng 'b'." cảnh báo mặc dù.
Ross Allen

1
cú pháp sẽ trông như thế nào nếu bạn cólet x = [{a: 1, b: 2, c: 3, z:26}, {a: 5, b: 6, c: 7, z:455}];
ke3pup

14
@RossAllen Có một tùy chọn ignoreRestSiblingsđã được thêm vào v3.15.0 (ngày 3 tháng 2 năm 2017). Xem: cam kết c59a0ba
Ilya Palkin

4
@IlyaPalkin Thú vị. Mặc dù vậy, nó cảm thấy hơi lười biếng vì nó không thay đổi thực tế là có một bphạm vi.
Ross Allen

2
Nếu bạn đang xây dựng Mô-đun không thành công: SyntaxError: Mã thông báo không mong muốn, có lẽ bạn cần thêm plugin chuyển đổi phần còn lại của babel. Xem babeljs.io/docs/plugins/transform-object-rest-s lây lan
jsaven

133
var clone = Object.assign({}, {a: 1, b: 2, c: 3});
delete clone.b;

hoặc nếu bạn chấp nhận tài sản không xác định:

var clone = Object.assign({}, {a: 1, b: 2, c: 3}, {b: undefined});

7
Đơn giản chỉ cần xóa tài sản là một cách rõ ràng và đơn giản để làm điều đó.
sshow

24
Nhắc nhở với xóa là nó không phải là một hoạt động bất biến.
Javid Jamae

1
cái này giữ chìa khóa
Fnamed Alnamrouti

1
Nhận xét của tôi đã được viết trước khi anh ấy chỉnh sửa câu trả lời của mình và thêm câu lệnh xóa
Fareed Alnamrouti

Đây chính xác là những gì tôi đang tìm kiếm, nhưng được thực hiện nhiều hơn theo một cách hơi khác: var cake = {... currentCake, requestorId: không xác định};
abelito

73

Để thêm vào câu trả lời của Ilya Palkin: bạn thậm chí có thể tự động xóa các phím:

const x = {a: 1, b: 2, c: 3, z:26};

const objectWithoutKey = (object, key) => {
  const {[key]: deletedKey, ...otherKeys} = object;
  return otherKeys;
}

console.log(objectWithoutKey(x, 'b')); // {a: 1, c: 3, z:26}
console.log(x); // {a: 1, b: 2, c: 3, z:26};

Bản demo trong Babel REPL

Nguồn:


3
Đây là một cú pháp tốt đẹp.
Hinrich

2
Điều này thật tuyệt, nhưng có cách nào để tránh varKeyKey không được sử dụng không? Không phải là nó gây ra bất kỳ vấn đề nào, nhưng làm cho JSHint phàn nàn và có vẻ kỳ lạ vì chúng tôi thực sự không sử dụng nó.
Johnson Wong

6
@JohnsonWong Làm thế nào về việc sử dụng _được phép cho một biến mà bạn không có ý định sử dụng?
Ryan H.

var b = {a:44, b:7, c:1}; let {['a']:z, ...others} = b; console.log(z , others ); // logs: 44, {b:7, c:1}
jimmont

70

Đối với những người không thể sử dụng ES6, bạn có thể sử dụng lodashhoặc underscore.

_.omit(x, 'b')

Hoặc ramda.

R.omit('b', x)

6
Sẽ không hợp lý hơn khi sử dụng bỏ qua ở đây? _.omit(x, 'b')
tibalt

Cảm ơn @tibalt. Cập nhật câu trả lời với nó.
Noel Llevares

xóa là ngắn gọn hơn - sử dụng lodash, gạch dưới hoặc ramda chỉ liên quan đến các dự án đã sử dụng và biết chúng, nếu không điều này ngày càng không liên quan trong năm 2018 và hơn thế nữa.
jimmont

1
@jimmont xóa đã được đề cập trong các câu trả lời khác. Không cần câu trả lời trùng lặp, bạn nghĩ sao? Và tất nhiên, nó chỉ liên quan đến những người đã sử dụng lodash hoặc ramda. Và nó cũng chỉ liên quan đến những người mắc kẹt với ES5 và trước đó như đã nêu trong câu trả lời này.
Noel Llevares

@dashmug Nhận xét trước đây của tôi là một lời chỉ trích về cách tiếp cận (không phải câu trả lời của bạn) cần được lưu ý khi chọn sử dụng phương pháp được trình bày trong câu trả lời này. Tôi sẽ muốn thông tin này nếu tôi đang đọc qua các câu trả lời và là lý do để thêm nhận xét và đề cập của tôi delete.
jimmont

63

Tôi sử dụng ESNext một lớp lót này

const obj = { a: 1, b: 2, c: 3, d: 4 }
const clone = (({ b, c, ...o }) => o)(obj) // remove b and c
console.log(clone)


Nếu bạn cần một chức năng mục đích chung:

function omit(obj, props) {
  props = props instanceof Array ? props : [props]
  return eval(`(({${props.join(',')}, ...o}) => o)(obj)`)
}

// usage
const obj = { a: 1, b: 2, c: 3, d: 4 }
const clone = omit(obj, ['b', 'c'])
console.log(clone)


9
Thay vì gói trong mảng và mapbạn có thể làm:(({b, c, ...others}) => ({...others}))(obj)
bucabay 22/12/18

@bucabay: Rực rỡ! Đó là câu trả lời tốt nhất trong số rất nhiều! Tuân thủ tiêu chuẩn, hoạt động hoàn hảo trong Node, v.v. Bạn nên gửi dưới dạng câu trả lời.
david.pfx

3
Người bạn đời trả lời tuyệt vời .. <3
Ajithkumar S

5
@totymedli: Không phải do tôi. Tôi sẽ sử dụng hình thức cú pháp, một phần của ES6 tiêu chuẩn, qua chức năng ma thuật bất cứ lúc nào, trên cơ sở dễ đọc.
david.pfx

1
Xuất sắc. Đó là tất cả.
darksoulsong

22

Bạn có thể viết một hàm trợ giúp đơn giản cho nó. Lodash có chức năng tương tự có cùng tên: bỏ qua

function omit(obj, omitKey) {
  return Object.keys(obj).reduce((result, key) => {
    if(key !== omitKey) {
       result[key] = obj[key];
    }
    return result;
  }, {});
}

omit({a: 1, b: 2, c: 3}, 'c')  // {a: 1, b: 2}

Ngoài ra, lưu ý rằng nó nhanh hơn Object.assign và xóa sau đó: http://jsperf.com/omit-key


11

Có lẽ một cái gì đó như thế này:

var copy = Object.assign({}, {a: 1, b: 2, c: 3})
delete copy.c;

Điều này có đủ tốt không? Hoặc cthực sự không thể được sao chép?


11

Sử dụng phá hủy đối tượng

const omit = (prop, { [prop]: _, ...rest }) => rest;
const obj = { a: 1, b: 2, c: 3 };
const objWithoutA = omit('a', obj);
console.log(objWithoutA); // {b: 2, c: 3}


Giải pháp tuyệt vời!
Denys Mikhalenko

2
Tôi đoán giải pháp này có nghĩa là để ngăn cảnh báo 'Biến không sử dụng' trong JSLint. Thật không may, việc sử dụng _không giải quyết được vấn đề cho ESLint ...
bert bruynooghe

6

Hey có vẻ như bạn chạy vào tham chiếu các vấn đề khi bạn đang cố sao chép một đối tượng sau đó xóa một thuộc tính. Ở đâu đó bạn phải gán các biến nguyên thủy để javascript tạo ra một giá trị mới.

Thủ thuật đơn giản (có thể là khủng khiếp) Tôi đã sử dụng là

var obj = {"key1":"value1","key2":"value2","key3":"value3"};

// assign it as a new variable for javascript to cache
var copy = JSON.stringify(obj);
// reconstitute as an object
copy = JSON.parse(copy);
// now you can safely run delete on the copy with completely new values
delete copy.key2

console.log(obj)
// output: {key1: "value1", key2: "value2", key3: "value3"}
console.log(copy)
// output: {key1: "value1", key3: "value3"}

Tôi thực sự thích nó. Có thể làm JSON.parse(JSON.stringify(Object.assign({}, obj, { key2: undefined })));. Thậm chí không phải xóa nó, chỉ cần một giá trị giả.
Chad

6

Đây là một tùy chọn để bỏ qua các khóa động mà tôi tin rằng chưa được đề cập:

const obj = { 1: 1, 2: 2, 3: 3, 4: 4 };
const removeMe = 1;

const { [removeMe]: removedKey, ...newObj } = obj;

removeMeđược đặt bí danh là removedKeyvà bỏ qua. newObjtrở thành { 2: 2, 3: 3, 4: 4 }. Lưu ý rằng khóa đã xóa không tồn tại, giá trị không chỉ được đặt thành undefined.


Giải pháp tốt đẹp. Tôi đã có một trường hợp sử dụng tương tự (khóa động trong bộ giảm tốc).
ericgio

4

CÁCH DỄ DÀNG NHẤT

const allAlphabets = {a: 1, b: 2, c: 3, ..., z:26};
const { b, ...allExceptOne } = allAlphabets;
console.log(allExceptOne);   // {a: 1, c: 3, ..., z:26}

3

Bỏ qua

let source = //{a: 1, b: 2, c: 3, ..., z:26}
let copySansProperty = _.omit(source, 'b');
// {a: 1, c: 3, ..., z:26}

vâng, Lodash là một lựa chọn thanh lịch, nhưng tôi đã cố gắng để đạt được cùng với vani ES6
andreasonny83

3

Bạn cũng có thể sử dụng toán tử lây lan để làm điều này

const source = { a: 1, b: 2, c: 3, z: 26 }
const copy = { ...source, ...{ b: undefined } } // { a: 1, c: 3, z: 26 }

2
Có vẻ siêu tiện lợi. Tuy nhiên, điều này giữ cho khóa là không xác định trongcopy
kano

vì vậy bạn có thể xóa các khóa không xác định nếu có những phím duy nhất ở đó
Victor

1
không chắc chắn lý do tại sao bạn thực hiện thêm phần lan truyền trong bản sao, const copy = { ...source, b: undefined } hoàn toàn giống nhau.
bert bruynooghe

3

Các giải pháp trên sử dụng cấu trúc bị ảnh hưởng bởi thực tế là bạn có một biến được sử dụng, điều này có thể gây ra khiếu nại từ ESLint nếu bạn đang sử dụng biến đó.

Vì vậy, đây là giải pháp của tôi:

const src = { a: 1, b: 2 }
const result = Object.keys(src)
  .reduce((acc, k) => k === 'b' ? acc : { ...acc, [k]: src[k] }, {})

Trên hầu hết các nền tảng (trừ IE trừ khi sử dụng Babel), bạn cũng có thể thực hiện:

const src = { a: 1, b: 2 }
const result = Object.fromEntries(
  Object.entries(src).filter(k => k !== 'b'))


2

Nếu bạn đang xử lý một biến lớn, bạn không muốn sao chép nó và sau đó xóa nó, vì điều này sẽ không hiệu quả.

Một vòng lặp đơn giản với kiểm tra hasOwnProperty sẽ hoạt động và nó thích ứng hơn nhiều với các nhu cầu trong tương lai:

for(var key in someObject) {
        if(someObject.hasOwnProperty(key) && key != 'undesiredkey') {
                copyOfObject[key] = someObject[key];
        }
}

1
Giải pháp toán tử trải rộng thực hiện chính xác như vậy với cú pháp đẹp hơn.
david.pfx

2

Cái này thì sao? Tôi không bao giờ tìm thấy cái này xung quanh nhưng tôi chỉ cố gắng loại trừ một hoặc nhiều thuộc tính mà không cần tạo thêm một đối tượng. Điều này dường như để thực hiện công việc nhưng có một số tác dụng phụ tôi không thể nhìn thấy. Để chắc chắn là không dễ đọc.

const postData = {
   token: 'secret-token',
   publicKey: 'public is safe',
   somethingElse: true,
};

const a = {
   ...(({token, ...rest} = postData) => (rest))(),
}

/**
a: {
   publicKey: 'public is safe',
   somethingElse: true,
}
*/

2

Tôi đã hoàn thành nó theo cách này, như một ví dụ từ bộ giảm tốc Redux của tôi:

 const clone = { ...state };
 delete clone[action.id];
 return clone;

Nói cách khác:

const clone = { ...originalObject } // note: original object is not altered
delete clone[unwantedKey]           // or use clone.unwantedKey or any other applicable syntax
return clone                        // the original object without the unwanted key

Có vẻ như rất nhiều công việc phụ, so với câu trả lời được chấp nhận từ 3 năm trước (và cả hai tùy chọn đều dựa vào việc chuyển mã cho nhiều trình duyệt).
Carpiediem

Tôi có một trường hợp sử dụng tương tự (bộ giảm tốc) vì vậy tôi đã nghĩ ra một cách hay, hỗ trợ các phím động mà không bị đột biến. Về cơ bản: const { [removeMe]: removedKey, ...newObj } = obj;- xem câu trả lời của tôi về câu hỏi này.
goldins

1

Gần đây tôi đã làm điều này rất đơn giản:

const obj = {a: 1, b: 2, ..., z:26};

chỉ sử dụng toán tử trải để phân tách thuộc tính không mong muốn:

const {b, ...rest} = obj;

... Và object.assign chỉ lấy phần 'phần còn lại':

const newObj = Object.assign({}, {...rest});

3
restđã là một đối tượng mới - bạn không cần dòng cuối cùng. Thêm vào đó, đây là giống hệt với giải pháp được chấp nhận.
Carpiediem

0
const x = {obj1: 1, pass: 2, obj2: 3, obj3:26};

const objectWithoutKey = (object, key) => {
  const {[key]: deletedKey, ...otherKeys} = object;
  return otherKeys;
}

console.log(objectWithoutKey(x, 'pass'));

1
Mặc dù mã này có thể cung cấp một giải pháp cho câu hỏi, tốt hơn hết là thêm ngữ cảnh vào lý do tại sao / cách thức hoạt động của nó. Điều này có thể giúp người dùng trong tương lai tìm hiểu và áp dụng kiến ​​thức đó vào mã của riêng họ. Bạn cũng có thể có phản hồi tích cực từ người dùng dưới dạng upvote, khi mã được giải thích.
borchvm
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.