prototypeとObject
foo.prototype.method = function(){};
と
foo = {method: function(){}};
の違い
— わちるだ (@watilde) April 27, 2013
ってツイートしたら「後者は問題ありそう」みたいな反応があって、色々調べてみました。
見通しの良さ
元々は以下のfooとhogeを比べた時、
「Objectだけで書いたほうがタイプ数少ないし見通し良いよ」
って友達に言われたのがキッカケでした。
var foo = function (name) { this.name = (name) ? name : 'foo'; }; foo.prototype.method = function () { console.log(this.name); }; var hoge = { name: 'hoge', method: function () { console.log(this.name) } };
newの代わりとしてのObject.create()
じゃあそれぞれインスタンスの生成やるとどうなるか
var bar = new foo('bar'); bar.method(); // =>bar var fuga = Object.create(hoge, {name: {value: 'fuga'}}); fuga.method(); // => fuga
これでそのまま使える気がしてきますが、ちょっと問題があります。
問題1:書き換え不可
既定でプロパティは
書き換え (writable)、列挙 (enumerable)、変更 (configurable)
が不可になります:
これ、どういうことかというと
var bar = new foo('bar'); bar.method(); // => bar bar.name = 'barbar'; bar.method(); // => barbar var fuga = Object.create(hoge, {name: {value: 'fuga'}}); fuga.method(); // => fuga fuga.name = 'fugafuga'; // ここで書き換えても fuga.method(); // => fuga 値そのまま
これの制限を解除するには第二引数でオプションを加えなきゃいけません。
var piyo = Object.create(hoge, { name: { value: 'piyo', writable: true, enumerable: true, configurable: true } }); piyo.method(); // => piyo piyo.name = 'piyopiyo'; piyo.method(); // => piyopiyo
これでは「Objectだけで書いたほうがタイプ数少ない」が本末転倒です。
問題2:初期化不可
また、Object.createでは以下の様な初期化コードの実行が出来ません
var foo = function () { console.log('Hello:D'); }; var bar = new foo(); // => Hello :D
解決策
以上の2つの問題を解決するのに、init関数を作成する運び
var baz = { init: function (name) { this.name = name; console.log('Hello:D'); }, method: function (){ console.log(this.name); } }; var qux = Object.create(baz); qux.method(); // => undefined qux.init('qux'); // => Hello :D qux.method(); // => qux qux.name = 'quxqux'; qux.method(); // => quxqux
これでスッキリしました。
Polyfill
あとはECMAScript 5thの仕様からして古いブラウザには対応していないので
Polyfillとして
if (!Object.create) { Object.create = function (o) { if (arguments.length > 1) { throw new Error('Object.create implementation only accepts the first parameter.'); } function F() {} F.prototype = o; return new F(); }; }
とかやると良いかもしれません。
まとめ
複数のインスタンスを生成するとか発想なしに、
とりあえずでObjectだけで組まれたコードを見かけたことがあるので
こうやって書き換えればうまく保守できるなーとか思いました。
ちなみに、個人的にはnewの方が好きです。
ネストが深くならないしー かっこいいしー
参考
https://developer.mozilla.org/ja/docs/JavaScript/Reference/Global_Objects/Object/create
おしまい。
追記
ご丁寧なコメント頂きました(*´∀`*)
gocho 「prototypeを用いた記述」と「オブジェクトメンバーとしての記述」は記述だけでなく、挙動も異なります. (動作確認) http://jsfiddle.net/gocho/d3RmZ/ (詳しい解説) http://d.hatena.ne.jp/maeharin/20130215/javascript_prototype_chain
おしまい
開眼! JavaScript ―言語仕様から学ぶJavaScriptの本質
- 作者: Cody Lindley,和田祐一郎
- 出版社/メーカー: オライリージャパン
- 発売日: 2013/06/19
- メディア: 単行本(ソフトカバー)
- この商品を含むブログを見る