あいうえおch.
Members Link

JSのハマりどころ

目次

DOM先読み

書き方忘れそうだから書いておく。

document.addEventListener('DOMContentLoaded', () => {}) // が便利
window.onload () => {} // も同じく

ただし,on~系は最後の記述のみ処理されるから同じ命令を複数使う場合は使用不可

オブジェクトリテラル

Object.values()はES2017で追加。便利だなあ。

const someObject = {
  keyA: 'someA',
  keyB: 'someB'
}
console.log(Object.keys(someObject)) // ['keyA', 'keyB']
console.log(Object.values(someObject)) // ['someA', 'someB']

canvas画像反転

後から書いててロクにテストしてないからそのままじゃ動かないかも。


scale(x, y)で変形したら,座標も(x, y)倍されるみたい。

const canvas = document.getElementById`myCanvas`
const context = canvas.getContext`2d`
let img = new Image()
img.src = './img/js.png' // 任意の画像を読み込み
context.save() // 今の状態を保存
context.scale(-1, 1) // 左右反転
const coordinate = {x: 100, y: 100} // 任意の座標
context.drawImage(-coordinate.x - img.width, coordinate.y) // でやっと思い通りの位置に表示できる
context.restore() // さっきのセーブ内容を戻す

localStorage

文字列しか保存できないから気をつけよう。

const storage = sessionStorage
storage.setItem('test', false)
const reverse = (key) { // こんなふうに書くと,文字列'false'は存在するからtrueを返す
  if (storage.getItem(key)) storage.setItem(key, !storage.getItem(key))
}
reverse('test')
console.log(storage.getItem('test')) //
storage.setItem('test', 'NO')
const reverse = (key) {
  if (getStorage(key) === 'YES') setStorage(key, 'NO')
  else setStorage(key, 'YES')
} // めんどくさいね
reverse('test') // 'YES'
reverse('test') // 'NO'

実行速度検証

'use strict'
let counterA = 0
const trialA = () => counterA = (counterA+1)|0
let counterB = [0]
const trialB = () => counterB[0] = (counterB[0]+1)|0
let counterC = {counter: 0}
const trialC = () => counterC.counter = (counterC.counter+1)|0
const testA = x => {}
const testB = () => {}
const testC = arg => {}
const testD = (x, y) => {}
function testE(){}
function testF(x){}
function testG(arg){}
function testH(x, y){}
const spaceA=()=>{}
const spaceB = () => {}
const        spaceC        =        ()        =>        {}
const measure = (name, func) => { // 関数の実行時間を計測する関数
  const start = performance.now()
  for (let i = 0; i< 1e8; i=(i+1)|0) func()
  const end = performance.now()
  const elapsed = (end - start)
  const elapsedStr = elapsed.toPrecision(3)
  console.log(`${name}: ${elapsedStr}`) // 実行にかかった時間をミリ秒で出力
}
measure('dummy', testA) // ダミーいれないと最初爆速だよみたいに言われる
measure('dummy', testB)
for (let i = 0; i< 4; i=(i+1)|0) {
  measure('a', trialA)
  measure('b', trialB)
  measure('c', trialC) // 自分の環境の場合,オブジェクトリテラルが一番早かった
  measure('a', testA)
  measure('b', testB) // これが早かった
  measure('c', testC)
  measure('d', testD)
  measure('e', testE) // こいつもなかなか
  measure('f', testF)
  measure('g', testG)
  measure('h', testH)
  // こっちはどれも変わらない
  measure('a', spaceA)
  measure('b', spaceB)
  measure('c', spaceC)
}

各自こぴぺ汁


const f = x => {}みたいな書き方して1文字稼いでたけど,

やっぱり,引数取る分だけ実行時間に差が出るみたいだから控えよう。

どっちの関数宣言も速度差はないみたい。


lintとかで注意されないから積極的に変な空白を揃える気が起きなかったけど,

そんな神経質にならなくても,どうでもいいみたいね。


最初だけタイマーがおかしくなるのは,わかんない。

読み込み時にはperformance.now()って動けないのかな?


コレで夜も安心。

new演算子とかも気になってきた。多用するようなら調べよう。

実行速度検証 その2

'use strict'
console.log('hello')

const measure = (name, func) => {
  const start = performance.now()
  func()
  const end = performance.now()

  const elapsed = (end - start)
  const elapsedStr = elapsed.toPrecision(3)
  console.log(`${name}: ${elapsedStr}`)
  return elapsed
}

let sum = 0

let vbl = 1
const addVbl = () => {
  sum = 0
  for(let i=0; i < 1e8; i++) sum += vbl
}
let arr = Array(100).fill(1)
const addArr = () => {
  sum = 0
  for(let i=0; i < 1e8; i++) sum += arr[50]
}
let obj = {}
for (let i = 0; i < 100; i++) {
  obj['n' + i] = 1
}
const addObj = () => {
  sum = 0
  for(let i=0; i < 1e8; i++) sum += obj.n50
}

measure('vbl', addVbl)
measure('arr', addArr)
measure('obj', addObj)

let ave = {vbl: 0, arr: 0, obj: 0}
const interval = 10
for (let i=0; i < interval; i++) {
  ave.vbl += measure('vbl', addVbl)
  ave.arr += measure('arr', addArr)
  ave.obj += measure('obj', addObj)
}

console.log(
  ave.vbl / 10, // 226ms
  ave.arr / 10, // 223ms
  ave.obj / 10  // 1505ms
)

オブジェクトリテラルおっそーい