JavaScript The Definitive Guide 7th Editionを読んでます
いわゆる「サイ本」
知らなかったことを書きます
空白行
ただ単にセミコロン;
を置いただけの行は空白行となる。
空白行はなにも実行しない。
;
これは例えばfor文を作成するが何も実行したくないときに用いられる。
JavaScriptの文法ではfor文には必ず文が必要であるため、なにも実行しない空白行を配置する必要がある。
// 配列を初期化する
for(let i = 0; i < a.length; a[i++] = 0) ;
配列 → 数値の変換
配列から数値への変換はときに奇妙である。
空の配列をは0に変換されるが、配列が1つだけの数字の要素を保つ場合にはその数に変換される
console.log(Number([])) // 0
console.log(Number([10])) // 10
console.log(Number([10, 20, 30])) // NaN
console.log(Number(['a'])) // NaN
これは次のように評価された結果である
-
prefer-number algorithm
が使われた結果、配列のvalueOf()
メソッドがまず呼ばれることになる。 - 配列の
valueOf()
はプリミティブな値を返さない(配列をそのまま返す)ので、次にtoString()
メソッドが呼ばれる - 空の配列に
toString()
をした結果は空文字""
が返されるので0と評価される。配列が1つの要素だけを持っている場合には、その要素を返すため結果その値に評価される。(配列が複数の要素を持っている場合には、カンマ,
区切りの値が返される"10,20,30"
この値を数値に変換すると得られるのはNaN
だ。
参考
オプショナルチェイニング演算子
オプショナルチェイニング演算子はメソッドの呼び出しにも使える
a?.b?.c()
try/finally 構文
let i = 0
while(i < 10) {
try {
console.log(i)
} finally {
i++
}
}
完全に空のオブジェクトの作成する
Object.cretate()
にnull
を渡すと一切prototypeを継承しないオブジェクトの作成することができる。
const obj = Object.create(null)
console.log(obj.toString()) // error: Uncaught TypeError: obj.toString is not a function
flatMap
でmapとfilterを同時に行う
const array = [1, 2, 3, 4, 5]
array.flatMap(x => x % 2 === 0 ? [] : x ** 2) // [1, 9, 25]
条件に一致しない場合には空の配列を返すようにする。
空の配列要素は平坦化されることによって最終的には配列から取り除かれることになる。
includes()
とindexOf()
の違い
includes()
はNaN
と一致するが、indexOf()
は一致しない
const arr = [1, 2, NaN, 4]
console.log(arr.indexOf(NaN)) // -1
console.log(arr.includes(NaN)) // true
bind()
で部分適用
const add = (x, y) => x + y
const add1 = add.bind(null, 1)
console.log(add1(2)) // 3
momorize functionを作成する
function memorize(f) {
const cache = new Map()
return function(...args) {
const key = args.length + args.join('+')
if (cache.has(key)) {
return cache.get(key)
} else {
const result = f.apply(this, args)
cache.ste(key, result)
return result
}
}
new
キーワードで呼び出されているかどうか確認する
関数やコンストラクタがfunction Func() {
if (!new.target) {
console.log('Func must be called with new')
} else {
console.log('Func instantiated with new')
}
}
func() // Func must be called with new
new func() // Func instantiated with new
replace()
には第2引数として関数を渡すことができる
const s = '15 times 15 is 225'
s.replace(/\d+/gu, n => parseInt(n).toString(16)) // 'f times f is e1'
関数は以下の引数を受け取る
match 一致した部分文字列 (上記の $& に対応) です。
p1, p2, ... replace() の第一引数が RegExp オブジェクトだった場合、n 番目の括弧でキャプチャされたグループの文字列 (上記の $1, $2, などに対応) です。例えば /(\a+)(\b+)/ が与えられた場合、p1 は \a+ に対する一致、p2 は \b+ に対する一致となります。
offset 一致した部分文字列の、分析中の文字列全体の中でのオフセットです(例えば、文字列全体が 'abcd' で、一致した部分文字列が 'bc' ならば、この引数は 1 となります)。
string 分析中の文字列全体です。
groups 名前付きキャプチャグループに対応しているブラウザーのバージョンでは、使用されるグループ名をキーとし、一致した部分を値とするオブジェクトになります (一致しない場合は undefined)。
JSON.stringify()で整形して出力する
JSON.stringify()
の2つ目の引数は、出力するプロパティをstring
かnumber
の配列で渡す。
null
を渡した場合にはすべてのプロパティを出力する。
3つ目の引数は空白文字の数を示す、string
かnumber
型。
number
型の場合1 〜 10の範囲でで受け取る。
0以下の数が渡された場合には空白文字は出力しない。
11以上の数が渡された場合には単に10となる。
string
型が渡された場合にはその文字が空白文字として扱われる。
const user = { name: "Alice", age: 18, id: 1 }
console.log(JSON.stringify(user, ['name', 'age'], 2))
'{
"name": "Alice",
"age": 18
}'
JSON.parse()
で返却時に値を変換する
const set = new Set([1, 2, 3])
const value = JSON.stringify({ set: [...set] })
const parse = JSON.parse(value, ((key, value) => {
if (key === 'set') {
return new Set(value)
}
return value
}))
console.log(parse)
{
set: Set(3) {
1,
2,
3,
__proto__: {...}
}
}
return
が渡されたとき
ジェネレーターにジェネレーターは通常の関数と同じくreturn
キーワードが使える。
しかしその値はfor/of
やスプレッド構文の中でジェネレーターが使われたときには無視されるが、next()
でジェネレーターを読んだ際には値を取得できるという違いがある。
function *countDown() {
yield 1
yield 2
yield 3
return 'done!'
}
console.log([...countDown()]) // [1, 2, 3]
const generator = countDown()
console.log(generator.next()) // { value: 1, done: false }
console.log(generator.next()) // { value: 2, done: false }
console.log(generator.next()) // { value: 3, done: false }
console.log(generator.next()) // { value: 'done!', done: true }
console.log(generator.next()) // { value: undefined, done: true }