変更なしでオブジェクトから値を削除します


96

元のオブジェクトを変更せずに、特定のキーのオブジェクトから値を削除するための良い方法は何ですか?

私は次のようなことをしたいと思います:

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 2015年

回答:


215

更新:

トリッキーなDestructuring割り当てを使用して、オブジェクトからプロパティを削除できます。

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

ただし、削除するプロパティ名が静的な場合は、単純な1行で削除できます。

let {lastname, ...o2} = o

最も簡単な方法は、単に変更するか、オブジェクトを変更する前にオブジェクトを複製することです。

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

またはomitlodashユーティリティライブラリの関数を使用することもできます。

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

lodashパッケージの一部として、またはスタンドアロンのlodash.omitパッケージとして入手できます。


3
それは本当に最も簡単な解決策ですか?たとえば、配列の場合a2 = a1.filter(el => el.id !== id)、特定のIDで配列内の要素を省略することができます。オブジェクトにはそのようなものはありませんか?
amann

1
@amannに同意します。どちらかがあるより良いソリューション、またはES6は本当に多くの機能的な方法でJSを使用可能にすることについて何かを逃しました。例えば。Rubyが持っているkeep_if
Augustin Riedinger

1
@AugustinRiedinger実際には、方法があります。私のアップデートを見てください。
Leonid Beschastny 2016

私はこの質問に同じ応じて提案するつもりだった:stackoverflow.com/questions/35152522/...
オーギュRiedinger

1
更新された解体ソリューションは素晴らしいです。私の心はそれによって少し吹き飛ばされていますが。なぜconst {[prop], ...rest} = obj動作しないのですか?抽出したプロパティを新しい変数に割り当てる必要があるのはなぜですか(omitこの場合)。
branweb 2017

28

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 2018

何も変更しません。aは、配列の最初の要素のみを参照します。次のようになります const { a,b, ...noA } = myObject; console.log(noA); // => {c: 3 }
。– senbon

1
これは最もエレガントでシンプルなソリューションです
Joe

1
キーが数字の場合、これを行う方法はありますか?
Marc Sl​​oth Eastman


4

あなたからの1項目以上を削除するには、これを拡張したい場合は、上記のコメントで示唆したようにobject使用するように私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
フィルター条件をreduceに適用して、ループを1つ節約できるようにしてみませんか?
Ivo Sabev

ヒントをありがとう@IvoSabev私はコードにいくつかの関数があり、そこでフィルター処理してから削減しますが、ループを保存するための提案を検討します。
ak85

3

パフォーマンスをもたらすスパイスを追加します。このスレッドを確認してください

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

delete演算子を使用すると、V8の隠しクラスパターンのパフォーマンスが低下します。一般に、使用しないことをお勧めします。

あるいは、オブジェクト自身の列挙可能なプロパティを削除するために、それらのプロパティなしで新しいオブジェクトのコピーを作成できます(lodashを使用した例):

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

または、プロパティ値をnullまたは未定義に定義することもできます(JSONへのシリアル化時に暗黙的に無視されます)。

o.prop = undefined

あなたも破壊的な方法を使うことができます

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.

未定義は大きなリストには適していません。または、多くの小道具が登場する時間の経過に伴う開発。メモリ使用量は増加し続け、クリーンアップされないため。したがって、使用方法によって異なります。そして、新しいオブジェクトを作成するだけでも良い方法のようです。

次に、Premature optimization is the root of all evilキックインします。したがって、トレードオフに注意する必要があります。そして必要なものと不要なもの。

lodashの_.omit()に関する注意

バージョン5から削除されました。リポジトリで見つけることができません。そして、ここでそれについて話す問題。

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

v8

あなたはこれを読むのに良いこれをチェックできますhttps://v8.dev/blog/fast-properties


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}

0

ESLintルール標準から受け入れられた回答に関する私の問題、分解しようとした場合:

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

2つの新しい変数、notNeededそしてalsoNotNeeded彼らは今使用されていないので、あなたのセットアップに応じて警告またはエラーをスローすることがあります。それで、未使用の場合はなぜ新しい変数を作成するのですか?

delete本当に関数を使う必要があると思います。


3
no-unused-varsルールは、実際にはオプションがありますignoreRestSiblings:このユースケースをカバーするために、今eslint.org/docs/rules/no-unused-vars#ignorerestsiblings
アーマン
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.