LoginSignup
2
0

More than 1 year has passed since last update.

【技術書まとめ】ハンズオンJavaScript

Last updated at Posted at 2021-09-16

「長い旅にはカバンより歌のほうがうれしいものだよ」

-- トーベ・ヤンソン:『さびしがりやのクニット』

読んだまとめ

JSの全体像が見えた気がする。ハンズオンで実際にコードを書くので頭にも入りやすかった。ただ分厚いので時間はかかった。

1章 学び始める前に

JavaScriptの基礎的な説明

2章 データを学ぶ

JavaScriptの基礎的な説明

3章 処理を学ぶ

  • アルゴリズムとは「何らかの解を得るための手順」のこと。
  • 式は文の一種で値を返すが、文は必ずしも値を返さない
    • let pi = 3.14
  • ブロック{}
    • 変数や定数のスコープができる
      • そのブロックのみで有効となる

4章 オブジェクトを学ぶ

  • JSのオブジェクトは単なるキーバリューのペアではなくメソッドも定義できる

5章 モジュールを学ぶ

  • true.toString()はプリミティブなのになぜできるのか
    • 対応するオブジェクトに自動変換されるから
      • ボックス化と呼ばれる
    • 明示的に相互変換するには
      • オブジェクトにする
        • new Object(true)
      • プリミティブにする
        • Object(true).valueOf()

6基本的な標準オブジェクトを学ぶ

  • falsyな値
    • false
    • null
    • undefined
    • 0
    • 0n
    • ''
    • NaN
  • 数値のプロパティアクセス
    • 42.toString()はエラーになる
      • ドットを二つでアクセスできる
        • 42..toString()
  • Well-Known Symbol
    • Symbol.hasInstance
    • Symbol.toPrimitive
    • Symbol.toStringTag
  • Functionオブジェクト
    • apply() は引数を配列で受け取る
      • add3.apply(1, [16, 25])
    • call() は個別に受け取る
      • add3.call(1, 16, 25)
    • bind() はthisや引数の値を固定した関数を新たに作る
      • bind(1)ならthisは1となる
  • RegExp
    • オプションフラグ
      • g
        • 一致した文字列を全て返す
      • i
        • 大文字小文字を無視する
      • m
        • 複数行検索する
    • 文字列メソッドで正規表現を利用する
      • search()
        • 見つかったら位置を、見つからなかったら-1を返す
      • match()
        • 見つかったらその文字列を、見つからなかったらnullを返す
      • matchAll()
        • 見つかったらイテレータを返す
      • split()
        • 正規表現に一致する部分で分割して配列を返す
      • replace()
        • 置き換えて返す

# 7章 コレクションを学ぶ

  • Array
    • Array.from(days, i => i * i)
      • 二乗したものを配列にできる
    • includes(3, 1)
      • 第二引数の位置から確認を始める
    • some(n => 4 < n)
      • 条件式を満たす要素があるかどうか確認する
      • every(n => 0 < n)
        • 配列の全ての要素が条件式を満たすか確認する
    • reverse()
      • 破壊的メソッド
    • sort()
      • 破壊的メソッド
      • デフォルトでは数値比較ではなく辞書順
    • entries()
      • 要素とインデックスが両方必要な時に使う
    • flat(2)
      • 引数で平坦化する深さを指定する
    • [1, 2, 3].reduce((sum, n) => sum += n, 0)
      • 最後の引数は初期値
        • 初期値は省略しない方がいい
          • 空配列の場合 TypeError が発生する
          •  要素が一つの場合コールバック関数が実行されない
    •  スクリーンショット 2021-07-26 8.43.56.png
      •  配列をスタックのように扱う
        •  stack.pop()
        •  stack.push()
      •  配列をキューのように扱う
        •  queue.shift()
        •  queue.pop()
  •  Map
    •  キーによって要素を管理するとき使う
    •  オブジェクトではobj[1]obj["1"]は区別されないが、マップでは区別される
    •  MapやSetはブラケット記法やドット記法ではアクセスできない
      •  ☠️ map.key
        •  プロバティへのアクセスとなる
    •  forEach()で回すときは値が先に渡される
      •  map.forEach((v, k) => console.log(key: ${k}, value: ${v}))
  • メモリ管理
    • JSが管理するメモリ
      • スタック
        • プリミティブを保持しているローカル変数が使用する
          • 型ごとに必要なメモリ容量が決まっている
        • オブジェクト
          • どこに保存しているかの情報のみ
            • これを参照と呼ぶ
              • メモリ容量は固定
            • オブジェクトは容量固定ではないから
            • 実際のデータはヒープに保存する
      • ヒープ
        • ガベージコレクションされる
          • 例として参照カウント
            • カウント0になったら利用なし
              • 解放される
                • 弱参照はカウントされない
  • WeakMap
    • 弱参照
      • 元オブジェクトの生成や取得に時間がかかる場合の付随情報を管理する使い方など
        • Mapだと元オブジェクトが消えても参照され続ける
  • Set
    • 値を一意に保持するだけの時に使う
      • [...new Set(days)]で days の重複を取り除ける
  • イテレータ
    • next()メソッドを持ったオブジェクトの総称
      • 戻り値はvaluedoneを持つオブジェクト
        • doneでまだ要素が残っているかどうかがわかる
  • イテラブル
    • 反復可能かどうか
      • そのオブジェクトがSymbol.iteratorキーとするプロパティを持つかどうか
        • for-ofは与えられたオブジェクトの[Symbol.iterator]メソッドを呼び出してイテレータを取得し、そのイテレータのnext()メソッドの呼び出し結果の done が true になるまで、next()を呼び出し value の値を変数に代入して、その変数を使用した処理を繰り返し実行している
          • for-ofできるオブジェクトは全て[Symbol.iterator]メソッドを持つ
            • 自分自身を返す[Symbol.iterator]メソッドがある
for (
    let iter = obj[Symbol.iterator](), rslt = iter.next(), item = rslt.value;
    !rslt.done;
    rslt = iter.next(), item = rslt.value
    ) {
    console.log(item)
}
  • ジェネレータ関数
    • イテレータかつイテラブル
      • 関数実行するとジェネレータオブジェクトを生成して返す
        • イテラブルなのでfor-of文で反復実行できる
    • function**method(){}で作成する
      • 関数定義の本文をnext()で実行する
        • return に到達するとそれを{value: "1200kVA", done: true}オブジェクト戻り値として返す
          • だがnext()が常にdone:trueだと繰り返せない
            • yieldを処理を一時中断するreturnとして使う
              • done:falseとなる
    • メソッド
      • next()
        • 引数をひとつ取れる
          • 再開された二度目以降の yield式の戻り値となる
            • 最初に渡した引数は無視される
      • return()
        • 処理の再開と同時に繰り返しを終了する
          • 与えた引数は戻り値の value の値に入る
      • throw()
        • 処理の再開と同時に例外を発生する

複雑なデータの扱いを学ぶ

  • バイナリデータ
    • 2進数で表現されたデータ
  • まずデータをそのまま保持する
    • ArrayBuffer オブジェクトを使う
      • バッファのサイズ(byte)を引数にする
      • ほとんど保持する機能だけ
        • .byteLengthでバイト数を読み取れる
        • slice(start, end)で切り取ったコピーを作れる
  • 読み書きは別オブジェクトを使う
    • ビュー
      • 型付き配列(TypedArray)
        • 特定の型を持つバイナリデータに配列形式でアクセスするオブジェクト群の総称
          • コンストラクタにArrayBufferオブジェクト以外の引数を与えると内部的に ArrayBufferオブジェクトを生成する
      • DataView オブジェクト
        • さまざまな型のデータにアクセスできる
          • set<Type>()
          • get<Type>()
        • 明示的にエンディアンを指定できる
          • リトルエンディアンはtrue
  • JSON
    • JSON.parse(42, reviver)
      • 第二引数で変換処理をする関数を渡せる
    • オブジェクトを文字列やバイト列に変換すること
      • 直列化やシリアライズと呼ばれる
        • JSON.stringify(obj)もその一つ
          • 列挙可能(enumerable)でないプロバティはJSON文字列に含まれない
          • toJSON()メソッドがあるとそれが使用される
          • JSON.stringify(obj, replacer)でJSON文字列変換前に Array[0] だけを取得するなどの処理ができる
          • 第3引数にはインデント指定できる
          • let obj2 = JSON.parse(JSON.stringify(ko1))で1行でディープコピーできる

国際化を学ぶ

  • i18n
    • 言語や時間、数値の表記の違いを吸収する
  • Date
    • new Date(1868, 3, 4)
      • 4月となる
        • 月だけが0から始まる
    • Intl.DateTimeFormat

非同期処理を学ぶ

  • 処理の流れをスレッドと呼ぶ
    • JSはシングルスレッド
  • 非同期処理
    • コールバック関数
      • 相手の都合のよいタイミングで電話を「かけ直して」もらう
      • Buttonオブジェクト
        • addEventListener()でコールパック関数を設定する
          • 処理するのはイベントハンドラやイベントリスナ
      • 何度も発生するイベントをその都度処理するのに適している
        • 一般的な非同期通信に適した手法ではない
          • コールバック地獄
            • Promise が解決してくれる
    • Promise
      • その処理が完了していなくても即座にPromiseオブジェクトを返してくれる
        • 完了後の処理を then()メソッドの引数として与えられる
          • Promiseは実行結果を保持している
            • 実行完了後にthen()メソッドを使う
              • 連結するとPromiseチェーンとなる
function waitFor(msec) {
    return new Promise(resolve => {
        setTimeout(resolve, msec)
    })
}

waitFor(Math.random() * 5000).then(() => {
    console.log("処理A")
    return waitFor(Math.random() * 5000)
}).then(() => {
    console.log("処理B")
    return waitFor(Math.random() * 5000)
}).then(() => {
    console.log("処理C")
})
  • catch()メソッドを使うときは then()メソッドでは第二引数を使わない
> Promise.resolve().then(() => console.log("Promise内"))
console.log("Promise後")

Promise後
Promise内
  • 常に then()メソッドのコールバック関数があとに実行される
    • 非同期処理はいつ完了するかわからない
      • 完了タイミングで挙動が変わると動作が不安定になる
        • 後実行の挙動が保証されている
  • 複数の非同期処理をまとめて扱う
    • Promise.all
    • Promise.allSettled
      • 一部失敗しても全体は失敗しない
      • then() で結果を受け取ることができる
    • Promise.race
      • 最初に完了するPromiseだけが最終結果に影響を与える
  • async関数
    • return文で値を返せば成功したPromiseが、throw文で例外を発生させれば棄却されるPromiseが返る
  • 非同期イテレータ
    • next()メソッドを持つが、その戻り値はPromiseとなる
      • for-await-of文で作る

メタプログラミングを学ぶ

  • Proxy
    • arrayProxy = new Proxy(array, {})
      • arrayProxyに対する操作はarrayに反映される
        • arrayそのままの挙動となる
          • ハンドラオブジェクトに{}ではなくメソッドを追加する
            • トラップと呼ばれる
              • 決められた処理の中継に割り込める
    • プロパティアクセスをプロキシする
      • get(), set(), has(), ownKeys()
array = [3.14, 9.8, 2.718]

arrayProxy = new Proxy(array, {
    get(target, prop) {
        return Math.round(target[prop]) // arrayProxy[0] が 3 となる
    },
    set(target, prop, value) {
        if (!Number.isInteger(value)) {
            throw new Error("not Integer")
        }
        target[prop] = value
    },
    has(target, prop) {
        return prop < 2
    },
    ownKeys(target) {
        return ["0", "1", "length"]
    }
})
  • 関数やコンストラクタの呼び出しをプロキシする
    • apply(), construct()
  • 取り消し可能なProxyを作成する
    • プロキシオブジェクトはターゲットの参照を保持しているためガベージコレクタに回収されない
      • Proxy.revocable()で取り消す

Webを学ぶ

  • Web
    • HTML文章の集合からJSで繋がれたコンテンツの集合になっていった
  • グローバルオブジェクト
    • 宣言していない変数や定数
      • globalThisオブジェクトのプロパティ
        • globalThis === window同じ
      • console
      • location
      • navigator
  • ドキュメントオブジェクトモデル(DOM)
    • DOMの構造
      • HTML, XML, SVG などを表現する
      • 木構造
        • DOMツリー
          • childNodes[0]で子ノードを辿っていける
    • 主要オブジェクト
      • Node
        • 木構造の各ノードを表すオブジェクト
      • Document
        • DOMツリーのルートノード
      • Element
        • タグ要素
      • HTMLElement
        • すべてのHTMLタグの継承元
      • スクリーンショット 2021-08-13 8.33.15.png
    • 要素への操作
      • document.body.childNodes
        • Nodeオブジェクトのプロパティ
          • Text整形のための改行なども含む
            • 整形のための要素が必要になることはほとんどない
      • document.body.children
        • Elementオブジェクトのプロパティ
          • HTML要素しか含まない
          • idを持つ子要素に直接アクセスできる
            • document.body.children.exampleId
    • 要素を検索する
      • getElementsByTagName()
      • getElementById()
      • getElementsByClassName()
      • querySelector()
      • querySelectorAll()
    • 要素のコンテンツを操作する
      • textContent
        • すべてのテキストを返す
      • innerText
        • 実際に表示されているテキストだけを返す
    • 要素を追加する
      • 作る
        • createElement()
        • createNode()
      • 追加する
        • appendChild()
        • insertBefore()
        • prepend()
        • append()
    • 要素を入れ替える
      • replaceChild()
    • console上でそのまま編集する
      • document.body.contentEditable = true
  • CSSオブジェクトモデル
    • document.styleSheets[0].cssRules
      • すべてのルールを取得できる
    • setProperty()で書き換えられる
    • insertRule()で挿入する
  • イベント
    • 「何かの出来事」が生じたら「何かの処理」を行う
      • イベント処理
        • addEventListener()とコールバック関数で実現する
          • document.body.addEventListener("click", evt => { evt.target.style.backgroundColor = `#${Math.floor(Math.random() * 0xffffff).toString(16)}` })
        • removeEventListener()
          • 無名関数は削除できない
            • 名前をつけて渡しておく必要がある
        • dispatchEvent()
          • 任意のタイミングでイベント発火させる
    • 代表的なイベント
      • keydown
        • キーが押された時
      • keyup
        • 押されたキーが解放された時
    • イベントハンドラの探索順序
      • 親をたどっていく
        • bodyタグはすべての表示要素の親
      • イベントの流れ
        • スクリーンショット 2021-08-20 8.19.52.png
      • 親から子
        • キャプチャリング
      • 子から親
        • バブリング
    • HTMLタグにはデフォルトでイベントに反応するものがある
  • Web Components
    • 独自の機能や見た目のタグを作成できる
    • Custom Elements
      • HTMLElementを継承したクラスを作る
      • customElements.define()で登録する
    • Shadow DOM
      • Shadow DOM 外の描画に影響を与えないDOMツリー
        • 通常のDOMツリーに追加できる
    • HTML Template
      • <template>タグ
        • 画面には描画されないがJSから参照できるDOM要素
          • <template>とJSを組み合わせて実際のDOMに描画する
            • HTMLとJSを分離できる
              • attribute を引数のようにコンテンツの中身に使うなど
// あっという間にお絵かき帳
document.styleSheets[0].insertRule(`
   .dot {
        position: absolute;
        width: 5px;
        height: 5px;
        background-color: black;
        }
`)
let clicking
document.body.addEventListener("mouseup", () => clicking = false)
document.body.addEventListener("mousedown", () => clicking = true)
document.body.addEventListener("mousemove", evt => {
    if(!(clicking && evt.shiftKey)) return
    const dot = document.createElement("div")
    dot.className = "dot"
    dot.style.left = `${evt.clientX}px`
    dot.style.top = `${evt.clientY}px`
    document.body.append(dot)
})

ネットワークを学ぶ

  • URI(Uniform Resource Identifier)
    • 「求めるコンテンツを示す手段」
      • 電話番号のようなもの
      • どうやってコンテンツを受け渡すかはそのあとの話
    • https://www.amazon.co.jp/s?k=javascript&ref=nb_sb_noss_2の構造
      • スキーム
        • https
      • デリミタ
        • :
      • オーソリティ
        • //amazon.com
          • プレフィックス
            • //
          • ホスト
            • amazon.com
      • パス
        • /s
      • クエリ
        • k=javascript&ref=nb_sb_noss_2
    • 包含
      • URI(Uniform Resource Locator)
      • URN(Universal Resource Name)
    • encodeURI()
      • そのままURIとして使える
    • encodeURIComponent()
      • そのままURIとして使えないが、クエリパラメータとして使える
  • HTTP
    • 通信プロトコル
      • 「もしもし〇〇ですが……」から始まる一連の儀礼や手順
    • リクエスト・レスポンス型
    • ステートレス
  • WebAPI
    • REST
      • URIでリソースを一意に識別する
      • GET, POST, PUT, PATCH, DELETE を使用する
  • fetch
    • 404エラーでもthen()が呼び出される
      • then の中で status を確認する
        • if (!response.ok) throw new Error(response.statusText)
  • navigator.sendBeacon()
    • ページナビゲーションに影響を与えずにビーコンを送信できる
  • HTTP以外のプロトコル
    • HTTP/2
      • バイナリベース
      • リクエスト・レスポンスの多重化ができる
    • WebSocket
      • 双方向にデータを送信できる
    • WebRTC
      • ブラウザ同士のリアルタイム通信ができる

ストレージを学ぶ

  • Cookie
    • DevToolsから確認する
    • コンソールから確認する
      • document.cookie
        • HttpOnlyが設定されているとJSからはアクセスできない
          • セッションIDをJSから読み込めるとセキュリティの問題になることがあるため
        • 読取はまとめて得られるが代入は1エントリずつ
          • document.cookie = "power=E"
          • 内部的なフィールドに値を設定し、それを文字列形式で読み出すゲッターとセッター
// JSでCookieを取得する
let cookieMap = () => new Map(document.cookie.split(/;\s*/).map(kv => {
    const ms = kv.match(/([^=]+)=(.*)/)
    return [ms[1], ms[2].replace(/(^"|"$)/g, "")]
}))
cookies = cookieMap()
cookies.get("lang")


// Cookieの大まかな内部構造
let doc = {
    _cookie: new Map(),
    get cookie() {
        return [...this._cookie].map(kv => kv.join("=")).join(";")
    },
    set cookie(val) {
        this._cookie.set(...val.split("="))
    }
}
doc.cookie = "power=B"
doc.cookie = "spec=C"
doc.cookie    // "power=B;spec=C"


// 属性を指定する
document.cookie = "power=B;max-age=1000"
  • WebStorage
    • サーバにデータが送信されない
      • クライアント側でだけ利用できる
        • Cookieは必ず送信されてしまう
    • 5~10MB程度のデータ
    • localStorage.getItem()
    • localStorage.setItem()
      • 文字列以外はJSONで入れる
      • 容量制限を超えるとエラーが出る
    • localStorage.removeItem()
    • localStorage.clear()
      • すべてのデータをまとめて削除する
  • IndexedDB
    • オブジェクト指向データベース
      • キーバリューストア
        • データベース作成やスキーマ定義が必要
      • スクリーンショット 2021-08-26 8.34.23.png
      • データベースの構造
        • オブジェクトストア
          • テーブルに対応するもの
        • オブジェクト
        • プロパティ
          • カラム
    • 接続
      • indexedDB.open("jojodb", 1)
        • 非同期で行われる
    • オブジェクトストアを作成する
      • db.createObjectStore("satnds", {keyPath: "id", autoIncrement: true})
    • インデックスを定義する
      • standStore.createIndex("nameIndex", "name", {unique:true})
    • オブジェクトを追加する
      • db.transaction(["stands"], "readwrite)
        • トランザクションを開始する
      • transaction.objectStore("stands")
        • オブジェクトストアを取り出す
      • standStore.add()
        • 追加する
          • 非同期で実行される
            • 結果はIDBRequestオブジェクト
    • オブジェクトを取得する
      • standStore.get(1)

マルチメディアを学ぶ

  • グラフィック系APIの操作

センサーとデバイスを学ぶ

  • モバイルデバイスのセンサー取得法など

PWAを学ぶ

  • ServiceWorker

    • バックグラウンドで動作するスクリプト
      • スクリーンショット 2021-09-09 7.58.35.png
    • 登録
      • navigator.serviceWorker.register()
  • ネイティブアプリを超える

    • URIでアプリケーションを共有できる
      • Web Share API
    • 支払い情報やログイン情報をブラウザでまとめられる
      • PaymentRequest API

セキュリティを学ぶ

  • サービスが家ならブラウザはサービスにつながるドアで、ログインは家の鍵
    • ユーザーが誰か確認する
      • 認証
    • 機能の利用を許可する
      • 認可
  • JSが安全に利用できる理由
    • サンドボックスで動作するから
      • 同一オリジンポリシー
        • オリジン
          • スキームとホストとポート番号の組み合わせ
        • オリジンが異なる時に制限されるもの
          • fetch()
          • Cookieの読み書き
          • WebStorageやIndexedDBへのアクセス
          • CanvasのgetImageData()
        • CORS(Cross-Origin Resource Sharing)
          • リクエストのOriginヘッダにオリジンを設定して送信する
            • サーバはそのオリジンを確認する
              • 通信許可ならAccess-Control-Allow-Originヘッダを設定したレスポンスを返す
                • 一定期間クロスオリジンの通信が許可される
      • ローカルファイルアクセス
      • クリップボードアクセス
  • 代表的な攻撃
    • クロスサイトスクリプティング(XSS)
      • ${name}部分に<script>alert(document.cookie)</script>などを入れられる
        • セッションIDの漏洩
          • セッションハイジャック
      • 対策
        • &lt;というようなHTMLエンティティに置換して埋め込む
        • Cookieの値を信用しない
          • 重要情報はサーバ上に保存する
          • Cookieは言語やスタイルの設定などにする
        • セッションIDはCookieをHttpOnlyにしてJSから読み取れないようにする
    • クロスサイトリクエストフォージェリ(CSRF)
      • ログイン済みのユーザに攻撃サイトを表示させてiframeでパスワードリセットさせるなど
    • 対策
      • 本来の<form>タグからしかリクエストできないようにする
        • <form>に隠しパラメータとしてサーバで生成した乱数を設定する
  • Credential Management API
    • JSからブラウザの「バスワードを保存」機能を利用できる
  • JSを通じて得られるハードウェアに関する情報
    • 意図的に不正確な値が返されることがある
      • 情報を集めてユーザーを特定するフィンガープリンティングを避けるため

パフォーマンスを学ぶ

  • 詳細な時間測定
    • performance.now()
    • console.time()console.timeEnd()で時間を測る
    • リソースの取得を計測する
      • performance.getEntriesByName(name)
        • スクリーンショット 2021-09-14 8.45.12.png
    • Webサイト表示のパフォーマンスを計測する
      • performance.getEntriesByType("navigation")[0]
        • スクリーンショット 2021-09-14 8.48.16.png
  • パフォーマンスを改善する
    • Web Worker
      • worker1 = new Worker("js/worker1.js")
      • やりとりできるデータ
        • 関数オブジェクトとDOMノード以外
          • 構造化クローンして受け渡されるから
            • コピーが重すぎる
              • Transferableオブジェクト
                • 参照だけ受け渡す
                  • 高速になる
    • WebAssembly

学び続けるために

  • ECMAScript
    • 標準化までの5ステージ
      • 0: 藁人形(Strawperson)
        • 「こういう仕様を考えた」と宣言した状態
      • 1: 提案(Proposal)
        • 課題と解決策とAPIの概要、代表者が決まる
          • デモなどで実際の動作を確認する
      • 2: 草案(Draft)
        • 議論が深まり正式なフォーマットで仕様がまとめられる
          • 公式のフォーマットで正確に記述することが目的
      • 3: 候補(Candidate)
        • 仕様書が完成して指名されたレビュアーとすべてのECMAScriptエディタが承認する
          • 実際の利用からフィードバックを得て改善することが目的
      • 4: 完了(Finished)
        • 受け入れテストが作成される
          • ECMA総会に提出されて批准されると標準化が完了となる
  • Web API
    • World Wide Web Consortium(W3C)
    • Web Incubator Community Group(WICG)
    • Web Hypertext Application Technology Working Group(WHATWG)
      • Living Standard
    • Internet Engineering Task Force(IETF)
    • Khronos Group
2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0