P256 console.errorとスタックトレース

console.logはメッセージだけなのに対して、console.errorではメッセージと共にスタックトレースが出力される。

P171 文字列とUnicode

const str = "リンゴ🍎";
const codePoints = convertCodePoints(str);
console.log(codePoints); // ["30ea", "30f3", "30b4", "1f34e"]
const codeUnits = covertCodeUnits(str);
console.log(codeUnits); // ["30ea", "30f3", "30b4", "d83c", "df4e"]

Unicodeは4バイトの表現が可能なため🍎が1文字
UTF-16サロゲートペア文字列は2バイト×2で表現しないといけないため2文字

インデックス 0 1 2 3 4
文字列 🍎
UnicodeのCode Point(16進数) 0x30ea 0x30f3 0x30b4 0x1f34e
UTF-16のCode Unit(16進数) 0x30ea 0x30f3 0x30b4 0xd83c 0xdf4e

JavaScriptには、文字列におけるCode Unitを数えるプロパティ(String#length)は存在するが、Code Pointを数えるメソッド等は現在存在していない。
 そのため、Array.fromを用いて変換後に数えるしか現状はない。

const codePoints = Array.from("リンゴ🍎");
console.log(codePoints.length); // 4
console.log(codePoints); // ["リ", "ン", "ゴ", "🍎"]

P147 Chapter15 文字列

【15.1 文字列を作成する】
・ダブルクォートとシングルクォートに意味的な違いはJavaScriptにはない。
・ES2015より、テンプレートリテラル(バッククォート`)が追加された。

【15.2 エスケープシーケンス】

エスケープシーケンス 意味
\' シングルクォート
\" ダブルクォート
\\ バックスラッシュ
\n 改行
\t タブ
\uXXXX Code Unit(\uと4桁のHexDigit)
\u{X} Code Point(\u{}のカッコ中にHexDigit)

【15.4 文字へのアクセス】
const str = "文字列";とした場合、str[0]、str[1]、etc...というアクセスが可能である。
インデックスの値は、0以上2^53 - 1未満の整数が指定可能である。

【15.5 文字列とは】
JavaScript(ECMA Script)は文字コードとして、Unicodeを採用し、文字をエンコードする方式としてUTF-16を採用している。
・String#charCodeAtメソッドで、文字列の指定インデックスのCode Unitを整数で返せる。

const str ="アオイ";
console.log(str.charCodeAt(0).toString(16)); // "30a2"

・Code Unitをhex値から文字列へと変換するにはString.fromCharCodeメソッドを使う。

const str = String.fromCharCode(
    0x30a2, // ア のCode Unit
    0x30aa, // オ のCode Unit
    0x30a4  // イ のCode Unit
);
console.log(str); // アオイ

ECMAScriptの内部表現としてUTF-16を用いているだけで、JavaScriptファイル自体のエンコードは、UTF-16以外の文字コードであっても問題ない。

【15.6 文字列の分解と結合】

const str1 = "赤・青・緑".split("・");
console.log(str1); // ["赤", "青", "緑"]

const str2 = "赤・青・緑".split("・").join("、");
console.log(str2); // "赤、青、緑"

const str3 = "a     b     c     d".split(/\s+/);
console.log(str3); // ["a", "b", "c", "d"]

【15.9 文字列の一部を取得】
・sliceメソッドもsubstringメソッドも非破壊的であり、どちらを利用するかはほぼ好みの問題

const str = "ABCDE";

console.log(str.slice(1)); // "BCDE"
console.log(str.slice(1, 5)); // "BCDE"
console.log(str.slice(-1)); // "E"
console.log(str.slice(1, 4)); // "BCD"
console.log(str.slice(4, 1)); // "" (第一引数 > 第二引数の場合は常に空文字列を返却)

console.log(str.substring(1)); // "BCDE"
console.log(str.substring(1, 5)); // "BCDE"
console.log(str.substring(-1)); // "ABCDE" (マイナスを指定すると0として処理)
console.log(str.substring(4, 1)); // "BCD" (第一引数 > 第二引数の場合、引数を反転させて処理[str.substring(1, 4)と等価])

・indexOfメソッドと扱うのもよくやる

const url = "https://example.com?param1";
const indexOfQuery = url.indexOf("?");
const queryString = url.slice(indexOfQuery);
console.log(QueryString); // "?param=1"

【15.10 文字列の検索】

const str = "にわにはにわにわとりがいる";
console.log(str.indexOf("にわ")); // 先頭インデックスを返すため0
console.log(str.lastIndexOf("にわ")); //  // 末尾のヒットした際の先頭文字のインデックスを返すため6(7文字目)
console.log(str.indexOf("さんわ")); // 指定した文字列が見つからない場合は-1

[真偽値の取得]
 ・String#startsWith(検索文字列):検索文字列が先頭に含むかの真偽値を返す
 ・String#endsWith(検索文字列):検索文字列が末尾に含むかの真偽値を返す
 ・String#includes(検索文字列):検索文字列を含むかの真偽値を返す

【15.11 正規表現オブジェクト】
[生成方法]
 ・const patternA = /パターン/フラグ; // 正規表現リテラルで生成
 ・const patternB = new RegExp("パターン", "フラグ"); //RegExpコンストラクタで生成

[正規表現リテラルRegExpコンストラクタで生成した場合の違い]
正規表現リテラルは静的なパターンの場合に利用する
RegExpは動的にパターンが変わる場合に利用する

P121 Chapter13 プロトタイプオブジェクト

【13.1 Objectはすべての元】
殆ど全てのオブジェクト(※1)は、Object.prototypeプロパティに定義されたprototypeオブジェクトを継承している。prototypeオブジェクトとは、すべてのオブジェクトの作成時に自動的に追加される特殊なオブジェクトである。prototypeオブジェクトが保持しているメソッドは、例えばhasOwnProperty, toString, valueOfなどである。prototypeオブジェクトに組み込まれているメソッドはプロトタイプメソッドと呼ぶ。

※1 Object.create(null);やnew Map();などはObject.prototypeを継承しないオブジェクトが生成される。

【13.2 プロトタイプメソッドとインスタンスメソッドの優先順位】
インスタンスとプロトタイプオブジェクトで同じ名前のメソッドがある場合には、インスタンスのメソッドが優先解決される。

【13.3 in演算子とObject#hasOwnProperyメソッドの違い】
hasOwnProperyメソッドは、そのオブジェクト自身が指定したプロパティを持っているかを判定する。
in演算子はオブジェクト自身が持っているかを判定し、持っていない場合はprototypeオブジェクトまで探索して持っているかを判定する。

P115 12.7.1 オブジェクトの列挙

・Object.keysメソッド:オブジェクトのプロパティ名の配列を返す
・Object.valuesメソッド[ES2017]:オブジェクトの値の配列を返す
・Object.entriesメソッド:オブジェクトのプロパティ名と値の配列の配列を返す

P91 Chapter11 ループと反復処理

【11.7 for...in文】
・for...in文は親オブジェクトの列挙可能なものがあるかまで探索してしまう。
・for...inは正しく扱うのが難しく、代わりとなる手段が豊富にあるため、基本使わない方が良い

【11.8 for...of文】[ES2015]
・iterableオブジェクト(Symbol.iteratorというメソッドを実装したオブジェクトのこと)に対して、利用可能である。
・配列、Stringオブジェクト、TypedArray、Map、Set、DOM NodeListなど、Symbol.iteratorが実装されているオブジェクトは多い。
・利用例

const array = [1, 2, 3];
for (const value of array) {
    console.log(value); // 1 2 3
}

const str = "牛丼屋";
for (const value of str) {
    console.log(value); // "牛" "丼" "屋"
}

P64 Chapter8 関数と宣言

【8.2 関数の引数】

  • 8.2.1 呼び出し時の引数が少ないとき

定義した関数の仮引数よりも呼び出し時の引数が少ない場合、余った仮引数にはundefiendという値が代入される。

  • 8.2.2 デフォルト引数[ES2015]

仮引数に対して仮引数 = デフォルト値という構文で、仮引数毎にデフォルト値を指定できる。
デフォルト引数では、引数が渡されなかった場合のみデフォルト値が入る。

  • 8.2.3 呼び出し時の引数が多いとき

関数の仮引数に対して引数の個数が多い場合、あふれた引数は単純に無視される。
但し、後述する可変長引数の記法がある場合は、その限りではない。


【8.3 可変長引数】

  • 8.3.1 Rest parameters[ES2015]

Rest parametersは、仮引数の前に...をつけた仮引数のことで、残余引数とも呼ばれる。
Rest parametersには、関数に渡された値が配列として代入される。

一方、配列を展開して関数の引数に渡すSpread構文というのもある。
Spread構文は、配列の前に...をつけた構文のことで、関数には配列の値を展開したものが引数として渡される。
次のコードでは、arrayの配列を展開してfn関数の引数として渡している。

function fn(x, y, z) {
    console.log(x);
    console.log(y);
    console.log(z);
}
const arrayA = [1, 2, 3];
fn(...arrayA); // fn(arrayA[0], arrayA[1], arrayA[2]);と等価
  • 8.3.2 arguments変数

昔は当文法が使えたが、現代JSではRest parametersを使える環境ではRest parametersを使うべきである。
(理由は本書に記載有)


【8.4 関数の引数と分割代入】

function printUserId({ id }) // {プロパティ変数} という記述が肝
    console.log(id); //42
}

const user = {
    id: 42;
};
printUserId(user);

配列に対しては、以下の様な記述が可能

function print([first, second]) { // 配列の場合は、{}は不要
    console.log(first); // 1
    console.log(second); // 2
}

const array = [1, 2];
print(array);


【8.5 関数はオブジェクト】

  • 8.5.1 関数式
const 変数名 = function() { // 関数式は変数名で参照できるため、関数名は省略できる
    // hoge
}
function 関数名() { // 関数宣言では関数名は省略できない
    // hoge
}

上記の様な名前を持たない関数を匿名関数(無名関数)と呼ぶ。
なお、再帰的に関数を呼びたい場合に匿名関数に名前を付与する場合もある。
但し、名前を付けた場合においても、関数内部から呼び出せても、関数外部から呼び出す事はできない。

- 8.5.2 Arrow Function[ES2015]
(基本文法)

const 変数名 = () => {
    // hoge
    return 関数の返す値; 
};

(Arrow Functionの省略記法)
 ・関数の仮引数が1つのときは()を省略できる
 ・関数の処理が1つの式である場合、ブロックとreturn文を省略できる
  なお、省略した場合は、評価した結果をreturnの返り値として扱う

// 仮引数の定義
const fnA = () => {/* 仮引数がないとき */};
const fnB = (x) => {/* 仮引数が1つのみのとき */};
const fnC = x => {/* 仮引数が1つの時は()を省略可能 */};
const fnD = (x, y) => {/* 仮引数が複数の時 */};
// 次の2つの定義は等価
const mulA = x => {return x * x};
const mulB = x => x * x; // 上記文の略記法

(Arrow Functionの特徴)
 ・名前を付けれない
 ・thisが静的に決定する
 ・functionキーワードに比べて短く書くことが可能である
 ・newできない
 ・arguments変数を参照できない

上記を理解すると、例えば以下の様な記述短縮が生まれる。(※1)

const array = [1, 2, 3];
// 通常記法
const doubleArray = array.map(function(value) {
    return value * 2;
});
console.log(doubleArray); // [2, 4, 6]
//略記法
const doubleArray= array.map(value => value *2);
console.log(doubleArray); // [2, 4, 6]

Arrow Functionで問題ない場合は、Arrow Functionで書き、そうでない場合のみfunctionキーワードを使う事が推奨される。
(thisの問題、関数とスコープ問題が起きにくいコードが書きやすいため)

※1
Java屋にしてみればきもち悪くて仕方ないが、JavaScriptにおいてmapは配列が保持しているお便利関数で、自身の配列の各要素を用いて別の配列を生み出すというメソッドである。
developer.mozilla.org

  • 8.5.3 コールバック関数

引数として渡される関数のことをコールバック関数と呼ぶ。
一方、コールバック関数を引数として扱う関数やメソッドを高階関数と呼ぶ。
例えば、配列のforEachメソッドはコールバック関数を引数として受け取る高階関数である。
forEachメソッドは、配列の各要素に対してコールバック関数を一回呼び出す事ができる。

const arrayA = [1, 2, 3]; //テスト用の配列を宣言しているだけ
const kanB = valueC => console.log(valueC); // コールバック関数 kanB は、引数 valueC をconsole.logに渡して標準出力するだけの関数
arrayA.forEach(kanB); 配列が持っているforEachメソッドを実行する事で、配列内の各値をkanBの引数として実行できる(そのため、kanBは引数は一つのみとなっている)


【8.6 メソッド】
オブジェクトもプロパティとして定義されている関数をメソッドと呼ぶ。
以下の記法で書くことができるが、8.6.1 メソッドの短縮記法にある通り、できればメソッドの短縮記法で書くべきである。

const obj = {
   method1: function() {
        // functionキーワードでのメソッド
    }, //メソッドを複数定義する場合は、メソッド間にカンマが必要
    method2: () => {
        // Arrow Functionでのメソッド
    },
    method3() {
        // 短縮記法
    }
}