m2O

2013/06/23 (日)

<script> を含む要素に innerHTML += するとどうなるか

|  <script> を含む要素に innerHTML += するとどうなるか - m2O を含むブックマーク

こんな HTML があるとします。いったいどんな動きになるでしょう?

<aside id="pc_ch_top_468x60_north" class="ads_nicovideo ads_header size_468x60">
    <script>document.getElementById('pc_ch_top_468x60_north').innerHTML += 'AAA!';</script>
</aside>

「a += b」は「a = a + b」の短縮表記なので

document.getElementById('pc_ch_top_468x60_north').innerHTML = " <script>document.getElementById('pc_ch_top_468x60_north').innerHTML += 'AAA!';</script> " + 'AAA!';

と同じ意味です。
要するに innerHTML に <script> を代入するとそれが実行されるかどうか、という問いになります。もし実行されるとしたらこの script だと無限再帰になって死んでしまいますからゆゆしき問題です。


というわけで実際に動かしてみました。

http://jsdo.it/miya2000/ndUU

身の回りのブラウザ(Opera(10.10, 12, Next15), Chrome27, Firefox21, ie10) ではどれも再実行はされず、「AAA!」が1つだけ表示される結果になりました。

これがどこかの仕様で決まっている動きなのかどうかわからないですが、意図的に script を実行させようとしたら上記のようなコードにはならないと思いますので、安全側に倒した挙動になっていると思います。つまり何も問題はありませんでした。



で、ここからが Opera クオリティ。
以下のようにコードを上に追加してみましょう。

<script>
document.addEventListener('DOMNodeInserted', function() {}, false);
</script>

<aside id="pc_ch_top_468x60_north" class="ads_nicovideo ads_header size_468x60">
    <script>document.getElementById('pc_ch_top_468x60_north').innerHTML += 'AAA!'</script>
</aside>

http://jsdo.it/miya2000/ofvz

なんと DOMNodeInserted イベントリスナを追加しただけで、script が再実行されて「AAA!」がいくつも出力されるようになってしまいました!
(Opera Next15 は大丈夫でした。)


そういうわけで DOMNodeInserted イベントを監視する User Javascript を使用していると、ニコニコチャンネルのトップページ広告がわらわらと増えていく現象が起こっていました。
原因がわかって対応もしたのでもう大丈夫なんですが、http://ads.nicovideo.jp/assets/js/ads-2.js の 234 行目あたりは修正した方がいいんじゃないかな、と思います。

--

というか普通はこうですかね。

<aside id="pc_ch_top_468x60_north" class="ads_nicovideo ads_header size_468x60"></aside>
<script>document.getElementById('pc_ch_top_468x60_north').innerHTML += 'AAA!';</script>

 

トラックバック - http://orera.g.hatena.ne.jp/miya2000/20130623