Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JavaScript #186

Open
hysryt opened this issue Aug 26, 2021 · 7 comments
Open

JavaScript #186

hysryt opened this issue Aug 26, 2021 · 7 comments

Comments

@hysryt
Copy link
Owner

hysryt commented Aug 26, 2021

No description provided.

@hysryt
Copy link
Owner Author

hysryt commented Aug 26, 2021

イベントループ

https://ja.javascript.info/event-loop

  1. macrotask キューにある最も古いタスクを取り出して実行
  2. すべての microtask を実行
  3. 変更がある場合はレンダリング
  4. macrotask キューが空であれば、macrotask が現れるまで待つ
  5. ステップ1 戻る

setTimeoutで設定した関数は macrotask キューに追加される。
queueMicrotaskやPromiseハンドリングは microtask キューに追加される。
(macrotaskはV8の用語らしい。仕様上では「タスクキュー」?)

setTimeout

仕組みはよくわからないが指定したコールバック関数は指定した時間の後 macrotask キューに追加される。

Promise

仕組みはよくわからないがPromiseがresolveまたはrejectされると登録されていたコールバックが microtask キューに追加される。

async/await

Promiseのシンタックスシュガー。
以下の2つは同等。つまりawait以降の処理はPromiseがresolveされると microtask キューに追加される。

const data = await fetch();
console.log(data);
fetch().then(data => {
  console.log(data);
});

@hysryt
Copy link
Owner Author

hysryt commented Nov 25, 2021

プライベートフィールド

ES2022で追加される予定の仕様。

class Human {
  #age = 20;
}

# で始まるインスタンスフィールドはプライベートになる。

重要な特徴として、プライベートフィールドはインスタンス内でもクラスごとに保持されるというものがある。

class Human {
  #age = 20;

  sayAge() {
    console.log(this.#age);  // Humanの#ageを指す
  }
}

class Man extends Human {
  #age = 30;

  sayAge2() {
    console.log(this.#age);  // Man の#ageを指す
  }
}

const man = new Man();
console.log(man.sayAge()); // 20
console.log(man.sayAge2()); // 30

上記のように、man インスタンスの中には Human#ageMan#age が格納されており、それぞれは別物として扱われる。

基本的には別のインスタンスのプライベートフィールドにはアクセスできないが、同じクラスであれば別のインスタンスのプライベートフィールドを読み取ることができる。

in

#age in objobj#age というプライベートフィールドを持っているかどうかを判断できる。
この式を使えるのは #age をもつクラスのメソッドのみ。(クラスメソッドでも使える?)

Human クラス内で上記の式を使った場合、 #ageHuman クラスの #age という意味になる。
そのため objAnimal クラスで、このクラスも #age を持っていたとしても、上記の式は false となる。(obj が持つのは Animal クラスの #age であって、Human クラスの #age ではないため)

この式を使うと、「そのオブジェクトがHumanクラスのインスタンスかどうか」を確かめることもできる。
インスタンスかどうかを確かめるには obj instanceof Human も使用できるが、こちらはプロトタイプの情報を見ているだけなので、Human をインスタンス化したものでなくても上記の式が true となるようなオブジェクトを作成できてしまう。

@hysryt
Copy link
Owner Author

hysryt commented Dec 5, 2021

Hoisting(ホイスティング、巻き上げ)

JavaScriptでは先にスコープ内の定義をすべて読み込む。
そのため定義より前に関数の呼び出しを記述していても問題なく動作する。

var による定義は、初期値が与えられていない場合は巻き上げ時に undefined が代入される。
letconst による定義は、初期値が与えられていない場合は巻き上げ時には何も代入されない。

@hysryt
Copy link
Owner Author

hysryt commented Dec 6, 2021

Shadow DOM

DOM をカプセル化する。
Shadow DOM の内部は開発者ツールからも見ることができない。

  • Shadow Host: 直接の子要素としてShadow DOMを持つノード。通常のDOMとShadow DOMの境界であり、Shadow Hostは通常のDOM。
  • Shadow Tree: Shadow DOM の中にあるDOMツリー
  • Shadow boundary: 通常のDOMとShadow DOMの境界
  • Shadow root: Shadow Treeのルート

attachShadow()

element.attachShadow(shadowRootInit)

element を Shadow Host として Shadow DOM を追加する。
Shadow Host から Shadow root を取得できる。

element.shadowRoot

Shadow DOM は通常のDOM APIで操作できる。

const host = document.querySelector('#host');
const shadow = host.attachShadow({mode: 'open'});

const child = document.createElement('div');
child.textContent = 'hello';

shadow.appendChild(child);

参考
https://developer.mozilla.org/ja/docs/Web/Web_Components/Using_shadow_DOM

@hysryt
Copy link
Owner Author

hysryt commented Dec 7, 2021

strictモード

ECMAScript5から追加された。
モジュールは自動的にstrictモードとなる。

strictモードには以下のような特徴がある。

  • 宣言なしでグローバル変数を使用できない
  • 無効な代入時にエラーを投げる
  • 無効な削除時にエラーを投げる
  • プロパティ名の重複が構文エラーになる
  • 引数名の重複が構文エラーになる
  • 8進表記の禁止
  • withの禁止
  • eval内の変数は外部に影響を与えない
  • など

strictモードを有効にするにはファイルの先頭に'use strict;' と記述する。

@hysryt
Copy link
Owner Author

hysryt commented Dec 8, 2021

モジュールのエクスポート

エクスポートは named export か default export のどちらかの方法で行う。
default export の場合は1つのモジュールにつき1つのエクスポートしかできない。
named export は1つのモジュールにつき0以上のエクスポートができる。

named export

以下は一例

export const x = 10;
export function test() {...}
export class Test {...}

// まとめてexport
export { name1, name2, name3 };

// 名前を変えてエクスポートすることも可能
export { name1 as alias };

変数、関数、クラスは宣言の直前に export をつければ named export になる。

named export は

import { name } from './module.js';

という構文でインポートする。

default export

以下は一例

export default function() {...}
export default class {...}

// 名前付きの default export もある
export default class Test {...}

// default という名前でエクスポートすると default export になる
export { name1 as default };

default export は

import name from './module.js';

という構文でインポートする。
この時 name は自由に決められるが、基本的にはファイル名と同名にすることが多い。

@hysryt
Copy link
Owner Author

hysryt commented Dec 19, 2021

ジェネレータ関数

ジェネレータ - Wikipedia

ジェネレータ関数は Generator オブジェクトを返す。
帰ってきた Generator オブジェクトの next() を呼び出すことで次の yield までを実行できる。

function* testGen(i) {
    yield i;
    yield i + 1;
    yield i + 2;
}

const gen = testGen(1);

console.log(gen.next().value); // 1
console.log(gen.next().value); // 2
console.log(gen.next().value); // 3

next()value プロパティと done プロパティを持つオブジェクトを返す。
next() を呼び出したときに次の yield がない場合は donetrue になる。

Generator オブジェクトは iterable プロトコルと iiterator プロトコルに準拠している。
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Iteration_protocols

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant