【JavaScript】ライブオブジェクトとは何者なのか
JavaScriptを勉強するなかで『ライブオブジェクト』という特殊な挙動をする奴に出会ったので、その特徴をまとめます。
コードが意図したのと違う動きをするときは、ライブオブジェクトの仕業かもしれません。
ライブオブジェクトとは
JavaScriptのオブジェクト(ここでいうオブジェクトは『モノ』みたいな意味です)は、2種類に分けることができます。スタティックオブジェクトと、ライブオブジェクトです。
対義語が『スタティック(静的、つまり動かない)なオブジェクト』であることからわかるように、ライブオブジェクトはまるで「生きているかのように動く」のが特徴です。
なにをいっているのか分からないとおもうので、以下のコードをみてください。
<ul id="target">
<li></li>
<li></li>
<li></li>
</ul>
<script>
const target = document.getElementById('target');
const lists = document.getElementsByTagName('li');
console.log(lists.length);
//1回目のコンソール表示
const newLi = document.createElement('li');
target.appendChild(newLi);
console.log(lists.length);
//2回目のコンソール表示
</script>
いちおう説明すると
①ulタグ内にあるliの数を取得してlistsという定数に代入
②listsを表示(1回目)
③JavaScriptで新しくliをつくり、ulタグに追加
④listsを表示(2回目)
という流れ。
lists.lengthはliの数なので、1回目のconsole.logでは当然3を返します。
では、2回目のconsole.logではなにが返ると思いますか?
注目してほしいのは、listsの代入の位置。
liの数を取得したのははじめだけなので3が返るはず...と思いきや、2回目のconsole.logは4を返します。
つまり、指示していないのに勝手に更新されている、ということ。
これがライブオブジェクトの特徴です。気持ちわるい...。
ライブオブジェクトの挙動について
ライブオブジェクトがなぜこんな挙動をするのかというと、コイツが常にDOMツリーを参照しているから。
つまり、DOMツリーが修正されると(さきほどの例でいえば③の操作)、その修正は同時にライブオブジェクトにも反映される、ということになります。
ですので、以下のコードは無限ループになってしまいます。
<ul id="target">
<li></li>
<li></li>
<li></li>
</ul>
<script>
const target = document.getElementById('target');
const lists = document.getElementsByTag('li');
for(let i = 0; i < lists.length; i++){
const newLi = document.createElement('li');
target.appendChild(newLi);
}
</script>
ulタグ内のliの数だけ新しくliタグを追加する(つまりこの場合、liを3つ追加する)という動作を期待したコードです。
ところが、for文に指定したlistsはライブオブジェクト。liを追加した時点でlists.lengthも増えるので無限ループになる、というわけです。
これを避けるには、以下のようにします。
<script>
const target = document.getElementById('target');
const lists = document.getElementsByTag('li');
for(let i = 0; length = lists.length; i < length; i++){
const newLi = document.createElement('li');
target.appendChild(newLi);
}
</script>
おなじことのように見えますが、ループ処理に入るまえにlists.lengthを取得しておき、それを条件につかうことで解決します。
ライブオブジェクトを扱うときの注意点
嫌な動きをするライブオブジェクトですが、使うときは3つのアプローチがあるようです。
①ライブオブジェクトの変化に影響されない書き方にする(上の例)
②ライブオブジェクトが変化することを期待した処理にする
③ライブオブジェクトが変化するまえに処理を終える
ネイティブのJavaScriptによるDOM操作では、ライブなオブジェクトを扱うケースが多いと思います。
いじっているオブジェクトがライブなのか、はたまたスタティックなのか。思わぬところでハマらないように意識しておきたいですね。
この記事が気に入ったらサポートをしてみませんか?