3
0

More than 1 year has passed since last update.

[JavaScript] プロパティを限定してオブジェクトのシャローコピーを行う

Last updated at Posted at 2022-03-26

次のようにオブジェクトの指定プロパティのみをコピーしたいときがあります。

const input = {
  a: "A",
  b: "B",
  c: "C",
  d: "D"
};

let output;
output = {
  a: "A",
  b: "B"
};
console.log(output); // {a: "A", b: "B"}

※let を使っているのは1ファイルで動作確認したからなので、普通はconst 使ってください。

シャローコピーしてプロパティを削除する方法

output = {...input};
delete output.c;
delete output.d;
console.log(output); // {a: "A", b: "B"}

悪くはなさそうですが、オブジェクト作ってから削除するのもどうかなと思います。

普通のオブジェクト生成

output = {
  a: input.a,
  b: input.b
};
console.log(output); // {a: "A", b: "B"}

これがごくごく普通で一般的な方法と思います。
が input や a とか b を何度も書くのもちょっと冗長に感じます。

分割代入とオブジェクト省略記法を使った書き方

let { a, b } = input;
output = { a, b };
console.log(output); // {a: "A", b: "B"}

a b を重複して書かなければいけないという問題もあるし、それ以上に a b という一時変数が生成されてしまうという問題があります。

次のように書きたいところだけど、そうすると想定した結果にならずに、output = input と同じになってしまいます。

output = {a,b} = input;
console.log(output); // {a: "A", b: "B", c: "C", d: "D"}

関数を使って分割代入とオブジェクト省略記法を使う

そこでこちらの方法。
a b を重複して書かなければいけないという問題は残ったままだけど、一時変数は外部に影響を与えない。
それなりにきれいな書き方だと思う。

output = (({ a, b }) => ({ a, b }))(input);
console.log(output); // {a: "A", b: "B"}

reduceを使う。

何やっているかわからなくなって可読性が悪そうだけど、このような書き方でも同じ出力を行うことができます。

output = 'a,b'.split(',').reduce((r, k)=>{
  r[k] = input[k];
  return r;
}, {})
console.log(output); // {a: "A", b: "B"}

こういう場合は、関数化してしまうとよいでしょう。関数化してしまえば内部実装などどうでもよいです。

const copyProp1 = (obj, propNames) => {
  return propNames.split(',').reduce((r, k)=>{
    r[k] = input[k];
    return r;
  }, {})
};

output = copyProp1(input, 'a,b');
console.log(output); // {a: "A", b: "B"}

Object.assign と map を使う

オブジェクトをそれぞれ作ってマージするというやり方でも行えます。オブジェクト生成数とマージ処理があるのでなんか遅くて無駄な気もしますが。

output = Object.assign({}, ...'a,b'.split(',').map(k=>({[k]: input[k]})))
console.log(output); // {a: "A", b: "B"}

これも、関数化してしまうと内部が読めなくても問題がないです。

const copyProp2 = (obj, propNames) => (
  Object.assign({}, ...propNames.split(',').map(k=>({[k]: obj[k]})))
);

output = copyProp2(input, 'a,b');
console.log(output); // {a: "A", b: "B"}

いろいろ対応したいなら、関数に閉じてしまえばよい。

自作の Parts.js で実装してます。

output = copyProperty(input, 'a,b');
// あるいは
output = copyProperty(input, ['a', 'b']);

主な処理のソースコードはここにあります。単に配列か文字列かで場合分けしている程度なことですが。

partsjs/_copyProperty.js at master · standard-software/partsjs
https://github.com/standard-software/partsjs/blob/master/source/object/_copyProperty.js

いろいろな引数に対応したければ、関数で書いてしまえばいいでしょう。

最後に

即時で書くときに
「関数を使って分割代入とオブジェクト省略記法を使う」のやり方もよいかもだけど
誰にでも読みやすいということを考えると
「普通のオブジェクト生成」のやり方が一番いいかもしれません。

何かの参考になったら、LGTMください。

もっとこんな風なやり方あるよ、とかあったら教えていただけると助かります。

3
0
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
0