Closed18
メモ:JavaScript第7版(サイ本)を読んでる
サイ本買ったから読んでみる。
読みながら、気になったところメモしていく。
1章 JavaScriptの概要
- JavaScriptは動的なインタプリタ型高級言語
- ES6(2015リリース)より単なるスクリプト言語から、大規模な開発なソフトウェア開発にも使える汎用的なプログラミング言語になった
- クラスやモジュールの追加など
- JavaScriptのインタプリタ
- Webブラウザのコンソール
- Node
- 整数(
1
)も実数(0.01
)も同じ数値型 - 評価すると値が作り出されるような語句のようなものを、式という
- 関数をオブジェクトと使うとメソッドになる
- クラス名は大文字から記述するのが慣習
- コアJavaScript言語は非同期ではない
2章 字句構造
- JavaScriptプログラムは、Unicode文字コードを使って記述
- Unicodeエスケープシーケンス => ASCII文字を使ってUnicode文字を記述できる
-
return
,break
,continue
キーワードと、直後の式の間には;
を入れない
3章 型、値、変数
- JavaScriptの型は、基本型とオブジェクト型の二つ
- JavaScriptインタプリタは、自動的にガーベッジコレクションを行う
- オブジェクト指向とは、グローバルに定義された関数を使って、さまざまな型の値を処理するのではなく、その型で定義されたメソッドを使って、値を処理するような考え
- 整数、16進数、2進数、8進数
let billion = 1000_000_000;
- まるめ誤差
- JavaScriptではシングルクオートを使い、HTMLではダブルクオートを使う
- テンプレートリテラル:式を評価し、式の値を文字列に変換し、文字列リテラルと結合したもの
typeof null; // 'object'
- オブジェクトは参照型
let b = Array.from(a);
- 明示的な型変換:
Boolean()
,String()
,Number()
- オブジェクトから基本型への変換アルゴリズム
- 文字列優先
- 数値優先
- 優先度なし
- 変数宣言時に初期値を代入するのが、良いプログラミングスタイル
- 変数、クラス、関数の定義はブロックスコープ
- NodeやクライアントサイドJavaScriptモジュールでは、グローバル変数のスコープは、変数が定義されているファイル、一方、従来のクライアントサイドJavaScriptでは、グローバル変数のスコープはHTMLドキュメント
- strictモード
4章 式と演算子
- JavaScript インタプリタが評価して値を生成できるものを式と呼ぶ
true + true // => 2
-
==
は等しい、===
は同値であると読む - しっかりとした文字列比較:
String.localeCompare()
-
Object
とArray
に in演算子
let a = [1, 2, 3]
a instanceof Array // => true
- &&演算子で、左辺が
false
だった場合、右辺は評価すらしない i = j = k = 0; // 3つの変数を 0 に初期化する
-
eval()
はソースコード文字列を動的に評価する typeof null // "object"
5章 文
- 意図的に空文を使用する場合は、その旨をコメントしておく
- JavaScriptの5つのループ文: while, do/while, for, for/of, for/in
- 配列や文字列、セット、マップに対して for/of を使う
let frequency = {};
for (let letter of "mississippi") {
if (frequency[letter]) {
frequency[letter]++;
} else {
frequency[letter] = 1;
}
}
frequency // => { m: 1, i: 4, s: 4, p: 2 }
- 配列を扱うときには、 for/in ではなく for/of を使う
- ラベル文:任意の文にラベルをつけることができる
- JavaScript インタプリタ自身がエラーをスローするときには、 Error クラスとそのサブクラスが使われる
- 例外はコールスタックを遡っていく
- try ブロック中で例外が発生し、例外を処理する catch ブロックが存在する場合は、まず catch ブロックに処理が移動し、次に finally ブロックが実行される
- class 本体のコードや、ES6 モジュール中のコードは自動的に strict コードになる
- strict モード
- with 文は使えない
- 変数は全て宣言しなければならない
- メソッドではなく、関数として呼び出された関数中において、 this の値は undefined になる
- 関数宣言は関数オブジェクトを生成し、指定された名前に代入する
- 関数とは異なり、クラス宣言はホイスティングされない
- モジュールとは、独自のグローバルな名前空間を持つ、JavaScript コードが含まれたファイル
第6章 オブジェクト
- オブジェクト自身のプロパティ以外に、他のオブジェクトからプロパティを継承することができる。この継承対象になるオブジェクトをプロトタイプと呼ぶ。
- コード中で生成したオブジェクトのすべてのプロパティは、書き込み可、列挙可、再設定可。
- すべてのJavaScriptオブジェクトには、もう一つの別のオブジェクトが関連づけられていて、これをプロトタイプと呼び、オブジェクトはこのプロトタイプのプロパティを継承する。
Object.create(Object.prototype) == {} == Obejct();
- in 演算子、
hasOwnProperty()
メソッド、propertyIsEnumerable()
メソッド Object.assign({}, defaults, o) == {...defaults, ...o}
-
JSON.stringihfy()
とJSON.parse()
- JSONの書式は、JavaScript構文のサブセット
-
toLocaleString()
メソッド - 同じ文字列を引数にして2つのSymbolを作ったとしても、この2つのSymbolは異なるものになる
- サードパーティ製のコードの中のオブジェクトに対して、プロパティを追加しなければならない場合、プロパティ名としてSymbolを使えば、既存のプロパティと衝突することはない
- スプレッド演算子が展開するのはオブジェクトの独自のプロパティだけ。
- プロパティのゲッターメソッドとセッターメソッド
- 列挙プロパティと独自プロパティ
第7章 配列
- 配列は、
Array.prototype
からプロパティを継承する - 文字列もスプレッド演算子可能
- 配列からSetオブジェクトに変換し、重複要素を削除する
- 配列は
length
プロパティを持つ、オブジェクトは持たない [1, 2, 3, 4, 5].length(3); // [1, 2, 3]
- delete演算子で配列の要素を削除できるが、配列の長さは変わらない
-
forEach()
は疎な配列に対して、存在しない要素に対しては関数を呼び出さない - 疎な配列に対して、
map()
メソッドを行った場合、返される配列も元の配列と同じように疎になる -
filter()
メソッドは疎な配列の場合、存在しない要素をスキップするため、疎な配列を密な配列に変換するのに使える -
splice()
メソッドはこのメソッドを呼び出した配列を変更する -
copyWithin()
メソッド -
sort()
メソッドは既存の配列をソートする Array.isArray([]); // true
Array.prototype.join.call("JavaScript", " "); // "J a v a S c r i p t"
第8章 関数
- 関数の呼び出しには、呼び出しコンテキストという値がある。
this
キーワードの値- アロー関数は、呼び出しコンテキストで
this
が定義されず、関数が定義された環境のthis
が継承される
- アロー関数は、呼び出しコンテキストで
- 関数宣言ぶんは巻き上げが起こる
- アロー関数は
prototype
プロパティを持たない
f?.(x);
// 以下と同じ
(f !== null && f !== undifined) ? f(x) : undefined;
- メソッドとして使われる関数には、暗黙的に、メソッドが呼び出されたオブジェクトが渡される
- 関数呼び出しや、メソッド呼び出しの前に
new
キーワードを記述すると、コンストラクタ呼び出しになる - Arguments オブジェクト
-
arguments
を使っている関数を見たら、一般的には残余パラメータ (...args
) で置き換えられる
-
- 関数定義で
...
を使った場合は、関数の複数の引数を配列にまとめる。残余パラメータ - 関数の実行を終了した後も値を保持し続ける「静的」変数を作成したいときは、関数自身のプロパティを使うと便利
- 構文スコープの基本:JavaScriptの関数は、定義されたときに有効なスコープチェーンを使って実行される
- クロージャー
- クロージャ自身が定義された外側の関数のローカル変数のバインドを抱え込む
- 関数呼び出しの時のローカル変数を閉じ込めるので、ローカル変数をプライベート変数のように使える
function counter() {
let n = 0;
return {
count: function() { return n++; },
reset: function() { n = 0 },
};
}
let c = counter();
let d = counter();
c.count() // 0
d.count() // 0
c.reset()
c.count() // 0
d.count() // 1
- 関数の
length
プロパティは、関数を宣言したときのパラメータ数を示す -
call()
メソッドと、apply()
メソッドを利用すると、あるオブジェクトのメソッドであるかのように関数を間接的に呼び出すことができる
f.call(o);
f.apply(o);
// 以下と同じ
o.m = f; // f を一時的に o のメソッドにする
o.m();
delete o.m; // 一時的に使いしたメソッドを削除する
// 同じ
f.call(o, 1, 2);
f.apply(o, [1, 2]);
function f(y, z) { return this.x + y + z; }
let g = f.bind({x: 1}, 2);
g(3); // 6
- Function()コンストラクタ
const f = new Funtion("x", "y", "return x * y;");
- 高階関数は、関数に対して処理を行う関数。引数として一つ以上の関数を受け取り、新たな関数を返す
-
memoize()
関数は、新しいオブジェクトを生成しキャッシュとして使う。このオブジェクトはローカル変数に保存されるので、返された関数(のクロージャ)中に閉じたものになる
第9章 クラス
- 同じプロトタイプオブジェクトからプロパティを継承する一連のオブジェクトをクラスと呼ぶ
- 同じクラスのオブジェクトは、同じプロトタイプオブジェクトのプロパティを継承する
// コンストクタ関数
function Range(from, to) {
this.from = from;
this.to = to;
}
// 全 Range オブジェクトがこのオブジェクトを継承する
Range.prototype = {
hoge: function(x) { return ... };
...
}
let r = new Range(1, 3); // Rangeオブジェクトを生成
r.hoge();
- クラスは大文字から始めるのが一般的
r instanceof Range // => true: r は Range.prototype を継承している
- クラス宣言の本体中のコードは暗黙的に strict モードになる
- 静的メソッド = クラスメソッド、
static
キーワードを記述 - クラスのインスタンスに対して呼び出す通常のメソッドを、インスタンスメソッドと呼ぶ
- スーパークラスとサブクラス、サブクラスのインスタンスは、スーパークラスのメソッドを全て継承する
-
extends
キーワード -
super
キーワードで、スーパークラスのコンストラクタや、オーバーライドされたスーパークラスのメソッドを呼び出すことができる
-
- オブジェクト志向プログラミングでよく知られている原則に、「継承よりも合成を優先」というものがある
- アロー関数は prototype プロパティを持たないので、コンストラクタとしては使えない
第10章 モジュール
- モジュール化とは、実装をカプセル化すること
- ES6のモジュールは、ファイルがモジュール
-
<script type="module">
ブラウザ上でES6 モジュールを使う - Import は hoisting される
- JavaScript の初期は、即時実行関数式によって、モジュール化を実現していた
第11章 JavaScript標準ライブラリ
- オブジェクトが持つ
toString
などの処理が複雑となる継承プロパティを含めないように、SetクラスとMapクラスが導入された - Setは配列に似ているが、順序付やインデックス付がされず、重複を許さない
- Setはメンバーかどうかを調べる処理に最適化されている
let oneDigitPrimes = new Set([2,3,5,7]);
oneDigitPrimes.has(2); // => true
- Mapは配列と似ているが、連続した整数のセットをキーとして使用するのではなく、任意の値をインデックスとして使うことができる
- 正規表現の定義
-
RegExp()
コンストラクタの利点は、正規表現を動的に作成できる
-
let pattern = /s$/;
let pattern = new RegExp("s$");
- どの句読点文字を
\
でエスケープしなければいけないか覚えられないから、句読点文字の前には常に\
を付加するようにする -
/p
構文
let greekLetter = `/p{Script=Cyrillic}/u`;
- 正規表現、名前付きのキャプチャグループ
- JavaScriptがミリ秒を使い切るのは27万年以上先
- データ構造をバイトや文字列のストリームに変換する処理を、シリアライズ(マーシャリング、ピックリング、直列化)と呼ぶ
let opts = {year: "numeric", era: "short"};
Intl.DateTimeFormat("en-u-ca-japanese", opts).format(d) // => "2 Reiwa"
-
Intl.Collator
オブジェクトを作成して、compare()
メソッドをsort()
メソッドに引数として渡せば、ロケールに適切な順序で文字列を並び替えることができる - URL API
第12章 イテレータの仕組み
- 反復オブジェクト:配列や Set や Map
- イテレータオブジェクト:反復処理を行う
- 反復結果オブジェクト:反復の各ステップの結果を保持する
const seq = function*(from, to) {
for(let i = from; i <= to; i++) yield i;
};
[...seq(3,5)] // => [3,4,5]
- ジェネレータ関数の一般的な用途はイテレータを作ること
- ジェネレータの基本機能は、計算処理を一時的に中止し、途中結果を生成し、後ほど計算を再開すること
-
yield
によって計算処理を一時停止して、任意の入力値を使って任意のタイミングで処理を再開できる - ジェネレータ関数では
yield
キーワードを使って、イテレータから返す値を指定する -
next()
を呼び出すたびに、ジェネレータ関数は次のyield
式まで実行され、yield
式の値がイテレータの戻り値になる -
yield
がなくなると、ジェネレータ関数は戻り、反復処理が完了する
第13章 非同期JavaScript
- JavaScriptの最も基本的な非同期プログラミングは、コールバックを使う方法
- Promiseが「解決される」、「満たされる」
- 非同期プログラミングをする時は、注意深くエラーを処理することが非常に重要
- ファイルを閉じるや、ネットワークを接続を閉じるなど、
finally()
コールバックで後始末を行う - Promiseのコールバックの戻り方
- コールバックから返されるPromiseを使って正常に戻る
-
null
を返す - エラーをスローする
- Promiseの並行処理
Promise.all()
- 非同期的なコードは、通常の動機的なコードと違って、値を返したり、例外をスローしたり出来ない。
- 満たされたPromiseは同期的なコードの戻り値のようなもの
- 失敗したPromiseは同期的なコードがスローする値のようなもの
- 関数を
async
と宣言すると、関数の戻り値はPromise
となる let [value1, value2] = await Promise.all([getJSON(url1), getJSON(url2)]);
async funciton f(x) { /* 関数本体 */ };
function f(x) {
return new Promise(function(resolve, reject) {
try {
resolve((function(x) { /* 関数本体*/ })(x));
}
catch(e) {
reject(e);
}
});
}
- 従来は、非同期処理はイベントやコールバック関数を使って処理していた。
- Promiseによって、コールバック関数を構造化するための新しい方法が提供された
-
async
やawait
のキーワードを使うと、一見同期的なコードに見えるような非同期的なコーろを記述できるようになる
第14章 メタプログラミング
- メタプログラミングは、コードを記述して、他のコードを操る
- 書き込み可属性、列挙可属性、再定義可属性
- 拡張可属性
第15章 Webブラウザ上のJavaScript
- HTML パーサーが
<script>
要素を見つけると、ディフォルトでは、ドキュメントの解釈や描写を中断し、スクリプトを実行するので、HTML が出力されなくなる
-defer
,async
属性を使うことで、スクリプトの実行を遅延できる - DOM: HTML ドキュメントコンテンツを扱うための API
- JavaScript はシングルスレッドのプログラミング言語
- スクリプトや、イベントハンドラが実行しているときは、ブラウザはユーザーの入力に応答できない
- Web Worker
- 並行実行の仕組み
- 計算量の多い処理を実行するためのバックグラウンドスレッド
- CORS:サーバ側で情報を提供するオリジンを決められるようにする
document.addEventListener("click", handleClick, {
capture: true,
once: true,
passive: true
});
- カスタムイベントのディスパッチ
-
innerHTML
は効率的ではない- 要素のコンテンツを文字列に変換するシリアライズ処理と、文字列を要素のコンテンツに変換する解析処理をなんども行うことになる
- ドキュメントは、要素ノードとテキストノードから構成される抽象的なツリー構造
- Web Components は React などのフレームワークと同じような機能をブラウザが提供する
- Documentfragrament は Node 型の一種。兄弟ノードのグループを一つとして扱いたいときに一時的な親ノードとなる
- シャドウDOM の重要な特徴はカプセル化。シャドウルートの子孫要素は、通常の DOM ツリーから見えなくなる
-
fetch()
メソッドは、HTTP および HTTPS リクエストを送信するための Promise ベースの APIを定義 - WebSocket は HTTP とともに使うことを目的としたネットワークプロトコル。非同期のメッセージパッシング API を定義している
- 同一オリジンリクエスト:
fetch()
に渡される URL が、リクエストを送信するスクリプトが含まれるドキュメントと同じオリジン(プロトコルとホストとポートが同じ)- クロスオリジンリクエストには、サーバが適切な「 Access-Control-Allow-Origin 」ヘッダでリクエストに応答する必要がある
- Storage オブジェクトに格納されたプロパティは永続します
- クライアントサイドストレージは、ドキュメントのオリジンごとに保管される
- クッキーは、サーバーサイドスクリプトで使われることを前提に設計されている
- クッキーとして保存されたデータは、クライアント側でしか使わなかったとしても、HTTP リクエストを送信するときに、全てのデータがサーバに送信される
- Session storage を使って保存されたデータは、ウィンドウやタブを閉じたら削除される
- IndexedDB:Web プラットフォームのシンプルなオブジェクトデータベース
- Service worker は、ワーカースレッドの一種。サービスを提供する Web アプリケーションからのネットワークをインターセプトし、検査sh、応答する機能を持つ
第16章 Node上のサーバーサイドJavaScript
- node コマンドは、コマンド引数で指定されたJavaScriptファイルを実行します
- Node プログラムは非同期。コールバックやイベントハンドラになっている。
- .mjs: ES6のモジュールとして読み込む
- .cjs: commonJSとして読み込む
-
util.promisify()
ラッパーで、多くの Node 関数を Promiseベースに変換できる
第17章 JavaScriptのツールと拡張機能
- Webパフォーマンスについて
- 完全にコントロールできる変数として、JavaScriptのコード量が少なければ少ないほど、速く読み込まれ、速く実行される
このスクラップは2022/12/11にクローズされました