Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Javascript のデータ型 プリミティブ型・オブジェクト

Javascript のデータ型 プリミティブ型・オブジェクト

Jeongmin LEE

April 23, 2024
Tweet

More Decks by Jeongmin LEE

Other Decks in Programming

Transcript

  1. CONTENTS 1. [] === [] は false である 2. プリミティブ型とオブジェクト

    3. メモリは Javascriptの データをどう処理するのか 4. コピーと比較 5. まとめ
  2. プリミティブ型 - 真偽値(Boolean): trueまたはfalseのデータ型 - 数値(Number): 42 や 3.14159 などの数値のデータ型

    - 巨大な整数(BigInt): ES2020から追加された任意精度の整数のデータ型 - 文字列(String): "JavaScript" などの文字列のデータ型 - undefined: 値が未定義であることを意味するデータ型 - null: 値が存在しないことを意味するデータ型 - シンボル(Symbol): ES2015から追加された一意で不変な値のデータ型 - 真偽値や数値などの基本的な値の型 - 一度作成したらその値自体を変更できない(immutable) プリミティブ型の種類
  3. アドレス … 102 103 104 … データ アドレス … 202

    203 204 … データ var a; TASK: 変数 a を宣言して! 変数 保存 データ 保存
  4. アドレス … 102 103 104 … データ 名前: a 値:

    アドレス … 202 203 204 … データ var a; TASK: 変数 a を宣言して! 変数 保存 データ 保存 1. 変数が入るメモリ空間確保(102) 2. 確保した空間の名前に変数名 a を設定
  5. アドレス … 102 103 104 … データ 名前: a 値:

    アドレス … 202 203 204 … データ ‘123’ var a; a = ‘123’ 変数 保存 データ 保存 TASK: 変数 a に ‘123’ をいれて! 1. ‘123’ を保存する別のメモリ空間を確保(203) 2. 確保したメモリに ‘123’ 保存
  6. アドレス … 102 103 104 … データ 名前: a 値:

    @203 アドレス … 202 203 204 … データ ‘123’ var a; a = ‘123’ 変数 保存 データ 保存 TASK: 変数 a に ‘123’ をいれて! 3. 変数保存領域から a を探す 4. a の値に 203 を渡す
  7. アドレス … 102 103 104 … データ 名前: a 値:

    @203 アドレス … 202 203 204 … データ ‘123’ Q. なぜ値を直接保存せず、領域を分けて保存するんですか? 102 名前: a 値: ‘123’ 変数 保存 データ 保存
  8. A. メモリを効率的に使うため 例)500個の変数を生成して全部に数字 5 割り当てる 値を直接割り当てる場合) 値を別で保存してアドレスを参照する場合) 結論: 500 x

    8 => 4000byte 必要 結論: 8 + (500 x 2) => 1008byte 必要 *メモリに数字を保存する場合は 8byte が必要 *メモリアドレスの保存には 2byte が使われると仮定する 102 名前: a 値: 5 8byte x 500 102 5 8byte 202 名前: a 値: @102 2byte + x 500 - 変数保存・データ保存領域を分けたら、重複データの処理効率が良くなる
  9. アドレス … 102 103 104 … データ 名前: a 値:

    @203 アドレス … 202 203 204 … データ ‘123’ var a; a = ‘123’ a = ‘abcdef’ 変数 保存 データ 保存 TASK: 変数 a に ‘abcdef’ を再代入して!
  10. アドレス … 102 103 104 … データ 名前: a 値:

    @204 アドレス … 202 203 204 … データ ‘123’ ‘abcdef’ var a; a = ‘123’ a = ‘abcdef’ 変数 保存 データ 保存 TASK: 変数 a に ‘abcdef’ を再代入して! 1. ‘abcdef’ を別途の文字列として保存する 2. 変数保存領域から a を探す 3. a の値を 204 に変える
  11. アドレス … 102 103 104 … データ 名前: a 値:

    @204 アドレス … 202 203 204 … データ ‘123’ ‘abcdef’ var a; a = ‘123’ a = ‘abcdef’ このデータを参照しているところがないので、削除される(Garbage collection) 変数 保存 データ 保存 GC
  12. アドレス … 102 103 104 … データ 名前: a 値:

    @204 アドレス … 202 203 204 … データ ‘abcdef’ var a = ‘abcdef’ a[0] = ‘G’ console.log(a) // → ‘abcdef’ 変数 保存 データ 保存 この領域に保存されたデータはGCされない限り、絶対変更されない プリミティブ型の値はデータ保存領域に 保存されるので、値自体を変更できない(immutable)
  13. アドレス … 103 104 105 106 … データ 名前: obj1

    値: アドレス … 201 202 203 204 … データ var obj1; obj1 = { a: 1, b: ‘bbb’ } TASK: 変数 obj1 に指定したオブジェクトを入れて! 1. データの保存領域確保(201) 2. データを保存しようとしたら、、データが複数ある! *メモリ構造空間には値が1つしか入れない 変数保存 データ保存
  14. アドレス … 301 302 303 304 … データ 名前: 値:

    名前: 値: アドレス … 103 104 105 106 … データ 名前: obj1 値: アドレス … 201 202 203 204 … データ @301 ~ ? TASK: 変数 obj1 に指定したオブジェクトを入れて! 1. データの保存領域確保(201) 2. 新しいメモリ空間(301 ~ ?)を確保 3. そのアドレスを確保しといたデータ保存領域の 201 に保存 変数保存 データ保存 変数保存 var obj1; obj1 = { a: 1, b: ‘bbb’ } * オブジェクトのプロパティを保存するメモリ領域はサイズが決まってなく、   必要なときに動的に確保する
  15. TASK: 変数 obj1 に指定したオブジェクトを入れて! 3. 301 の名前にプロパティ名 a を設定 4.

    202 の空間を確保、データ 1 保存 5. 変数保存領域から a を探し、値に 202 設定 6. 302 の名前にプロパティ名 b を設定 7. 203 の空間を確保、データ ‘bbb’ 保存 8. 変数保存領域から b を探し、値に 203 設定 アドレス … 301 302 303 304 … データ 名前: a 値: @202 名前: b 値: @203 アドレス … 103 104 105 106 … データ 名前: obj1 値: アドレス … 201 202 203 204 … データ @301 ~ ? 1 ‘bbb’ 変数保存 データ保存 変数保存 var obj1; obj1 = { a: 1, b: ‘bbb’ }
  16. TASK: 変数 obj1 に指定したオブジェクトを入れて! アドレス … 301 302 303 304

    … データ 名前: a 値: @202 名前: b 値: @203 アドレス … 103 104 105 106 … データ 名前: obj1 値: @201 アドレス … 201 202 203 204 … データ @301 ~ ? 1 ‘bbb’ 変数保存 データ保存 変数保存 var obj1; obj1 = { a: 1, b: ‘bbb’ } 9. 変数保存領域から obj1 を探す 10. obj1 の値に 201 を渡す プリミティブ型と違って、データ保存領域に 値ではなく、メモリアドレスが保存される
  17. アドレス … 201 202 203 204 … データ @301 ~

    ? 1 ‘bbb’ 2 アドレス … 301 302 303 304 … データ 名前: a 値: @202 名前: b 値: @203 データ保存 アドレス … 103 104 105 106 … データ 名前: obj1 値: @201 変数保存 変数保存 var obj1 = { a: 1, b: ‘bbb’ } obj1.a = 2 TASK: obj1.a プロパティのバリューを 2 に変更して! 1. データの保存場所確保(204)、2 保存
  18. var obj1 = { a: 1, b: ‘bbb’ } obj1.a

    = 2 アドレス … 201 202 203 204 … データ @301 ~ ? 1 ‘bbb’ 2 アドレス … 301 302 303 304 … データ 名前: a 値: @204 名前: b 値: @203 データ保存 アドレス … 103 104 105 106 … データ 名前: obj1 値: @201 変数保存 変数保存 TASK: obj1.a プロパティのバリューを 2 に変更して! 2. 変数保存領域から obj1 を探す 3. 値のアドレスをたどり、a の値を 204 に変更
  19. var obj1 = { a: 1, b: ‘bbb’ } obj1.a

    = 2 console.log(obj1.a) // → 2 アドレス … 201 202 203 204 … データ @301 ~ ? 1 ‘bbb’ 2 アドレス … 301 302 303 304 … データ 名前: a 値: @204 名前: b 値: @203 データ保存 アドレス … 103 104 105 106 … データ 名前: obj1 値: @201 変数保存 変数保存 オブジェクトの値は別途の変数保存領域に保存され、 データ保存領域ではそのアドレスを保存してるので、 値自体を変更できる(mutable)
  20. var obj1 = { x: 3, arr: [ 3, 4

    ] } アドレス … 201 202 203 204 … データ @301 ~ ? 3 アドレス … 301 302 303 304 … データ 名前: x 値: @202 データ保存 アドレス … 103 104 105 106 … データ 名前: obj1 値: 変数保存 変数保存 TASK: プロパティに配列があるオブジェクトを保存して! (配列割り当ての前は割愛)
  21. var obj1 = { x: 3, arr: [ 3, 4

    ] } アドレス … 201 202 203 204 … データ @301 ~ ? 3 アドレス … 301 302 303 304 … データ 名前: x 値: @202 名前: arr 値: データ保存 アドレス … 103 104 105 106 … データ 名前: obj1 値: 変数保存 変数保存 TASK: プロパティに配列があるオブジェクトを保存して! アドレス … 401 402 403 304 … データ 変数保存 1. 302の名前にプロパティ名 arr を設定 2. arr の値のための保存領域空間確保
  22. var obj1 = { x: 3, arr: [ 3, 4

    ] } アドレス … 201 202 203 204 … データ @301 ~ ? 3 @401 ~ ? 4 アドレス … 301 302 303 304 … データ 名前: x 値: @202 名前: arr 値: データ保存 アドレス … 103 104 105 106 … データ 名前: obj1 値: 変数保存 変数保存 TASK: プロパティに配列があるオブジェクトを保存して! アドレス … 401 402 403 304 … データ 名前: 0 値: @202 名前: 1 値: @204 変数保存 3. 別メモリ領域確保(@401 ~ ?)、そのアドレスを 203 に保存 3. index 0 の要素の値はすでに保存済みの 3のメモリアドレスを入れる 4. データ保存領域に 4 を保存 5. index 1 の要素の値に 4 のメモリアドレス(204)を入れる
  23. var obj1 = { x: 3, arr: [ 3, 4

    ] } アドレス … 201 202 203 204 … データ @301 ~ ? 3 @401 ~ ? 4 アドレス … 301 302 303 304 … データ 名前: x 値: @202 名前: arr 値: @203 データ保存 アドレス … 103 104 105 106 … データ 名前: obj1 値: 変数保存 変数保存 TASK: プロパティに配列があるオブジェクトを保存して! アドレス … 401 402 403 304 … データ 名前: 0 値: @202 名前: 1 値: @204 変数保存 6. arr の値情報が入ってるメモリのアドレス(203)を arr の値に指定
  24. var obj1 = { x: 3, arr: [ 3, 4

    ] } アドレス … 201 202 203 204 … データ @301 ~ ? 3 @401 ~ ? 4 アドレス … 301 302 303 304 … データ 名前: x 値: @202 名前: arr 値: @203 データ保存 アドレス … 103 104 105 106 … データ 名前: obj1 値: @201 変数保存 変数保存 TASK: プロパティに配列があるオブジェクトを保存して! アドレス … 401 402 403 304 … データ 名前: 0 値: @202 名前: 1 値: @204 変数保存 7. obj1 のプロパティ情報が入ってるメモリのアドレス(201)を obj1 の値に指定
  25. アドレス … 102 103 104 … データ 名前: a 値:

    @203 名前: b 値: @203 アドレス … 202 203 204 … データ ‘123’ var a = ‘123’; var b = ‘123’; a === b // → true 変数 保存 データ 保存 TASK: 変数 a と b を === で比較して! (a, b の保存・データ割り当ては割愛) 1. 変数保存領域から a と b を探す 2. a と b の値を比較
  26. アドレス … 102 103 104 … データ 名前: a 値:

    @203 名前: b 値: @203 アドレス … 202 203 204 … データ ‘123’ var a = ‘123’; var b = a; a === b // → true 変数 保存 データ 保存 (a の保存・データ割り当ては割愛) 1. b が入るメモリ空間確保、名前に b を指定 2. a の値である 203 を b の値に指定 3. a と b の値を比較 TASK: 変数 a と b を === で比較して!
  27. アドレス … 102 103 104 … データ 名前: a 値:

    @203 名前: b 値: @204 アドレス … 202 203 204 … データ ‘123’ ‘456’ var a = ‘123’; var b = a; b = ‘456’ a === b // → false 変数 保存 データ 保存 1. ‘456’ のデータを保存する(204) 2. 変数名 b の値を 204 に変える 3. a と b の値を比較する TASK: 変数 b の値を再代入してから a と b を比較して!
  28. アドレス … 102 103 104 … データ 名前: a 値:

    @203 名前: b 値: @204 アドレス … 202 203 204 … データ ‘123’ ‘456’ var a = ‘123’; var b = a; b = ‘456’ a === b // → false 変数 保存 データ 保存 1. ‘456’ のデータを保存する(204) 2. 変数名 b の値を 204 に変える 3. a と b の値を比較する TASK: 変数 b の値を再代入してから a と b を比較して! 比較のとき参照するメモリアドレスが値を見てるので 値同士の比較と同じ動きになる
  29. アドレス … 301 302 302 304 … データ 名前: a

    値: @203 アドレス … 103 104 105 106 … データ 名前: obj1 値: @201 名前: obj2 値: @202 アドレス … 201 202 203 204 … データ @301 ~ ? @401 ~ ? 1 変数保存 データ保存 変数保存 var obj1 = { a: 1 }; var obj2 = { a: 1 }; obj1 === obj2 TASK: 変数 obj1 と obj2 を === で比較して! (obj1, obj2 の保存・データ割り当ては割愛) アドレス … 401 402 402 404 … データ 名前: a 値: @203 変数保存
  30. アドレス … 301 302 302 304 … データ 名前: a

    値: @203 アドレス … 103 104 105 106 … データ 名前: obj1 値: @201 名前: obj2 値: @202 アドレス … 201 202 203 204 … データ @301 ~ ? @401 ~ ? 1 変数保存 データ保存 変数保存 var obj1 = { a: 1 }; var obj2 = { a: 1 }; obj1 === obj2 // → false TASK: 変数 obj1 と obj2 を === で比較して! (obj1, obj2 の保存・データ割り当ては割愛) 1. 変数保存領域から obj1 と obj2 を探す 2. obj1 と obj2 の値を比較 アドレス … 401 402 402 404 … データ 名前: a 値: @203 変数保存
  31. アドレス … 301 302 302 304 … データ 名前: a

    値: @203 アドレス … 103 104 105 106 … データ 名前: obj1 値: @201 名前: obj2 値: @202 アドレス … 201 202 203 204 … データ @301 ~ ? @401 ~ ? 1 変数保存 データ保存 変数保存 var obj1 = { a: 1 }; var obj2 = { a: 1 }; obj1 === obj2 // → false TASK: 変数 obj1 と obj2 を === で比較して! (obj1, obj2 の保存・データ割り当ては割愛) 1. 変数保存領域から obj1 と obj2 を探す 2. obj1 と obj2 の値を比較 アドレス … 401 402 402 404 … データ 名前: a 値: @203 変数保存 比較のとき参照するメモリアドレスが、 別のメモリアドレスを見てるのでメモリアドレス 同士の比較と同じ動きになる
  32. アドレス … 301 302 302 304 … データ 名前: a

    値: @203 アドレス … 103 104 105 106 … データ 名前: obj1 値: @201 名前: obj2 値: @201 アドレス … 201 202 203 204 … データ @301 ~ ? 1 変数保存 データ保存 変数保存 var obj1 = { a: 1 }; var obj2 = obj1; obj1 === obj2 // → true TASK: 変数 obj1 と obj2 を === で比較して! (obj1 の保存・データ割り当ては割愛) 1. obj2 が入るメモリ空間確保、名前に obj2 を指定 2. obj1 の値である 201 を obj2 の値に指定 同じメモリアドレスを参照してる
  33. アドレス … 301 302 302 304 … データ 名前: a

    値: @204 アドレス … 103 104 105 106 … データ 名前: obj1 値: @201 名前: obj2 値: @201 アドレス … 201 202 203 204 … データ @301 ~ ? ‘Hi’ 変数保存 データ保存 変数保存 var obj1 = { a: 1 }; var obj2 = obj1; obj2.a = ‘Hi’ console.log(obj1) // { a: ‘Hi’ } obj1 === obj2 // → true TASK: 変数 obj1.a の値を変更してから比較して! (obj1 の保存・データ割り当ては割愛) 1. obj2 が入るメモリ空間確保、名前に obj2 を指定 2. obj1 の値である 201 を obj2 の値に指定 同じメモリアドレスを参照してる ので、片方の変更が全体に反映される
  34. アドレス … 301 302 302 304 … データ 名前: a

    値: @204 アドレス … 103 104 105 106 … データ 名前: obj1 値: @201 名前: obj2 値: @201 アドレス … 201 202 203 204 … データ @301 ~ ? ‘Hi’ 変数保存 データ保存 変数保存 var obj1 = { a: 1 }; var obj2 = obj1; obj2.a = ‘Hi’ console.log(obj1) // { a: ‘Hi’ } obj1 === obj2 // → true TASK: 変数 obj1.a の値を変更してから比較して! (obj1 の保存・データ割り当ては割愛) 1. obj2 が入るメモリ空間確保、名前に obj2 を指定 2. obj1 の値である 201 を obj2 の値に指定 同じメモリアドレスを参照してる ので、片方の変更が全体に反映される オブジェクトを変更する際コピーするのではなく、 新しいオブジェクトを生成する理由がここにある。 逆にオブジェクトを使ってるところに変更を全部反映したい場合は、 わざと一つのオブジェクトを使う場合もある(事例)
  35. アドレス … 301 302 302 304 … データ 名前: a

    値: @203 アドレス … 103 104 105 106 … データ 名前: obj1 値: @201 名前: obj2 値: @201 アドレス … 201 202 203 204 … データ @301 ~ ? 1 変数保存 データ保存 変数保存 var obj1 = { a: 1 }; var obj2 = obj1; obj1 === obj2 // → true TASK: obj1 をコピーしてから、値を再代入して比較して! (obj1 の保存・コピーは割愛)
  36. アドレス … 301 302 302 304 … データ 名前: a

    値: @203 アドレス … 103 104 105 106 … データ 名前: obj1 値: @201 名前: obj2 値: @202 アドレス … 201 202 203 204 … データ @301 ~ ? @401 ~ ? 1 変数保存 データ保存 変数保存 var obj1 = { a: 1 }; var obj2 = obj1; obj2 = { a: 1 }; obj1 === obj2 // → false アドレス … 401 402 402 404 … データ 名前: a 値: @203 変数保存 TASK: obj1 をコピーしてから、値を再代入して比較して! 1. データ保存領域から新しい空間確保(202) 2. 変数保存領域も確保、そのアドレス(@401 ~ ?)を 202 に保存 3. 401 に obj2.a の情報保存 4. obj2 の値を 202 に変更
  37. アドレス … 301 302 302 304 … データ 名前: a

    値: @203 アドレス … 103 104 105 106 … データ 名前: obj1 値: @201 名前: obj2 値: @202 アドレス … 201 202 203 204 … データ @301 ~ ? @401 ~ ? 1 変数保存 データ保存 変数保存 var obj1 = { a: 1 }; var obj2 = obj1; obj2 = { a: 1 }; obj1 === obj2 // → false アドレス … 401 402 402 404 … データ 名前: a 値: @203 変数保存 TASK: obj1 をコピーしてから、値を再代入して比較して! 1. データ保存領域から新しい空間確保(202) 2. 変数保存領域も確保、そのアドレス(@401 ~ ?)を 202 に保存 3. 401 に obj2.a の情報保存 4. obj2 の値を 202 に変更 オブジェクトも値自体を再代入したら 参照するメモリアドレスが変わる
  38. プリミティブ型 - コピーしてから変更してもコピー元に反映されない - コピー本が参照するメモリアドレスが原本と変わるため - 比較のとき参照するメモリアドレスが値を見てる - 理解が難しい場合は、一旦値を比較すると考えてもOK(動作的には同じなので) オブジェクト

    - コピーしてから変更したらコピー元にも反映される - コピー本と原本が同じメモリアドレスを参照しているため - 比較のとき参照するメモリアドレスが別のメモリアドレスを見てる - 理解が難しい場合は、一旦メモリアドレスを比較すると考えてもOK(動作的には同じなので) - オブジェクトも値自体を再代入したら参照するメモリアドレスが変わる 整理
  39. Javascript のデータ型には2種類がある プリミティブ型 - Boolean、Number、BigInt、String、undefined、null、Symbol - 値がデータ保存領域をに保存されるので、値を変更できない(immutable) - コピーしてから変更してもコピー元に反映されない -

    コピー本が参照するメモリアドレスが原本と変わるため - 比較のとき参照するメモリアドレスが値を見てる - 理解が難しい場合は、一旦値を比較すると考えてもOK(動作的には同じなので)
  40. オブジェクト - オブジェクト、配列、関数、クラス、正規表現、Dateなど - 値が変数保存領域をに保存されるので、値を変更できる(mutable) - コピーしてから変更したらコピー元にも反映される - コピー本と原本が同じメモリアドレスを参照しているため -

    比較のとき参照するメモリアドレスが別のメモリアドレスを見てる - 理解が難しい場合は、一旦メモリアドレスを比較すると考えてもOK(動作的には同じなので) - オブジェクトも値自体を再代入したら参照するメモリアドレスが変わる
  41. - JavaScript Primer - 코어 자바스크립트 - 코어 자바스크립트 -

    데이터타입 (기본형과 참조형) 参考資料