「JavaScript 第7版」を読む(3章まで)
JavaScriptをずっと昔から雰囲気で使っていて、体系的な理解が不足しているのと、現代的な書き方に慣れずに大昔の書き方をする傾向にあるので、いまさらながらJavaScriptの本を読むことにした。
ECMAScript Version | 年 |
---|---|
5 | 2009 |
6 | 2015 |
7 | 2016 |
8 | 2017 |
9 | 2018 |
10 | 2019 |
11 | 2020 |
12 | 2021 |
13 | 2022 |
14 | 2023 |
年とバージョン番号は9ずれている。
ECMAScript version history - Wikipedia
esnextというのは常に次にリリースされる予定のバージョンを指しす。常に最新の仕様をカバーしたものになる。
Unicodeエスケープシーケンスは文字列リテラル、正規表現リテラル、識別子の中で使える。
Javaのようにどこでも使えるわけではない。なので、以下のようなことはJavaScriptではできない。
Unicode正規化はしない。だからこういうことになる。
const 커피 = "a";
const 커피 = "b";
console.log(커피); // => a
console.log(커피); // => b
console.log(\uCEE4\uD53C); // => a
console.log(\u110F\u1165\u1111\u1175); // => b
セミコロンは省略できる。
文の終わりに都度セミコロンを書く流儀の人と、省略できる場合にはセミコロンを書かない流儀の人といる。
JavaScriptは行末にセミコロンがない場合に、セミコロンがなくても解釈できる場合はそのままにし、セミコロンを挿入しないと解釈できない場合に限りセミコロンを挿入して文の終わりとする。(3つの例外がある)
以下は f(a + b)
で解釈できるので、1つの文になる。
let x = f
(a + b).toString()
1つ目の例外として、 return
, throw
, yield
, break
, continue
の直後に改行がある場合は常にセミコロンが挿入される。
以下は return; a;
になる。
return
a;
2つ目の例外は ++
, --
に関して。後置演算子として行をまたいではいけない。
3つ目の例外はアロー関数 =>
に関して。 =>
を次の行に書いてはいけない。
JavaScriptの型
- 基本型
null
undefined
Symbol
- 数値
- 文字列
- 論理値
- オブジェクト型
配列はオブジェクト型に含まれる。
関数やクラスもオブジェクト型。
基本型はすべて不変。文字列もJavaと同じく不変。
typeof null
は "object"
が返される。
console.log(typeof undefined); // => "undefined"
console.log(typeof null); // => "object"
数値は64ビット浮動小数点数。整数として正確に表現できるのは正負とも絶対値が2の53乗まで(2の53乗を含む)。
算術演算子 **
はES6から使えるようになった。
これもES6からある。
Math.hypot(a, b, c)
のように使う。
で log1p
を使うべき。
expm1
はその逆関数
0 / 0
は NaN
になる。
それ以外のゼロ除算は Infinity
または -Infinity
になる。
これはハマりそう。
const zero = 0;
const negz = -0;
console.log(zero === negz); // => true
console.log(1 / zero === 1 / negz); // => false
BigInt
型は従来の数値型では表現できない大きな整数を表現できる。
リテラルは 10n
のように n
を付ける。
console.log(2n ** 63n); // => 9223372036854775808n
console.log(2n ** 64n); // => 18446744073709551616n
console.log(BigInt("18446744073709551616")); // => 18446744073709551616n
JavaScriptの文字列はJavaと同じくUTF-16でエンコードされており、文字列を操作する各種メソッドはのUTF-16のコード単位で処理する。
for/of
ループで文字を反復処理する場合は、サロゲートペアが考慮され、コードポイント単位になるらしい。
コードポイントが1文字に対応しない場面では for/of
は使えない。
const s1 = "커피"; // \uCEE4\uD53C
const s2 = "커피"; // \u110F\u1165\u1111\u1175
console.log(s1.length); // 2
for (const ch of s1) {
// 2回ループする
console.log(ch);
}
console.log(s2.length); // 4
for (const ch of s2) {
// 4回ループする
console.log(ch);
}
ES6以降では、Unicodeエスケープシーケンスはコードポイントを中かっこで囲める。中かっこで囲めば4桁以外のコードポイントも表現できる。
console.log("\u{20B9F}"); // 𠮟
console.log("\u{A5}"); // ¥
normalize
というUnicode正規化をするメソッドがある。
const s1 = "커피"; // \uCEE4\uD53C
const s2 = "커피"; // \u110F\u1165\u1111\u1175
console.log(s1 === s2); // => false
console.log(s1 === s2.normalize("NFC")); // => true
console.log(s1.normalize("NFD") === s2); // => true
文字列の繰り返しは repeat
というメソッド。
console.log("Hello".repeat(3)); // => HelloHelloHello
console.log("Hello" * 3); // => NaN
テンプレートリテラルは {}
の中の式が展開される。
const name = "world";
console.log(`\
Hello,
${name.toUpperCase()}!
`);
// => "Hello,\nWORLD!\n"
通常の文字列リテラルで使えるバックスラッシュによるエスケープをそのまま使える。
論理型に型変換すると
値 | 論理値に型変換すると |
---|---|
undefined |
false |
null |
false |
"" |
false |
0 |
false |
-0 |
false |
NaN |
false |
Infinity |
true |
{} |
true |
[] |
true |
console.log(null == undefined); // => true
console.log(undefined == undefined); // => true
console.log(null === undefined); // => false
console.log(undefined === undefined); // => true