ここから本文です

Object.prototype.toString.call(value)で [object XXXobject] と表示される変数 v...

sou********さん

2014/2/1522:48:29

Object.prototype.toString.call(value)で [object XXXobject] と表示される変数 value を定義したいのですが、
何をどうすればいいのでしょうか?

お世話になります。

現在、getElementsByClassNameのクロスブラウザ用コードを書いているのですが、
その出力を Object.prototype.toString.call(value) で検査しようとすると、
配列を使っているため [object Array] と出ます。

これを本来の関数のように [object NodeList] とさせたいのですが、
誤判定を防ぐのが目的なので [object xNodeList] などとでも表示できれば良いと考えました。

これを行うには、多分JavaScriptにおけるオブジェクトの継承が必要だと考え、
その方向で調べたのですが、該当する情報が見つかりません。

どうすればいいでしょう?

質問したいのは、
・Object.prototype.toString.call(value) の結果文字列に好きなオブジェクト名を指定したい。
・NodeList オブジェクトを継承したい。
の、2つです。

2つ目は、別に無理なら無理で構わないと考えています。

補足すいません、当方JavaScriptのクラス(っぽいもの)について全く扱ったことがなく、
貴重な回答にも関わらず一部正確な意味を把握できずにおります。

>[[Class]] は内部プロパティなので詐称することが出来ません。
つまり、Object.prototype.toString.call(value) で [object XXXobject] などと出る変数は定義不能・・・と捉えてよろしいでしょうか?

閲覧数:
184
回答数:
3

違反報告

ベストアンサーに選ばれた回答

rio********さん

編集あり2014/2/1601:01:01

[[Class]] は内部プロパティなので詐称することが出来ません。
(そんなことが出来たら安心して Object.prototype.toString,call を使うことが出来ません)
[[Class]] を改変する事は諦めて instanceof で該当オブジェクトを判定するとか別の方法を模索してください。

NodeList を継承するなら、Object.create を使うか prototype を使えばいいと思います。

(補足後)
> つまり、Object.prototype.toString.call(value) で [object XXXobject] などと出る変数は定義不能・・・と捉えてよろしいでしょうか?
仰る通りです。
http://www2u.biglobe.ne.jp/~oz-07ams/prog/ecma262r3/15-2_Object_Obj...
http://es5.github.io/#x15.2.4.2
ちなみに私の知識はES5で止まっていますのでES6についてはわかりません。ごめんなさい。

現状では [object NodeList] と全く同じ動作をさせるのは不可能だと思いますので、それを期待するなら jQuery のようにオブジェクトの内容判定を含めて全機能をラップする実装が現実解だと思います。
(名前だけ変更して中の性質が違ったら混乱を生みますよね。個人的にはnativeオブジェクトと区別する為に別の名前にして欲しいですが。)

rishorusさんが指摘されていますが、getElementsByClassName の戻り値はliveであり、配列はnot liveなので関数名は getElementsByClassNameNotLive 等のわかりやすい名前にした方がいいと思います。

# Re: sounisi5011さん

質問した人からのコメント

2014/2/16 02:39:19

様々な回答、ありがとうございました。

結局 Object.prototype.toString.call(value) に任意の値を出すことは出来ないようなので、
オブジェクトとして出力する関数を作成することにしました。
旧IEは、DOM系の値が全て [object Object] として出力されるので、
多分これで大丈夫でしょう・・・

ベストアンサー以外の回答

1〜2件/2件中

並び替え:回答日時の
新しい順
|古い順

b0a********さん

編集あり2014/2/1600:08:02

ES5までは不可能です
[object Class]の「Class」の部分はオブジェクト固有の内部プロパティ[[Class]]の値が入ります
この値は配列であれば"Array"と決まっていて、上書きすることはできません

ES6では[[Class]]の代わりに@@toStringTagが導入されたので、それを使うことにより一部の値を除き自由に変更することができます
また、@@toStringTagは継承で引き継いてデフォルトの値を上書きすることができるので、NodeListにも@@toStringTagがきちんと実装されれば継承で反映されるようになるはずです

また、継承そのものにも問題があります
例えメソッドを継承させても、DOMのメソッドは大抵非ジェネリックなものとして実装されているので使うことはできません
NodeListのメソッドを使うにはNodeListだと認めてもらわないといけませんが、ES5までは形質、つまり内部プロパティを引き継がせる手段が用意されていないので不可能です
ES6では@@createが導入されたので、もしNodeListにそれを実装することになれば可能になります


~~補足より~~
いっそ、Object.prototype.toStringの方を変更してはどうですか?

ris********さん

編集あり2014/2/1600:36:25

そもそも論として、NodeList は「live である」というのは大丈夫ですか?

最近は DOM の名付け規則もだいぶ揺らいでいますが、基本的に getElements... の返すリストは「生きて」います。すなわち、DOM 文書木の変更に合わせ、自動的にアップデートされます。典型的には、いちいち load イベントなぞ待たなくても冒頭で

var targetNodes = document.getElementsByClassName('hoge');

としておけば、最初は個数が 0 であっても、文書木構築にしたがい個数が増えていき、実際に使おうと思う頃には全て入っている。逆に、文書木からノードを除去すれば自動的にリストからも除去されるため、ループを書くときは注意しなければならない。そういうのが NodeList です。

だから、「live でない NodeList」という特殊なものを返す querySelectorAll() は、getElements... とは命名されなかったわけです。

---

「live な NodeList」を実装したければ、NodeIterator と getter を使うことになります。実際に作ってみれば、なぜ NodeList をループで回すときに、I = targetNodes.length のようにして個数のスナップショットをとった方が良いのか分かるでしょう。

それでもおそらく完璧なものにはならないでしょうし、そもそも getter を使えるエンジンならとっくに getElementsByClassName() を持っているでしょうから Polyfill の目的からずれてしまいます。

だからまあ、「Array を返すメソッド」として getElements.... ではない別の名前を使う方が、色んな意味で無難だと思いますけどね。標準化されたメソッドにも関わらず仕様に沿っていないものは、バグを持ち込むことになりますので。


【追記】うるさく申し上げますが、NodeList でないものを "NodeList" と偽ったら駄目ですよ。標準仕様が存在するものですので。

NodeList を継承できるかどうかで言えば、エンジンによります。そもそも NodeList は上のように DOM 内部に食い込む仕様になっていますので、たいていラップされているはずです。

みんなで作る知恵袋 悩みや疑問、なんでも気軽にきいちゃおう!

Q&Aをキーワードで検索:

Yahoo! JAPANは、回答に記載された内容の信ぴょう性、正確性を保証しておりません。
お客様自身の責任と判断で、ご利用ください。
本文はここまでです このページの先頭へ

「追加する」ボタンを押してください。

閉じる

※知恵コレクションに追加された質問は選択されたID/ニックネームのMy知恵袋で確認できます。

不適切な投稿でないことを報告しました。

閉じる