7cc@はてなブログ

JavaScriptとかとか

IE9 開発者ツールの不具合 / デバッグ時の注意点

環境は全てIE9。10+では不明

IE9

console

開発者ツールを開いていないと、そこで止まる

location.hash

ローカルファイルだと、戻る/進むでロケーションバーに表示されなくなる。実際にはある。

非ascii文字のID + エンコードされたページ内リンク の :target

開発者ツールを開いていると、有効になる

<style>
:target{color: red}
</style>

<a href="#%E3%81%82"></a>
<p id="あ"></p>

HTML5ではIDに使える文字に制限が無くなったので上のHTMLはvalid

IE8以下

Date.now()

ドキュメントモードをIE8以下にしても使えてしまう

透過png + アニメーションの再現ができない

IE8と透過pngとJavascriptで泣いた話 | くろひつじのメモ帳

不可視要素のfocus/blurでエラーが出ない

実際はエラー
#1486 (Triggering focus to hidden elements does not work in IE) – jQuery Core - Bug Tracker

Quirksモード

document.documentElement.style.maxHeightがundefinedではない

が文字("")を返す。
実際には、CSS max/min-height/widthは適用されない。

IE8の開発者ツール

オマケ。未確認。

addEventListenerのhandleEventについて

オブジェクト(指向)で使うようです。

syntax

プロパティにhandleEventがあるオブジェクトを第二引数に渡す。
handleEventの値はfunction

// 変数に入れて
var foo = {
  val: 1,
  handleEvent(ev) {
    console.log(this.val++)
  }
}
document.addEventListener('click', foo)
document.removeEventListener("click", foo) // removeできる

// 直接
document.addEventListener('click', {
  val: 1,
  handleEvent(ev) {
    console.log(this.val++)
  }
})

this.handleEventが参照されるので、継承では近いものになる。

function Foo(){}
Foo.prototype.handleEvent = function() {
  console.log(1)
}

var foo = new Foo()
document.addEventListener("click", foo)

// ↑ Foo.prototype.handleEventが呼ばれる
// ↓ foo.handleEventが呼ばれる

foo.handleEvent = function() {
  console.log(2)
}

使う利点は何か

thisはイベントリスナ内でevent.currentTargetを指す。
handleEventではオブジェクトに固定される

handleEventを使わない場合

var o = {
  str: "hello",
  foo: function() {
    alert(this.str)
  }
}

o.foo() // "hello"
document.addEventListener("click", o.foo) // undefined

イベントリスナはthisの参照がdocumentになり、o.fooはdocument.fooになるのでundefinedに。

handleEventを使った場合

var obj = {
  str: "hello",
  handleEvent: function() {
    alert(this.str)
  }
}

o.handleEvent() // "hello"
document.addEventListener("click", obj) // "hello"

thisの呼び出しがobjに固定された。

使う必要は無い

handleEventを使わなくても同じことはできる。
Array#mapみたいなあれば便利だけど、無いなら無いでどうにかなる系だと思う。
thisを固定するひと手間がかかるので、使うにこしたことは無いのだけれど。

必要かという点で見れば、必要でないメソッドは沢山あるので深く考えない方が良いと思う(´ω`)

オブジェクトの例

var obj = {
  str: "hello",
  fn: function() {
    alert(this.str)
  }
}

// thisの呼び出しを固定するひと手間
var listener = function() {
  obj.fn()
}
document.addEventListener("click", listener)
document.removeEventListener("click", listener)

MDNに載っている例のせいかbindと比較されることが多いけれど、
bindでもイベントリスナを変数に代入すればremoveできる。

コンストラクタの例

3つの異なる書き方を比較する。どれも同じことをしている。

handleEvent + コンストラクタ

function Foo(element, str) {
  this.str = str
  this.element = element
}
Foo.prototype.handleEvent = function(evt) {
  alert(this)
}
Foo.prototype.init = function() {
  this.element.addEventListener('click', this)
}
Foo.prototype.cancel = function() {
  this.element.removeEventListener('click', this)
}

var foo = new Foo(document, "hello")
foo.init()
foo.cancel()

Foo.prototype.handleEvent = function(){} // 全体のcallbackを書き換え
foo.handleEvent = function(){} // 個別に書き換え

記述が一番短い

function + コンストラクタ

function Foo(element, str) {
  this.element = element
  this.str = str
}
Foo.prototype.handle = function(e) {
  alert(this.str)
}
Foo.prototype.init = function() {
  var _this = this
  this.listener = function(e){
    _this.handle(e, this)
  }
  this.element.addEventListener('click', this.listener)
}
Foo.prototype.cancel = function() {
  this.element.removeEventListener('click', this.listener)
}

var foo = new Foo(document, "hello")
foo.init()
foo.cancel()

// やっぱり書き換え可能
Foo.prototype.handle = function(){}
foo.handle = function(){}

いちいち新しい関数を作るので効率は悪い。継承の利点の一つが失われている。
その点を除けばhandleEventと同等のことができる。

bind + コンストラクタ

Foo.prototype.init = function() {
  this.listener = this.handle.bind(this)
  this.element.addEventListener('click', this.listener)
}

後からイベントリスナのcallbackを書き換えることは不可能。でもremoveはできる。
(でも書き換えなんて実際するかどうか)

ということで、handleEventでしかできないことがあるのか考えたけど思いつかなかった。他の方法でわざわざ遠回りすることもないので、オブジェクトなら素直に使うということで。

xhr GETのキャッシュ

XMLHttpRequest GET のキャッシュについて
・・・なのだけれど、xhrだけではなく、キャッシュ全般にいえる話だった。

キャッシュの仕組みについては以下のリンク参照。

キャッシュが無効に設定されている

それで終わり。パラメータの有無は関係無くなる

キャッシュが有効な場合

パラメータ無し
サーバーと通信しない
ブラウザのキャッシュから読み込み
2度目以降はオフラインでも可
パラメータ有り かつ そのパラメータが2度目以降
サーバーと通信
更新されていない -> 304 Not Modified
更新されている -> 200 OK
パラメータ有り かつ そのパラメータが初回
キャッシュは無効
200 OK

xhrでキャッシュを利用したくない場合

ユニークなパラメータにする。Date.now()が定番

JavaScriptからはキャッシュが有効か分からない

成功した場合、xhr.statusは200になる。304は返らない。