かもメモ

自分の落ちた落とし穴に何度も落ちる人のメモ帳

JavaScript 特定のプロパティを削除した新しいオブジェクトを返したい

delete メソッドとかで Array.filter みたいな感じで、 state の中から特定のプロパティを削除して新しいオブジェクトを返したい。

1. Object.assign() で オブジェクトをコピーして delete

JavaScriptdelete 演算子は破壊的なので、 Object.assign() でオブジェクトをコピーしてから使えばOK。

const Tristar = {
  leader: '神崎美月',
  member1: '一ノ瀬かえで',
  member2: '紫吹蘭',
};

const omitProperty = (obj) => (key) => {
  const clone = Object.assign(obj);
  delete clone[key];
  return clone;
}

omitProperty(Tristar)('member2');
// => {leader: "神崎美月", member1: "一ノ瀬かえで"}

紫吹蘭ちゃんさん… 。゚(゚´ω`゚)゚。

シンプルにOK

2. 分割代入 ( Destructuring assignment ) で除外する

{ deleteKey, ...newObject } = Object で特定のプロパティを分離できるので、これを利用できそうです。
分割代入構文は {key: var_name, ...others} = object のようにすると、分割したプロパティの変数名を指定することが出来ます。

e.g.

const obj = { x:1, y:2, z:3 };
const { x: _, ...data } = obj;
console.log(_); // => 1
console.log(x); // => ReferenceError: x is not defined

👇実装

const Tristar = {
  leader: '神崎美月',
  member1: '一ノ瀬かえで',
  member2: '紫吹蘭',
};

const omitProperty = (obj) => (key) => {
  const { [key]: _, ...newObjct} = obj;
  return newObjct;
}

omitProperty(Tristar)('member2');
// => {leader: "神崎美月", member1: "一ノ瀬かえで"}

// 存在しないプロパティの場合も問題なし
omitProperty(Tristar)('member3');
// => {leader: "神崎美月", member1: "一ノ瀬かえで", member2: "紫吹蘭"}

いい感じですが、 _ という未使用の変数が出来てしまうので eslint で no-unused-vars のアラートが出ちゃったりして、ぐぬぬ…という感じです。

{ key: {}, ...others } = object で変数を作成せずに特定のプロパティを除外できるっぽい

分割代入で取り出すプロパティの変数指定を {}[] にすると変数にならないので、単純にオブジェクトから除外できるようです。 {}, [] を指定する場合は、存在しないプロパティのキーを指定されるとエラーになるので、デフォルト引数を指定してあげる必要がるようです。
cf. 特定のプロパティを除外した新しいオブジェクトを作る(immutableなdelete) - rikubaのブログ

e.g.

const obj = { x:1, y:2, z:3 };

var { x: {}, ...data } = obj;
console.log(data); // => {y: 2, z: 3}

var { null: {}, ...data} = obj;
// => TypeError: Cannot destructure property 'null' of 'obj' as it is undefined.

var { null: {} = {}, ...data} = obj;
console.log(data); // => {x: 1, y: 2, z: 3}

色々試してみた所、変数指定は NaN, undefined でも可能で、これの場合は存在しないプロパティのキーが指定されてもデフォルト引数なしでもエラーにならないようでした。 ( null を変数に指定することはSyntaxErrorになり出来ませんでした。 )

e.g.

const obj = { x:1, y:2, z:3 };

// 変数指定を null にすることは出来ない 
var { x: null, ...data} = obj;
// => SyntaxError: Invalid destructuring assignment target

var { x: NaN, ...data} = obj;
console.log(data); // => {y: 2, z: 3}
var { null: NaN, ...data} = obj;
console.log(data); // => {x: 1, y: 2, z: 3} デフォルト引数不要

var { x: undefined, ...data} = obj;
console.log(data); // => {y: 2, z: 3}
var { null: undefined, ...data} = obj;
console.log(data); // => {x: 1, y: 2, z: 3} デフォルト引数不要

変数を作らないので undefined にしちゃうのがデフォルト引数も不要なので直感的な用に感じました。
これを利用して分割して必要なデータを返す関数にしてしまえば、シンプルに書くことができそうです。

e.g.

const omitProperty = (obj) => (key) => {
  // プロパティ分割代入な引数で取って残りを返す関数を作成
  const omit = ({ [key]: undefined, ...newObjct}) => {
    return newObjct
  };
  return omit(obj);
};
// 👇即時関数にしてしまえば1行に
const omitProperty = (obj) => (key) => {
  return (({ [key]: undefined, ...newObjct}) => newObjct)(obj);
};

👇テスト

const Tristar = {
  leader: '神崎美月',
  member1: '一ノ瀬かえで',
  member2: '紫吹蘭',
};

const omitProperty = (obj) => (key) => {
  return (({ [key]: undefined, ...newObjct}) => newObjct)(obj);
};

omitProperty(Tristar)('member2');
// => {leader: "神崎美月", member1: "一ノ瀬かえで"}

omitProperty(Tristar)(NaN);
// => {leader: "神崎美月", member1: "一ノ瀬かえで", member2: "紫吹蘭"}

A W E S O M E .。.:・'(゚▽゚)’・:.。.
💪₍ ᐢ. ̫ .ᐢ ₎✌️

所感

eslint の no-unused-vars を ignore するしかないかなーって思ってたので、分割代入で変数指定を利用して変数を作成しないようにできる Hack は完全に盲点でした。


[参考]

_人人人人人人人人人_
> Take Me Higher <
 ̄YYYYYYYYY^ ̄