らんだむな記憶

blogというものを体験してみようか!的なー

Vue.js (2)

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/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 されてますよねぇ、というふんわり解釈で濁すことはできるかもしれない。