街中で見かけて「グッときた人」の思い出

下記コードは、私には同じことをしているように見えるのですが、
Aの方じゃないと駄目なケース、
Bの方じゃないと駄目なケースというのは存在しますか?

それともAとBは完全に、お互いを代替え可能なものでしょうか?

//-----------------------------------------------
// A
//-----------------------------------------------
var Box = {
a: 1
}
console.debug( Box.a );// 1
//-----------------------------------------------
// B
//-----------------------------------------------
function Box()
{
this.a = 1;
}
var hoge = new Box;
console.debug( hoge.a );// 1

A 回答 (3件)

一応、私なりの回答をしますが、もっと詳しい人が回答するかもしれないので、しばらくオープンにされたほうがいいと思います(というか私も知りたい^^;)。



Aの

var Box = {
a: 1
}

は、

var Box = (function() {
var obj = new Object;
obj.a = 1;
return obj;
})();

と、ほぼ等価なので、コンストラクターにObjectを使ってることになります。
Bの場合は、明示してある通りBoxがコンストラクターになります。

なので、生成されたインスタンス(オブジェクト)の[[prototype]]プロパティ(__proto__)が異なります。
もちろん、コンストラクターが違うので、constructorプロパティも異なります。

[Aの場合]
Box.__proto__ === Object.prototype
Box.constructor === function Object

[Bの場合]
hoge.__proto__ === Box.prototype
hoge.constructor === function Box

プロトタイプチェーンを利用して、静的プロパティを定義するとき、Bならば

Box.prototype.method = function(){ hogehoge... };

となりますが、Aの場合は、

Object.prototype.method = function(){ hogehoge... };

と、全てのオブジェクトの大元であるObjectにプロパティを定義することになり危険です。

それから、No.1のbabu_babooさんもおっしゃってますが、似たオブジェクトを複数生成する場合、Bならば、

var hoge = new Box;
var fuga = new Box;

で済みますが、Aの場合、

var Box2 = Box;

では、オブジェクトの参照先(アドレス)をコピーしているだけとなり、新たなオブジェクトの生成にはなりません。
新たな類似オブジェクトの生成には、deep copyが必要となりますが、JavaScriptではかなり困難です。

以上より、私なりの結論としましては、静的プロパティ(プロトタイプチェーン)を利用せず、その1つだけのオブジェクトの生成だけでいいときは、表記が簡単でわかりやすいAの方法でいいと思います。
    • good
    • 0
この回答へのお礼

ありがとうございます。
下記の箇所を見て思い当たりました。
なるほど。そういえばそうですね。
newするだけで識別できますね。
---------------------------------
Bならば、

var hoge = new Box;
var fuga = new Box;

で済みますが、Aの場合、

var Box2 = Box;
---------------------------------

prototypeの部分もryu_chanさんがきっかけで何かかが分かりかけている気がします。
とても勉強になりました。
もう少しコードを試せばprototypeがわかりそうかもです??

お礼日時:2011/03/07 00:21

instanceof の結果が違います。



// A
Box instanceof Box; // TypeError
Box instanceof Object; // true

// B
hoge instanceof Box; // true
hoge instanceof Object; // true

new を使うと、そのオブジェクトがどのコンストラクタから作られたものか、という情報が残ります(正確には、どのオブジェクトにプロトタイプ委譲しているか)。

例えば、XPath パーサを書くとします。まず大元となる XPathObject を用意し、そこから派生した XPathString、XPathNumber、XPathBoolean、XPathNodeSet を作ります。

このとき、あるオブジェクト obj がどのデータ(文字列、数値、真偽値、ノードセット)であるかは instanceof を使えば分かります。仮に、

var sequence = [obj1, obj2, obj3];

というシーケンスがあり、ここから数値であるものだけ取り出したい、というときは

var numOnly = sequence.filter(function(obj) { return obj instanceof XPathNumber; });

のようにすれば良い。

データ・オブジェクト設計をうまくやれば instanceof を活用できるし、ひとつのオブジェクトにゴチャゴチャ詰め込むなら活用できない。その程度と言えばその程度の話です。

---
なお、No.2 の仰る『deep copy』に関しては、ECMAScript 5 / JavaScript 1.8.5 で Object.create() が導入されましたので、

// A'
var box_ = Object.create(Box);

で Box にプロトタイプ委譲する box_ を作ることができます。deep copy とはやや(かなり)異なりますが、ある意味ではこれが(__proto__ に近い)素直なプロトタイプベースですね。

さらに、同じく ECMAScript 5 で導入された Function#bind() を使えば

// B'
var huga = new Box.bind.apply(Box, arguments);

のように、new するコンストラクタに任意数の引数を渡すことができます。この辺で悩んだことのある人には朗報でしょう。

これらはそれぞれ A、B に関わる拡張です。つまり、どちらも(それなりに)必要ということです。そして、両者はともに instanceof が自然な結果になるよう考えられています。
    • good
    • 0
この回答へのお礼

反応が遅れましたが、僕の知らないことがたくさん紹介されていてとても啓発を受けました。
理解するのにいろいろ調べる必要がありそうなので、先にお礼を述べさせていただきます。
instanceofの存在は知っていましたが、今使うのか!と教えられてやっと気づいた次第です。
ありがとうございました。

お礼日時:2011/03/10 01:08

そのうち、まっとうなかいとうがあるでしょう~!



>私には同じことをしているように見える
わたしにもそうみえる。^^;

>Aの方じゃないと駄目なケース
きのうを1つにまとめるときに、べんり。けっして、だめというほどでもないけれど。

>Bの方じゃないと駄目なケース
それをふくすうひつようとするばあい。
    • good
    • 0
この回答へのお礼

ありがとうございます。
ケースバイケースという感じでしょうか。
あまり重要な問題でもないのかもしれないですね?

お礼日時:2011/03/06 12:58

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!