🧩

参照 vs スプレッド構文 vs structuredClone()

2023/11/27に公開

🧐 この記事は

どれがどう違うの??という話

📖 定義

前提

const original = {
  name: 'John',
  profile: {
    age: 30  
  }
}

のオブジェクト original と同じオブジェクト copy を作りたい
以降比べる作り方をそれぞれ「参照のコピー」「スプレッド構文によるコピー」「structuredClone()によるコピー」と呼ぶ。

参照のコピー

let refCopy = original;

スプレッド構文によるコピー

let spreadCopy = {...original};

structuredClone()によるコピー

let structuredCopy = structuredClone(original);

⚖️ 参照のコピー vs スプレッド構文によるコピー

// 元のデータ
const original = {
  name: 'John',
  profile: {
    age: 30  
  }
}

// 参照のコピー
let refCopy = original;
// スプレッド構文によるコピー
let spreadCopy = {...original};

// originalの値を変えてみる
original.name = 'Tom'; 

// 表示してみる
console.log(original.name); // Tom
console.log(refCopy.name); // Tom
console.log(spreadCopy.name); // John

というように、 refCopyoriginal の変更に引っ張られる。
spreadCopy は元のデータが保持できている。
ちなみに、コピー側の変更も同様。

refCopyの値を変えてみる(変数定義はさっきと一緒)
// refCopyの値を変えてみる
refCopy.name = 'Tom';

// 表示してみる
console.log(original.name); // Tom
console.log(refCopy.name); // Tom
console.log(spreadCopy.name); // John
spreadCopyの値を変えてみる(変数定義はさっきと一緒)
// spreadCopyの値を変えてみる
spreadCopy.name = 'Tom';

// 表示してみる
console.log(original.name); // John
console.log(refCopy.name); // John
console.log(spreadCopy.name); // Tom

⚖️ 参照のコピー vs structuredClone()によるコピー

// 元のデータ
const original = {
  name: 'John',
  profile: {
    age: 30  
  }
}

// 参照のコピー
let refCopy = original;
// structuredClone()によるコピー
let structuredCopy = structuredClone(original);

// originalの値を変えてみる
original.name = 'Tom'; 

// 表示してみる
console.log(original.name); // Tom
console.log(refCopy.name); // Tom
console.log(structuredCopy.name); // John

先ほどと同様、 structuredCopy は元のデータが保持できている。
ちなみに、コピー側の変更も同様なので割愛。

⚖️ スプレッド構文によるコピー vs structuredClone()によるコピー

// 元のデータ
const original = {
  name: 'John',
  profile: {
    age: 30  
  }
}

// スプレッド構文によるコピー
let spreadCopy = {...original};
// structuredClone()によるコピー
let structuredCopy = structuredClone(original);

// originalの値を変えてみる
original.name = 'Tom'; 

// 表示してみる
console.log(original.name); // Tom
console.log(spreadCopy.name); // John
console.log(structuredCopy.name); // John

これまでを総合するに、どっちも original の変更には左右されない。
じゃあ何が違うのかというと

// 元のデータ
const original = {
  name: 'John',
  profile: {
    age: 30  
  }
}

// スプレッド構文によるコピー
let spreadCopy = {...original};
// structuredClone()によるコピー
let structuredCopy = structuredClone(original);

// originalの値を変えてみる
original.profile.age =  20;

// 表示してみる
console.log(original.profile.age); // 20
console.log(spreadCopy.profile.age); // 20
console.log(structuredCopy.profile.age); // 30

というように、 spreadCopyoriginal 内の階層2段階以上の値を変更すると引っ張られてしまう。
ちなみに、 refCopy も変わらず original の変更に引っ張られる。
こちらもコピー側の変更も同様。

spreadCopyの値を変えてみる(変数定義はさっきと一緒)
// spreadCopyの値を変えてみる
spreadCopy.profile.age = 20;

// 表示してみる
console.log(original.profile.age); // 20
console.log(spreadCopy.profile.age); // 20
console.log(structuredCopy.profile.age); // 30
structuredCopyの値を変えてみる(変数定義はさっきと一緒)
// structuredCopyの値を変えてみる
structuredCopy.profile.age = 20;

// 表示してみる
console.log(original.profile.age); // 30
console.log(spreadCopy.profile.age); // 30
console.log(structuredCopy.profile.age); // 20

✅ それぞれのメリットデメリット

※ いずれも上記のコードの場合

参照 スプレッド構文 structuredClone()
文字数
※ 右辺のみ;抜き

8文字
⚪︎
13文字

25文字
originalを汚さない ⚪︎
1段階まで
関数を含む場合
例) original.greet = function() {console.log('Hello, world!')}
⚪︎
originalが変更されたら変更されちゃう

originalが変更されても変更されない

エラーになる
100万回for文で回した時の時間
※ 10回平均

38.98ms
⚪︎
253.99ms

1899.46ms

Discussion