new Vue({ render: function(createElement) { return createElement("div", "こんにちは") } })
は VNode
を返すけど、
var div = document.createElement("div")
は DOM ノードを返しますというお話。
この辺はブラウザの実装から見ると分かりやすい気もする。
後者の場合、内部では HTML レンダリングエンジン (ここでは Blink を引用する) 側のクラス、つまりhttps://source.chromium.org/chromium/chromium/src/+/master:third_party/blink/renderer/core/html/html_div_element.h;l=31?q=class%20HTMLDivElement&ss=chromium&originalUrl=https:%2F%2Fcs.chromium.org%2Fでいうところの
namespace blink { class CORE_EXPORT HTMLDivElement : public HTMLElement { DEFINE_WRAPPERTYPEINFO(); public: explicit HTMLDivElement(Document&); private: void CollectStyleForPresentationAttribute( const QualifiedName&, const AtomicString&, MutableCSSPropertyValueSet*) override; }; } // namespace blink
がメモリ上に作成されているはず。で HTML レンダリングエンジン が所有する“DOM ツリーを管理する構造”にぶら下げられるのを待っている。
一方前者の場合、内部では JavaScript エンジン (V8 とか) 側のオブジェクトとしての VNode
なるものが作成されているはず。これについてもう少し見たい。
- https://github.com/vuejs/vue/blob/v2.6.11/types/vue.d.ts
- https://github.com/vuejs/vue/blob/v2.6.11/types/vnode.d.ts
辺りはインターフェイスの類?重要そうなのは https://github.com/vuejs/vue/tree/v2.6.11/src/core/vdom 以下に見える。
ら辺をぼんやり眺めると、render
関数の引数に渡ってくる createElement
は
この辺がその実処理であって、じっくり見ると、 VNode
が作成されていることがわかる。タグを指定しない場合は、vnode.js で定義されている
export const createEmptyVNode = (text: string = '') => { const node = new VNode() node.text = text node.isComment = true return node }
で空の VNode
が作成される。で、この VNode
の定義については、
になるだろう。JavaScript 上の処理としてはこんな感じのようだ。
ここで JavaScript 上の処理を実際に下で支えている JavaScript エンジンとして架空のエンジン「DirtyJs」を想像してみよう(JavaScriptCore
に触れると終わりがなくなるので触れない)。きっとそいつは速度重視だろうから、C だとか C++ とかで実装されていることだろう。VNode
の作成は内部的には
class DirtyJsClass { public: DirtyJsClass(...); ~DirtyJsClass(); ... };
みたいな C++ のクラスのインスタンスが作成されて、「DirtyJs」の管理下のガベージコレクタに登録されることになると思われる。ここで DirtyJsClass
は「DirtyJs」に所属する JavaScript の class を表現するためのオブジェクトである。
一方、DOM API document.createElement
については、「DirtyJs」の中に DOM API の実装が存在していて
HTMLElement *DirtyJsDOM_document::createElement(Document& document, const char *tag_name) { std::string tag(tag_name); if (tag == "div") { // XXX: 本来は HTML レンダリングエンジン側のオブジェクトはもっと抽象化する。 return new HTMLDivElement(document); } ... }
という感じになっているだろう。ここで HTMLDivElement
は HTML レンダリングエンジン (ここではなんとなく Blink のつもり) に所属するオブジェクトである。
「DOM のノード」と「JavaScript のオブジェクトとしての VNode
」を論理的かつ抽象的に区別してとらえるのはなんかよく分からなくて難しいけど、ブラウザ/JavaScript エンジンの具体的な実装からの想像なら、所属するエンジンが異なり意味合いも異なる別々のクラスが instantiate されてますよねぇ、というふんわり解釈で濁すことはできるかもしれない。