Object.prototypeの拡張≒グローバル関数の定義

JavaScriptは標準で`prototype`を使ったオブジェクト指向をサポートしているわけで（これについては[ここ](http://www.atmarkit.co.jp/ait/articles/0709/25/news148.html)らへんを参考に）、それを利用することでビルトインのオブジェクト（`Number`、`Array`など）を拡張することができました。が、このビルトインオブジェクトの拡張は長い間禁忌とされてきました。その理由はいくつかありますが、代表的な理由としては、「`for( .. in .. )`文でオブジェクトを列挙しようとした時に拡張したものまで列挙されてしまう」ことや「複数のライブラリでビルトインオブジェクトを拡張したとき、名前が衝突することがる」ことなどが挙げられます。というかだいたいこの二つです。この二つのうち、前者はES5でproperty descriptorをいじれるようになって、列挙するかどうかを制御することが出来るようになったため問題では無いのですが、最後のは現状どうしようもありません（Ruby 2.0のRefinementsみたいな仕様ができない限り）。でもまあ、外部に公開するライブラリじゃないなら自己責任でプロトタイプ拡張ぐらい行なってもいいんじゃないかって思ってます。
__が、`Object.prototype`を拡張するのは絶対にだめです。__
__薬物乱用並にダメ絶対です。__

これからその理由を書いて行きたいと思います。

##Object.prototypeを拡張するとどうなるの？

まずは`Object.prototype`を拡張する例を。

```js:
function extendMethod(object, methodName, method) {
  if(typeof Object.defineProperty !== 'function') {
    object[methodName] = method;
  } else {
    Object.defineProperty(object, methodName, {
      configurable: false,
      enumerable: false,
      value: method,
    });
  }
}

extendMethod(Object.prototype, 'forEach', function(iter) {
  var
  key;
  for(key in this) {
    iter.call(this, this[key], key, this);
  }
});
```

`extendMethod`というプロトタイプを拡張するための関数を定義して、それを使って`Object.prototype`に`forEach`というメソッドを追加しています。
わざわざ`extendMethod`なんて関数を作ったのは、`Object.defineProperty`のない環境でも動くようにするためと、`Object.defineProperty`の設定値を統一させるためです。

こうすると、こんなことができます。

```js:
!{
  foo: 1,
  bar: 2,
  baz: 3,
}.forEach(function(val, key) {
  console.log('%s : %s', key, val);
//=> foo : 1
//=> bar : 2
//=> baz : 3
});
```

ここで重要なのは`forEach`という本来はなかったメソッドを呼び出すことができている点です。

これだけだと便利になっているような気がします。ががが、これには大きな問題があります。

##Object.prototypeを拡張したときの弊害

`Object.prototype.forEach`が拡張された状態でこのコードを試してみましょう。

```js:
''.forEach(function(val, key) {
  console.log('%s : %s', key, val);
});

1..forEach(function(val, key) {
  console.log('%s : %s', key, val);
});

true.forEach(function(val, key) {
  console.log('%s : %s', key, val);
});

!function(){}.forEach(function(val, key) {
  console.log('%s : %s', key, val);
});
```

一見訳の分からないコードですが、これは正常（≒例外を吐くこと無く）に動きます。動くことがなにか問題なの？　と思うかもしれませんが、これって結構大問題です。無意識に全てのオブジェクトに`forEach`メソッドを追加してしまったわけですから。
これは、全てのオブジェクトの基底クラスである`Object`の`prototype`を変更したために他の全ての`prototype`も変更してしまったからです。Javaでいうと、`java.lang.Object`クラスにメソッドを追加するようなものです。
（ちなみに`Array`の場合は`forEach`が自身のプロトタイプで宣言されているので影響ありません）

ですが、この程度なら別にいいんじゃない？　というような気もします。`_.each(obj,...)`とか書くより`obj.forEach(...)`と書いたほうがメソッド呼び出しらしくて分かりやすいですし。

では、次のセクション。

##`Object.prototype`の拡張≒グローバル関数の定義

この記事のタイトルです。

どういうことなのかというと、JavaScriptのグローバルオブジェクトは`Object`を継承しているので、グローバルスコープからさっき定義した`forEach`を呼び出すことができます。

つまり、

```js:
forEach(function(val, key) {
  console.log('%s : %s', key, val);
});
```

という呼び出しが可能になってしまいます。（上のコードはNode.jsだと意外とたくさん出力するので注意してください）

（仕様ではグローバルオブジェクトが`Object`を継承するとは限らないんだけど、V8もSpiderMonkeyも継承しているのであまり関係ないのです。昔のIEは継承してなかった気がするけどあまり関係ないのです）

一般にグローバル変数とか関数はヤバイと言われています。というのも、プログラムのどこからも参照できるため、タイポがあったりすると予期せぬ挙動を見せたりします。
例えば、ローカルなスコープで少し特殊にオブジェクトを列挙する`forEach`という関数を定義しようとしたのだけどタイポして`forEAch`という名前になってしまったとする。その状態で`forEach`を呼び出したら`Object.prototype.forEach`が呼ばれて……あとは分かるな？
まあ`forEach`程度なら大した問題にはなりませんが、これが運命のめぐり合わせで引数が一致したりするとかなり発見しにくいバグに化けたりします。怖いです。

##最後に

例をコードで示すと無駄に長くなってしまって本質的なところが見えにくかったので全て言葉で示したのですが、わかりにくくなってしまってすみません。
あと最初に、`Object.prototype`を拡張するのは薬物並にダメ絶対と書きましたが、薬物並にスリリングな感覚を楽しみたいならやってみてもいいかもしれません。しかし、自己責任です。やったあとに激しい喪失感に襲われても僕は知りません。

それでは、ありがとうございました。