변형없이 객체에서 값 제거


101

원래 객체를 변경하지 않고 특정 키의 객체에서 값을 제거하는 좋고 짧은 방법은 무엇입니까?

다음과 같은 작업을하고 싶습니다.

let o = {firstname: 'Jane', lastname: 'Doe'};
let o2 = doSomething(o, 'lastname');
console.log(o.lastname); // 'Doe'
console.log(o2.lastname); // undefined

그러한 작업을위한 많은 불변성 라이브러리가 있다는 것을 알고 있지만 라이브러리 없이는 빠져 나가고 싶습니다. 그러나 이렇게하려면 유틸리티 함수로 메서드를 추상화하지 않고도 코드 전체에서 사용할 수있는 쉽고 짧은 방법이 필요합니다.

예를 들어 값을 추가하려면 다음을 수행합니다.

let o2 = {...o1, age: 31};

이것은 매우 짧고 기억하기 쉬우 며 유틸리티 기능이 필요하지 않습니다.

값을 제거하기 위해 이와 같은 것이 있습니까? ES6는 매우 환영합니다.

대단히 감사합니다!


"객체를 변경하지 않고 값 제거"는 의미가 없습니다. 당신은 무언가에서 제거하는 동시에 그것을 그대로 유지할 수 없습니다. 실제로하고있는 것은 부분 복사를하는 것입니다.
JJJ

답변:


224

최신 정보:

까다로운 Destructuring 할당으로 객체에서 속성을 제거 할 수 있습니다 .

const doSomething = (obj, prop) => {
  let {[prop]: omit, ...res} = obj
  return res
}

그러나 제거하려는 속성 이름이 정적 인 경우 간단한 한 줄로 제거 할 수 있습니다.

let {lastname, ...o2} = o

가장 쉬운 방법은 간단히 또는 개체를 변경하기 전에 복제 할 수 있습니다.

const doSomething = (obj, prop) => {
  let res = Object.assign({}, obj)
  delete res[prop]
  return res
}

또는 유틸리티 라이브러리의 omit함수를lodash 사용할 수 있습니다 .

let o2 = _.omit(o, 'lastname')

lodash 패키지 의 일부 또는 독립형 lodash.omit 패키지로 사용할 수 있습니다.


3
정말 가장 간단한 해결책입니까? 예를 들어 배열의 a2 = a1.filter(el => el.id !== id)경우 특정 ID로 배열 내의 요소를 생략 할 수 있습니다 . 객체에 그런 것이 없습니까?
amann

1
@amann에 동의합니다. 어느 쪽이 있다 더 나은 솔루션, 또는 ES6 정말 더 많은 기능 방식으로 JS의 사용 가능한을 만들기에 대해 뭔가를 놓쳤다. 예 : Ruby haskeep_if
Augustin Riedinger 2016

1
@AugustinRiedinger 실제로 방법이 있습니다. 내 업데이트를 참조하십시오.
Leonid Beschastny

1
업데이트 된 구조 분해 솔루션은 훌륭합니다. 내 마음은 약간 충격을 받았지만. 왜 const {[prop], ...rest} = obj작동 하지 않습니까? 추출 된 속성을 새 변수 ( omit이 경우) 에 할당해야하는 이유는 무엇 입니까?
branweb

1
@ Antoni4 no-unused-vars규칙 에 "생략"또는 "생략"을 추가 할 수 있습니다 . 정규식 일뿐입니다.
adrianmc

33

ES7 객체 구조화 사용 :

const myObject = {
  a: 1,
  b: 2,
  c: 3
};
const { a, ...noA } = myObject;
console.log(noA); // => { b: 2, c: 3 }

1
a변수에 저장 되면 const x = 'a'어떨까요?
FFF

아무것도 변경하지 않습니다. a는 배열의 첫 번째 요소만을 나타냅니다. 다음과 같을 수 있습니다. const { a,b, ...noA } = myObject; console.log(noA); // => {c: 3 }
senbon

1
이것은 가장 우아하게, 간단한 해결책이다

1
키가 숫자 인 경우이를 수행하는 방법이 있습니까?
Marc Sloth Eastman


4

위의 설명에서 제안한대로 objectI like to use 에서 둘 이상의 항목을 제거하기 위해 이것을 확장 하려면 filter. 과reduce

예 :

    const o = {
      "firstname": "Jane",
      "lastname": "Doe",
      "middlename": "Kate",
      "age": 23,
      "_id": "599ad9f8ebe5183011f70835",
      "index": 0,
      "guid": "1dbb6a4e-f82d-4e32-bb4c-15ed783c70ca",
      "isActive": true,
      "balance": "$1,510.89",
      "picture": "http://placehold.it/32x32",
      "eyeColor": "green",
      "registered": "2014-08-17T09:21:18 -10:00",
      "tags": [
        "consequat",
        "ut",
        "qui",
        "nulla",
        "do",
        "sunt",
        "anim"
      ]
    };

    const removeItems = ['balance', 'picture', 'tags']
    console.log(formatObj(o, removeItems))

    function formatObj(obj, removeItems) {
      return {
        ...Object.keys(obj)
          .filter(item => !isInArray(item, removeItems))
          .reduce((newObj, item) => {
            return {
              ...newObj, [item]: obj[item]
            }
          }, {})
      }
    }

    function isInArray(value, array) {
      return array.indexOf(value) > -1;
    }


1
리 듀스에 필터 조건을 적용하면 루프 하나를 절약 할 수있는 이유는 무엇입니까?
Ivo Sabev

@IvoSabev 팁에 감사드립니다. 내 코드에 몇 가지 기능이 있습니다. 필터링 한 다음 줄이지 만 루프를 저장하기 위해 앞으로의 제안을 고려할 것입니다.
ak85

4

성능을 가져 오는 향신료를 추가합니다. 이 스레드 벨로우즈 확인

https://github.com/googleapis/google-api-nodejs-client/issues/375

delete 연산자를 사용하면 V8 히든 클래스 패턴에 성능이 저하됩니다. 일반적으로 사용하지 않는 것이 좋습니다.

또는 개체 고유의 열거 가능한 속성을 제거하려면 해당 속성없이 새 개체 복사본을 만들 수 있습니다 (lodash 사용 예제).

_.omit (o, 'prop', 'prop2')

또는 속성 값을 null 또는 undefined (JSON으로 직렬화 할 때 암시 적으로 무시 됨)로 정의 할 수도 있습니다.

o.prop = 정의되지 않음

파괴적인 방법도 사용할 수 있습니다.

const {remov1, remov2, ...new} = old;
old = new;

그리고 더 실용적인 예 :

this._volumes[this._minCandle] = undefined;
{ 
     const {[this._minCandle]: remove, ...rest} = this._volumes;
     this._volumes = rest; 
}

보시다시피 [somePropsVarForDynamicName]: scopeVarName동적 이름에 구문을 사용할 수 있습니다 . 그리고 모든 것을 대괄호 (새 블록)로 묶어 나머지는 가비지 수집됩니다.

여기 테스트 : 여기에 이미지 설명 입력

exec :

여기에 이미지 설명 입력

또는 다음과 같은 기능을 사용할 수 있습니다.

function deleteProps(obj, props) {
    if (!Array.isArray(props)) props = [props];
    return Object.keys(obj).reduce((newObj, prop) => {
        if (!props.includes(prop)) {
            newObj[prop] = obj[prop];
        }
        return newObj;
    }, {});
}

타이프 스크립트 용

function deleteProps(obj: Object, props: string[]) {
    if (!Array.isArray(props)) props = [props];
    return Object.keys(obj).reduce((newObj, prop) => {
        if (!props.includes(prop)) {
            newObj[prop] = obj[prop];
        }
        return newObj;
    }, {});
}

용법:

let a = {propH: 'hi', propB: 'bye', propO: 'ok'};

a = deleteProps(a, 'propB'); 

// or 

a = deleteProps(a, ['propB', 'propO']);

이렇게하면 새 개체가 생성됩니다. 그리고 물체의 빠른 속성이 유지됩니다. 중요하거나 중요 할 수 있습니다. 매핑 및 개체에 여러 번 액세스하는 경우.

또한 연결 undefined하는 것도 좋은 방법이 될 수 있습니다. 당신이 그것을 감당할 수있을 때. 키의 경우 값도 확인할 수 있습니다. 예를 들어 모든 활성 키를 얻으려면 다음과 같이하십시오.

const allActiveKeys = Object.keys(myObj).filter(k => myObj[k] !== undefined);
//or
const allActiveKeys = Object.keys(myObj).filter(k => myObj[k]); // if any false evaluated value is to be stripped.

Undefined는 큰 목록에는 적합하지 않습니다. 또는 많은 소품이 들어 오면서 시간이 지남에 따라 개발됩니다. 메모리 사용량이 계속 증가하고 정리되지 않을 것입니다. 따라서 사용법에 따라 다릅니다. 그리고 새로운 개체를 만드는 것이 좋은 방법 인 것 같습니다.

그런 다음 Premature optimization is the root of all evil의지가 시작됩니다. 따라서 트레이드 오프를 인식해야합니다. 필요한 것과 그렇지 않은 것.

lodash의 _.omit ()에 대한 참고 사항

버전 5에서 제거되었습니다. repo에서 찾을 수 없습니다. 그리고 여기에 그것에 대해 이야기하는 문제가 있습니다.

https://github.com/lodash/lodash/issues/2930

v8

https://v8.dev/blog/fast-properties 좋은 읽기를 확인할 수 있습니다.


1

ESLint 규칙 표준에서 받아 들여지는 대답에 대한 내 문제는 다음과 같습니다.

    const { notNeeded, alsoNotNeeded, ...rest } = { ...ogObject };

2 개 개의 새로운 변수, notNeeded그리고 alsoNotNeeded그들이 지금은 사용되지 않는 이후 설정에 따라 경고 또는 오류가 발생 할 수 있습니다. 그렇다면 왜 사용하지 않는 경우 새 변수를 생성합니까?

delete기능을 진정으로 사용해야한다고 생각합니다 .


4
no-unused-vars규칙은 실제로 옵션이 있습니다 ignoreRestSiblings:이 사용 사례를 다루 지금 eslint.org/docs/rules/no-unused-vars#ignorerestsiblings
AMANN

0

lodash cloneDeep 및 삭제

(참고 : 얕은 개체 대신 lodash 복제를 사용할 수 있습니다.)

const obj = {a: 1, b: 2, c: 3}
const unwantedKey = 'a'

const _ = require('lodash')
const objCopy = _.cloneDeep(obj)
delete objCopy[unwantedKey]
// objCopy = {b: 2, c: 3}

0

내 코드의 경우 map ()의 반환 값에 대한 짧은 버전을 원했지만 여러 줄 / 다중 작업 솔루션은 "추악"했습니다. 주요 기능은 오래 void(0)되는 결의 undefined.

let o2 = {...o, age: 31, lastname: void(0)};

속성은 객체에 유지됩니다.

console.log(o2) // {firstname: "Jane", lastname: undefined, age: 31}

그러나 전송 프레임 워크는 나를 위해 그것을 죽입니다 (bc stringify).

console.log(JSON.stringify(o2)) // {"firstname":"Jane","age":31}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.