📝

JavaScript 学習実施メモ 4

2021/02/09に公開

初学者のメモです。間違い等ありましたらご指摘コメント待ってます。

4回目のやつ。

前回: https://zenn.dev/yuki_kanayama/articles/816cd1022c652f

初回: https://zenn.dev/yuki_kanayama/articles/37022f0373e38d

ラッパーオブジェクト

プリミティブ値を内包するオブジェクト。(オブジェクトの中身がプリミティブ)
暗黙的に、ラッパーオブジェクトで定義せずともそのメソッドを呼び出すことができる。

1. const a = new String('hello'); // わざわざインスタンス化せずにそのまま代入する
2. // or
3. const a = 'hello'
4.  
5. console.log(a.toUpperCase());// ラッパーオブジェクトのメソッド

シンボル(symbol)

プロパティーの重複をさけるために、必ず一意の値を返す関数。今後のJSのアップデートでビルドインオブジェクト、メソッドが増えた時に、それまでに宣言していたプロパティ名が被っても別のプロパティとして扱うことができる。

1. const s = Symbol('hello');
2. const s2 = Symbol('hello');
3.  
4. console.log(s === s2); // 名前は同じだが false となる。
5.  
6. console.log(typeof s); // Symbol

ちなみに、ビルドインオブジェクト(String,Array,など)をsymbolを使用してプロトタイプ拡張すると、プロトタイプ汚染となるため基本的に実施しない。

プロパティーとディスクリプター

プロパティの設定値

プロパティには設定値が4種類ある。その4つをディスクリプターと呼ぶ。

1. value         値
2.  
3. configurable  設定変更可能性
4.  
5. enumerable    列挙可能性
6.  
7. writeble      値の変更可能性
1. // オブジェクトリテラルで定義
2. const obj = {
3.   prop: 0,
4. };
5.  
6. obj.prop = 3;
7. const descriptor = Object.getOwnPropertyDescriptor(obj, 'prop');
8. console.log(descriptor);
9. // {value: 3, writable: true, enumerable: true, configurable: true}
10.  
11. // 空のオブジェクトに「defineProperty」で定義
12. const obj2 = {};
13. Object.defineProperty(obj2, 'prop', {
14.   value: 0,
15. })
16.  
17. obj2.prop = 5;
18. const descriptor2 = Object.getOwnPropertyDescriptor(obj2, 'prop');
19. console.log(descriptor2);
20. // {value: 0, writable: false, enumerable: false, configurable: false} 
21. // writable が false のため書き換えができずvalueが変わっていない。

getter/setter と static

1. // クラスで定義した場合
2. class PersonClass { 
3.   constructor(name, age) {
4.     this.name = name;
5.     this.age = age;
6.   }
7.  
8.   get x() {
9.     return this.name; // 設定した名前で呼び出す時に実行される。
10.   }
11.  
12.   set x(val) {
13.     this.name = val; // 設定した名前が書き換えた時に実行される。
14.   }
15.  
16.   static hello() {
17.     console.log('Hello!'); // インスタンス化せずに使える。スタティックメソッド。
18.   }
19.  
20.   bye() {
21.     console.log('Bye!!');
22.   }
23. }
24.  
25. const p2 = new PersonClass('James', 36);
26. p2.x = 'Kevin'; // xを書き換えているので「set」が呼ばれる
27. console.log(p2.x); // xを呼び出しているので「get」が呼ばれる
28.  
29. PersonClass.hello(); // スタティックメソッドの呼び出し。
30. p2.bye(); // 通常のメソッドの呼び出し。
31. p2.constructor.hello(); // スタティックメソッドは、インスタンス化した後だと「constructor」からじゃないと呼び出せない。
32.  
33. // コンストラクタ関数で定義した場合
34. function Person(name, age) {
35.   this.name = name;
36.   this.age = age;
37. }
38.  
39. Object.defineProperty(Person.prototype, 'nameValue', {
40.   get: function () {
41.     return this.name;
42.   },
43.   set: function (val) {
44.     this.name = val;
45.   }
46. });
47.  
48. const p1 = new Person('Bob', 26);
49. p1.nameValue = 'Akira';
50. console.log(p1.nameValue);
1. // 実行結果
2. Kevin
3. Bye!!
4. Hello!
5. Hello!
6. Akira

チェーンメソッド

定義したメソッドを1つの塊として実行できる。

1. class Person {
2.   constructor(name, age) {
3.     this.name = name;
4.     this.age = age;
5.   }
6.  
7.   hello(person) {
8.     console.log(`${this.name} says hello ${person.name}`);
9.     return this; // 「return」で this(bob) を返り値にしている
10.   }
11.  
12.   introduce() {
13.     console.log(`Hi, I'm ${this.name}, ${this.age} years old.`);
14.     return this;
15.   }
16.  
17.   shakeHands(person) {
18.     console.log(`${this.name} shake hands with ${person.name}.`);
19.     return this;
20.   }
21.  
22.   bye(person) {
23.     console.log(`Goodbye, ${person.name}.`);
24.     return this;
25.   }
26. }
27.  
28. const bob = new Person('Bob', 23);
29. const tim = new Person('Tim', 33);
30.  
31. bob.hello(tim) // チェーンメソッドの記述方法。
32.   .introduce()
33.   .shakeHands(tim)
34.   .bye(tim)
35.  
36. console.log(bob.introduce());
37. console.log(bob);
1. // 実行結果
2. Bob says hello Tim
3. Hi, I'm Bob, 23 years old.
4. Bob shake hands with Tim.
5. Goodbye, Tim.
6. Hi, I'm Bob, 23 years old.
7. Person {name: "Bob", age: 23}
8. Person {name: "Bob", age: 23}

for...inと列挙可能性

for...in

列挙可能プロパティに対して順不同で反復処理を実行する。プロトタイプチェーン内も列挙対象となる。自分自身にのみ設定されているプロパティのみを列挙する場合は、

Object.hasOwnProperty();

を使用する。

ちなみに、Symbol(のちに名前が被っても大丈夫なプロパティ)で定義したプロパティは、for...in で列挙対象にならない。

for...ofと反復可能性

for...of

イテレーターを持つオブジェクトの反復操作を行う。

イテレーターとは…。反復操作を行う際に使用するオブジェクト。(String,Array,Mapなど)本来、ループ処理する場合は、ディスクリプターの『enumerable : 列挙可能性』の値を確認し動作するが、『for...of』の場合は、配列のプロトタイプにあるイテレーターが呼ばれて実行されている。つまり、『for...of』を使用できるのはイテレーターのみ。逆もしかりで、イテレーターは、『for...of』のみでループ処理を行う。

Map, Set

Map、Set

データを管理するための入れ物。コレクションとも呼ぶ。

1.                 Map        Object
2.   キー         制約なし       文字列
3.  
4.   for...in       ×            ◯
5.  
6.   for...of       ◯            ×
1.                 Array        Set
2.   重複値           ◯           ×
3.  
4.   for...in        ◯           ×
5.  
6.   for...of        ◯           ◯

反復可能オブジェクト(イテレーター)

ジェネレーター

イテレーターを生成するための特殊な関数。

1. function* genIterator(max = 10) {
2.   let i = 0;
3.   while (i < max) {
4.     yield i++;
5.   }
6.   return;
7. }
8.  
9. const it = genIterator();
10. for (let k of it) {
11.   console.log(k);
12. }
1. function* genStep({ min = 0, max = 20, step = 1 }) {
2.   let num = min - step;
3.   while (num < max) {
4.     num += step;
5.     yield num;
6.   }
7. }
8.  
9. const it = genStep();
10.  
11. for(let value of it) {
12.   console.log(value);
13. }

上記の場合、genStep呼び出し時オブジェクトの引数が渡っておらず、オブジェクトなしでの実行となりエラーとなる。

1. function* genStep({ min = 0, max = 20, step = 1 } = {}) {
2.   let num = min - step;
3.   while (num < max) {
4.     num += step;
5.     yield num;
6.   }
7. }

定義部分で、

({ 初期値など } = {})

を記述すると、引数がないときのオブジェクトがオブジェクトリテラルとなり、そこのデフォルト値として記述内容の部分が適用される動きになる。

非同期処理

スレッド

連続して実行される一本の処理の流れ。

メインスレッド

Javascriptの実行とレンダリング(画面描写処理)を行う。

同期処理

メインスレッドでコードが順番に実行される。1つの処理が完了するまでは次の処理には進まない。
メインスレッドが専有されている === コールスタックにコンテキストが積まれてる

非同期処理

一時的にメインスレッドから処理が切り離される。

タクスキュー

実行待ちの非同期処理の行列。非同期処理の実行順を管理している。キューの仕組みを 「先入れ先出し」 という。**FIFO(First In, First Out)**ともいう。

Discussion