javascriptのprototype拡張はどこまで許されるか
孫引きなんだけどちょっと気になった点
404 Blog Not Found:javascript - es2pi はじめました http://blog.livedoor.jp/dankogai/archives/51859796.html
本来の JavaScript の利用方法(Prototype 拡張)に立ち返り、Array.prototype, String.prototype, Number.prototype 等を拡張しています
最近のJSは基本的に肥大化するし、DOMはグローバルな状態であり、またprototypeもどこからでもアクセスできるという点ではグローバルである。
手癖が悪い人はprototype経由で値の受け渡ししはじめる。JSではスコープチェーンなりで値の受け渡しをするように気をつけたい。
経験上、方針を決めずにprototypeを触りまくると遅かれ早かれ破綻する。が、元々プロトタイプ指向な言語だけに、うまく活用すると言語としての自由度がグンと上がる。そのバランスを取らないといけない。
以下にprototype拡張が許されると思しきケースを書く。
1. polyfill系ライブラリ
- prototype.js
- sugar.js
- es5-shim
- es2pi
JS5未満の標準ライブラリは貧弱であり、それを補完する系のもの。ECMA Harmony もしくは Rubyインスパイアのものが多い。
このライブラリを使っている限りは、ライブラリが提供するコードを使うべきで、よくわからないからと自分で定義してしまうと、ロジックが重複して見通しが悪くなる。
2. オブジェクト宣言, prototype継承
JavaScriptでオブジェクト宣言する際は勿論prototype経由で振る舞いを定義することになる。
coffee-scriptで継承を実現する際は、次のようなスニペットが挿入される。
// Generated by CoffeeScript 1.6.1 (function() { var List, __hasProp = {}.hasOwnProperty, __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }; List = (function(_super) { __extends(List, _super); function List() { return List.__super__.constructor.apply(this, arguments); } return List; })(Array); }).call(this);
このコードはArrayを継承したListクラスを作る。
まあ普通のprototype活用だとは思う。
3. 実装(not ライブラリ)
自分がフロントエンドを作る側で、かつ自分自身を継承する人がいない場合、独自の挙動を追加することは許されるとは思っている。
ただ、その場合1つのファイルを指定するなどの明示的なアプローチをとる必要がある。たとえば array_proto.js でArrayの拡張を書き、それ以外ではArray.prototypeは決して触れない、とか。
そしてpolyfill系ライブラリを使っている場合はある程度任せるべきで、かつ上書きしてはいけない。それでいてアプリケーションロジックの実行前に全部読み込んでおくべきだと思う。
プロトタイプはアプリケーション実行前後に同じものであってほしい。コード中で動的にprototypeオブジェクトを変更されるのは怖くて仕方ない。
まあ、便利だけど明示的に、ってのが自分の信条です。