Deep copyの注意点

環境

Node.js v14.2.0

Date型, function, undefined, symbolを使う場合

例(コード)

const obj = {
  s: 'bar',
  n: 13,
  ns: '13',
  d: new Date(),
  u: undefined,
  f: () => {},
  sy: Symbol(''),
  nu: null,
  a: [new Date(), undefined, null, () => {}, Symbol(''), []]
}

const copy = JSON.parse(JSON.stringify(obj))

typeof obj.d // 'object'
typeof copy.d // 'string'

copy
// {
//   s: 'bar',
//   n: 13,
//   ns: '13',
//   d: '2020-05-16T15:01:38.298Z',
//   nu: null,
//   a: [ '2020-05-16T15:01:38.298Z', null, null, null, null, [] ]
// }

原因

  • 有効なJSON値でない
  • 結果、JSON.stringifyが変換できない

Boolean、 Number、 String の各オブジェクトは、文字列化の際に慣習的な変換セマンティクスに従い、対応するプリミティブ値に変換されます。 変換の際に undefined、 関数 (Function)、シンボル (Symbol) は有効な JSON 値ではありません。変換中にそのような値に遭遇した場合は、 (オブジェクトの中で発見された場合は) 省略されたり、 (配列の中で見つかった場合は) null に変換されたりします。

developer.mozilla.org

途中でエラーが発生した場合

  • エラー発生時点で中断するため、以降の処理は発生しない
var target = Object.defineProperty({}, 'foo', {
  value: 1,
  writable: false
}); // target.foo は読み取り専用のプロパティ

Object.assign(target, { bar: 2 }, { foo2: 3, foo: 3, foo3: 3 }, { baz: 4 });
// TypeError: "foo" is read-only
// target.foo に代入しようとすると、この例外が発生する

console.log(target.bar);  // 2, 一番目のコピー元オブジェクトはコピーされている
console.log(target.foo2); // 3, 二番目のコピー元の最初のプロパティもコピーされている
console.log(target.foo);  // 1, ここで例外が発生(値は変更されていない)
console.log(target.foo3); // undefined, assign メソッドが終了したので foo3 はコピーされない
console.log(target.baz);  // undefined, 三番目のコピー元もコピーされない

developer.mozilla.org