読者です 読者をやめる 読者になる 読者になる

他社サイトに設置するjsタグを作る時のTips(prototype汚染の話)

javascript 技術

こんにちは、g0eです。

アドテク業界ではjavascriptのタグ(以下、jsタグ)をクライアントサイトに埋め込んでもらうことがよくあります。 自社サイトの開発と違って、設置先のサイトでどのようなjavascriptが動いているかわからないので、他のjavascriptと競合しないように書く必要があります。

今回は他サイトに設置するjsタグを書く時に注意すべき事項の中の一つの、prototype汚染の話をしたいと思います。

プロトタイプ汚染の例

下記のコードを実行した後に、

// Objectのプロトタイプを汚染するコードの例
Object.prototype.hoge = function(){}

下記のような、オブジェクトpiyoをfor-inループで 調べるようなスクリプトを実行します。

var piyo = {foo: 1, bar: 2};
for(var k in piyo){
   console.log(k);
}

すると、コンソールに以下の文字列が表示されると思います。

foo
bar
hoge    /* !? */

そんなの当たり前だろ、と思った方はこの記事はここで読み終えていただいて大丈夫です。

あれ、hogeが混ざってきたぞ、という方はこのまま読み進めて下さい。

javascriptのプロトタイプチェーンの話はなかなか奥が深い話なので、今回は言及しませんが、上記のようにObject.prototypeやArray.prototypeなどに新しいプロパティを追加するコードがどこかにある場合、for-inループをそのまま使うのは非常に危険ということが伝わったでしょうか?

一昔前(むしろ大昔?)に流行ったprototype.jsというライブラリを利用しているサイトで、このようなプロトタイプ汚染に巻き込まれることがあります。

プロトタイプ汚染に強いfor文の書き方

hasOwnPropertyを使う

for-inループの中で取得したプロパティが、対象オブジェクト自身のプロパティ(つまり、プロトタイプチェーンをたどって取得したものではない)かどうかをチェックして利用するようにします。

var piyo = {foo: 1, bar: 2};
for(var k in piyo){
   if(piyo.hasOwnProperty(k)){
      console.log(k);
   }
}
Object.keysを使う

Object.keysを使ってプロパティの一覧を取得することでも、同じ効果を得ることができます。

var piyo = {foo: 1, bar: 2};
var keys = Object.keys(piyo);
for(var i=0;i<keys.length;i++){
   console.log(keys[i]);
}

まとめ

かなり駆け足になってしまいましたが、今回のまとめは以下の通りとなります。

  • ObjectやArrayのprototypeをいじらない(プロトタイプ汚染しない)
  • for-inループを使う時は注意する(使わない、もしくはhasOwnPropertyを併用する)