Closed15

JavaScript The Definitive Guide 7th Editionを読んでます

azukiazusaazukiazusa

空白行

ただ単にセミコロン;を置いただけの行は空白行となる。
空白行はなにも実行しない。

;

これは例えばfor文を作成するが何も実行したくないときに用いられる。
JavaScriptの文法ではfor文には必ず文が必要であるため、なにも実行しない空白行を配置する必要がある。

// 配列を初期化する
for(let i = 0; i < a.length; a[i++] = 0) ;
azukiazusaazukiazusa

配列 → 数値の変換

配列から数値への変換はときに奇妙である。
空の配列をは0に変換されるが、配列が1つだけの数字の要素を保つ場合にはその数に変換される

console.log(Number([])) // 0
console.log(Number([10])) // 10
console.log(Number([10, 20, 30])) // NaN
console.log(Number(['a'])) // NaN

これは次のように評価された結果である

  1. prefer-number algorithmが使われた結果、配列のvalueOf()メソッドがまず呼ばれることになる。
  2. 配列のvalueOf()はプリミティブな値を返さない(配列をそのまま返す)ので、次にtoString()メソッドが呼ばれる
  3. 空の配列にtoString()をした結果は空文字""が返されるので0と評価される。配列が1つの要素だけを持っている場合には、その要素を返すため結果その値に評価される。(配列が複数の要素を持っている場合には、カンマ,区切りの値が返される"10,20,30"この値を数値に変換すると得られるのはNaNだ。

参考

https://stackoverflow.com/questions/62717437/behavior-of-greater-than-and-another-inequality-comparison-operators-on-arra

azukiazusaazukiazusa

オプショナルチェイニング演算子

オプショナルチェイニング演算子はメソッドの呼び出しにも使える

a?.b?.c()
azukiazusaazukiazusa

try/finally 構文

let i = 0

while(i < 10) {
  try {
    console.log(i)
  } finally {
    i++
  }
}
azukiazusaazukiazusa

完全に空のオブジェクトの作成する

Object.cretate()nullを渡すと一切prototypeを継承しないオブジェクトの作成することができる。

const obj = Object.create(null)

console.log(obj.toString()) // error: Uncaught TypeError: obj.toString is not a function
azukiazusaazukiazusa

flatMapでmapとfilterを同時に行う

const array = [1, 2, 3, 4, 5]

array.flatMap(x => x % 2 === 0 ? [] : x ** 2) // [1, 9, 25]

条件に一致しない場合には空の配列を返すようにする。
空の配列要素は平坦化されることによって最終的には配列から取り除かれることになる。

azukiazusaazukiazusa

includes()indexOf()の違い

includes()NaNと一致するが、indexOf()は一致しない

const arr = [1, 2, NaN, 4]

console.log(arr.indexOf(NaN)) // -1
console.log(arr.includes(NaN)) // true
azukiazusaazukiazusa

bind()で部分適用

const add = (x, y) => x + y
const add1 = add.bind(null, 1)
console.log(add1(2)) // 3
azukiazusaazukiazusa

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
    }
}
azukiazusaazukiazusa

関数やコンストラクタが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
azukiazusaazukiazusa

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)。

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/String/replace#specifying_a_function_as_a_parameter

azukiazusaazukiazusa

JSON.stringify()で整形して出力する

JSON.stringify()の2つ目の引数は、出力するプロパティをstringnumberの配列で渡す。
nullを渡した場合にはすべてのプロパティを出力する。

3つ目の引数は空白文字の数を示す、stringnumber型。
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
}'
azukiazusaazukiazusa

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__: {...}
  }
}
azukiazusaazukiazusa

ジェネレーターに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 }
このスクラップは2021/12/18にクローズされました