はじめに
ウェブサービスを作ってみる、の学習編。
https://qiita.com/tsnb/items/f004e0fafd924ba411b4#_reference-ce2fbc322b278df77f63
今回から、フェーズ0としてログイン周りを実装するためにjavascriptの学習をしていく。
javascriptの知識はあんまりない、適当にググりながら書いたことあるレベル。
参考にする情報
こちらを順に進めていく。
問題はDOMとかの概念をきちんと理解してない。現在はWHATWGで策定されている仕様らしい。
その他にも用語すら知らないものがあるかもしれんが見つけたら随時更新する。
- DOM
- XMLHttpRequest
- Virtual DOM
- npm, yarn
- css周りは諦めて適当にやる
- Webpack
- Babel
- ESLint
- JSX
- React
- (Redux)
今回のゴール
DOM1コア,DOM1(HTML)についての基本仕様を確認して、
javascriptで挙動を適当に確認するためにコードを書いてみる。
奥が深そうすぎてLiving Standardまで全部読むのは一旦時間的に無理なので書きつつ学ぶ。
綺麗な書き方とか最新の書き方は一旦無視。
jsprimerを後で読む。
DOMはなぜ使うのか
DOMはHTML文書およびXML文書へアクセスしたり操作したりするために使う。
今はVirtual DOMとやらを使うらしいが基礎の知識として学んでおく。
DOMって何
- wikiがまとまってるのでまずこれを読む
-
文書オブジェクトモデル(DOM)第1水準 仕様書(日本語版、非公式)
W3Cのドキュメント読みやすい
文書オブジェクトモデル(DOM)とは、HTML文書およびXML文書のためのアプリケーション=プログラミング=インターフェイス(API)である。これは、文書の論理的構造や、文書へのアクセスや操作の方法を定義するものである。DOM仕様書においては「文書」という用語は広い意味で使われる。ますますXMLは数多くの異なる種類の情報を表現する方法として用いられつつあり、これらの情報は多様なシステムに貯えられる場合がある。この多くは伝統的には文書としてよりもデータとして見られたであろうものである。にもかかわらず、XMLはこのデータを文書として表わし、DOMはこのデータを処理するために使われる場合があるのである。
メモ
DOM構造モデルの重要な特性の1つは構造同型性 (structual isomorphism) である。どの2つのDOM実装が同じ文書の表現を作成するために使われても、それらは全く同じオブジェクトや関連性がある同じ構造モデルを作り出すのである。
DOMは現在のところ2つの部分からなっている。DOMコアと DOM HTML とである。DOMコアは、XML文書用に使われる機能を表現し、また DOM HTML の基礎としても働く。DOMの準拠実装は、コアの章にある基本インターフェイスのすべてを、定義されている意味論をもたせて実装しなければならない。さらに、DOM HTML と拡張(XML)インターフェイスとのうち少なくとも1つを、定義されている意味論をもたせて実装しなければならない。
我々はインターフェイスを仕様化するのであって、作成されるべき現実のオブジェクトを仕様化するのではないので、DOMは、ある実装についてどのコンストラクタを呼ぶべきかを知ることができない。一般的に、DOMユーザは、Document クラス上の createXXX() メソッドを呼び出して文書構造を作成し、DOM実装は、createXXX() 関数の実装においてこれらの構造の独自の内部的構造を作成する。
DOM Core
インターフェイス Document
Document インターフェイスは、HTML文書またはXML文書の全体を表わす。概念的には、これは文書樹のルートであり、その文書のデータへの主要なアクセスを提供する。
要素、テキストノード、注釈、処理命令などは Document の文脈の外側では存在しえないから、Document インターフェイスはこれらのオブジェクトを作成するために必要なファクトリーメソッドも含む。Node オブジェクトは ownerDocument 属性をもつ。これは、オブジェクトを、それが作成された文脈の Document と結びつけるものである。
自分の認識
- Documentクラス = Document インタフェースというIDLで定義されたDOM( Core)仕様でのクラス [仕様]
- Documentオブジェクト = Documentクラスから作成された現実の実装によるオブジェクト
- Javascriptのdocument = Documentオブジェクトにアクセスするグローバル変数
理解の促進
document変数からh1要素のheader1というidのオブジェクトを取り出して、
その中のテキスト内容をdocument.writeに書き出すコードを書いてみる。
See the Pen 001.DOM-001.document by maat maat (@maatmaat) on CodePen.
DOM構造モデル
DOMは文書を、より特化した他のインターフェイスを実装もする Node オブジェクトの階層構造として表わす。ノード型の中には多様な型の子ノードをもってよいものもあるし、文書構造内でその下に何ももつことができないリーフノードであるものもある。ノード型や、それらが子としてもってよいノード型は、以下の通りである。
Nodeオブジェクトってなんや、Node インターフェイスのことか?こんがらがってきたんご。
Nodeについて学ぶ。
インターフェイス Node
Node インターフェイスは、DOM全体にとって主要なデータ型である。これは、文書樹の中にある単一のノードを表わす。Node インターフェイスを実装するオブジェクトはすべて、子を扱うためのメソッドを露出するが、Node インターフェイスを実装するオブジェクトのすべてが子をもってよいとは限らない。たとえば、Text ノードは子をもってはならず、そうしたノードに子を追加すれば DOMException を発生させることになる。
nodeName 属性、nodeValue 属性、および attributes は、引き出された特定のインターフェイスへのキャストダウンなしにノード情報をつかむための機構として組み込まれる。特定の nodeType にこれらの属性の明確な割り付けがない場合(例. Element の nodeValue や Comment の attributes)には、これは null を返す。特化されたインターフェイスは関連する情報を取得したり設定するためより簡便な追加的機構を含む場合があることに注意すること。
nodeType確認
Node型は12種類あるようだ。
const unsigned short ELEMENT_NODE = 1;
const unsigned short ATTRIBUTE_NODE = 2;
const unsigned short TEXT_NODE = 3;
const unsigned short CDATA_SECTION_NODE = 4;
const unsigned short ENTITY_REFERENCE_NODE = 5;
const unsigned short ENTITY_NODE = 6;
const unsigned short PROCESSING_INSTRUCTION_NODE = 7;
const unsigned short COMMENT_NODE = 8;
const unsigned short DOCUMENT_NODE = 9;
const unsigned short DOCUMENT_TYPE_NODE = 10;
const unsigned short DOCUMENT_FRAGMENT_NODE = 11;
const unsigned short NOTATION_NODE = 12;
理解の促進
Nodeのもつ属性の中身を確認してみる。
attribute属性のnodeTypeは2になっている。
更にattributes[0].nodeNameでidが取れている。
<body id="body" class="test">
とかするとattributes[0]でid、attributes[1]でclassが取れそう?
See the Pen 001.DOM-002.node by maat maat (@maatmaat) on CodePen.
他のインタフェースも確認しておく
DOMはまた、Node の子や Element.getElementsByTagName メソッドにより返される要素といったようなノードの順序つきリストを処理するための NodeList インターフェイスや、Element の属性といったような、それらの name 属性により参照されるノードの順序なしセットを処理するための NamedNodeMap インターフェイスも仕様化する。DOMの NodeList や NamedNodeMap は「生き」ている、すなわち基礎にある文書構造への変更が関連するすべての NodeList や NamedNodeMap に反映される。たとえば、DOMユーザが、ある Element の子を含んでいる NodeList オブジェクトを取得し、その後にその要素にもっと多くの子を追加(または子を除去または修正)すれば、それらの変更は、ユーザの側でさらなるアクションがなくとも NodeList に自動的に反映されるのである。同様に、樹の中の Node への変更は、NodeList や NamedNodeMap 内にあるそのノードへの参照すべてで反映される。
インターフェイス NodeList
NodeList インターフェイスは、この集合体の実装方法を定義したり強制したりすることなく、ノードの順序つき集合体の抽象体を提供する。
理解の促進
Node.childNodesプロパティで、
子の現在のNodeListを返すらしい。
ついでにhogehogeを取得してみた。
childNodes の代わりにchildrenを使うと、
TextNodeを含まない要素ノードだけのcollectionが得られるっぽい。
HTMLcollectionとの違いがよく分からん。生きている=HTMLcollection=動的っぽい?
See the Pen 001.DOM-003.nodelist by maat maat (@maatmaat) on CodePen.
インターフェイス NamedNodeMap
NamedNodeMap インターフェイスを実装するオブジェクトは、名前でアクセスできるノードの集合体を表現するために使われる。NamedNodeMap は NodeList からの承継をしないことに注意すること。NamedNodeMap は何らかの特定の順序で維持されないのである。NamedNodeMap を実装しているオブジェクトの中に含まれているオブジェクトは、順序を表わす添え字でアクセスしてもよいが、これは単に NamedNodeMap の内容を簡単に列挙できるようにするものであって、DOMがこれらのノードに順序を指定するという意味合いを含むのではない。
inputのtypeとかvalueとかonclickみたいなものは順序は関係ないってことか
理解の促進
inputのtypeとvalueを取得してみる
See the Pen 001.DOM-003.namednodemap by maat maat (@maatmaat) on CodePen.
DOMString 型
- DOMString は、16ビット量の物の連なりである。これはIDL用語では typedef sequence DOMString;
- アプリケーションは、UTF-16([UNICODE] の Appendix C.3 および [ISO-10646] の Amendment 1 に定義されている)を使って DOMString をエンコードしなければならない。
基本的なインタフェース
- Exception DOMException
DOMオペレーションは、「例外的」環境、すなわちオペレーションが(論理的理由や、データが失われているとか、実装が不安定になっているせいで)実行できないときにには、例外を発生させるだけである。 - インターフェイス DOMImplementation
インターフェイス DocumentFragment
性能とか考えだすと重要そうなのでちゃんと理解を深めておくか
DocumentFragment は、「軽量」または「最小限」の Document オブジェクトである。ある文書の樹の一部分を抜き出せたり、文書の新しいフラグメントを作成できたりすることを望むのはとてもよくあることである。フラグメントを移動させることで文書の切り張りのようなユーザコマンドを実装することを考えてみよ。そうしたフラグメントを保持できるオブジェクトをもつことは望ましいことであり、この目的のために Node を使うということはごく当然である。Document オブジェクトもこの役割を果たしうるのは確かであるが、Document オブジェクトは、基礎にある実装次第で潜在的に重いオブジェクトとなりうるのである。このことのために本当に必要とされるのは、ごく軽量のオブジェクトである。DocumentFragment はそうしたオブジェクトである。
さらに、多様なオペレーション -- ノードを他の Node の子として挿入するといったようなもの -- が、DocumentFragment オブジェクトを引数としてとってよい。これは、DocumentFragment の子ノードすべてを、このノードの子リストへ動かす。
DocumentFragment ノードの子は、文書の構造を定義するサブツリーの頂上を表わす0個以上のノードである。DocumentFragment ノードは整形式のXML文書である必要はない(整形式の解析されるXMLエンティティに課された規則に従う必要はあり、複数のトップノードを持つことができるが)。たとえば、DocumentFragment がもってよい子は1つだけであり、その子ノードは Text ノードであってもよい。そうした構造モデルは、HTML文書や整形式のXML文書を表わすものではない。
DocumentFragment が Document(または実際は子を取ってよいその他の Node どれでも)に挿入されるとき、その Node に挿入されるのは、DocumentFragment の子であって、DocumentFragment そのものではない。ユーザが兄弟であるノードを作成しようと思うときには、このことは DocumentFragment をとても便利なものにする。DocumentFragment はこれらのノードの親として行動し、ユーザは insertBefore() や appendChild() といったような Node インターフェイスからの標準的なメソッドを使うことができるのである。
ふぅ、整理が必要ですな。
- NodeTypeにDocumentFragmentというタイプがあるのでこれ自体はNode(IDL定義にも書いてる)
- DocumentインタフェースのIDLに
createDocumentFragment
なるメソッドがある
空の DocumentFragment オブジェクトを作成して帰り値として返す
Documentから生成されるインタフェースということか - DocumentFragmentは親を持たない => 常に何かの親として動く
- 「DocumentFragment がもってよい子は1つだけであり」、がよくわからん。「DocumentFragment ノードの子は、文書の構造を定義するサブツリーの頂上を表わす0個以上のノード、」というのと矛盾している? => 誰か教えて・・
- ユーザが兄弟であるノードを作成しようと思うときには => 兄弟関係にあるノードをまるっとDocumentFragmentを親として木構造にすることができる
- 「DocumentFragment の子ノードすべてを、このノードの子リストへ動かす。」とあるように他のノードに挿入すると子ノードは移動する
理解の促進
DocumentFragmentに子ノードを追加して、bodyに挿入する。
https://uhyohyo.net/javascript/7_4.html のパクリ。
NodeインタフェースのcloneNodeを使ってbodyに挿入しないと、
DocumentFragmentの子ノードはappendChildすると消えることが確認できた。
See the Pen 001.DOM-003.documentfragment by maat maat (@maatmaat) on CodePen.
インターフェイス CharacterData
CharacterDate インターフェイスは、DOM内のキャラクタデータにアクセスするための属性やメソッドのセットで Node を拡張するものである。The CharacterData interface extends Node with a set 明確性のため、このセットは、これらの属性やメソッドを使うオブジェクトごとにではなく、ここで定義される。Text その他は CharacterData からインターフェイスを承継するけれども、CharacterDAte に直接に対応するDOMオブジェクトはない。このインターフェイスにおける offset はすべて 0 から始まる。
理解の促進
Text ObjectはCharacterDataを継承しているので、appendDataメソッドが使えるっぽい。
See the Pen 001.DOM-004.characterdata by maat maat (@maatmaat) on CodePen.
インターフェイス Attr
Attr インターフェイスは、Element オブジェクトの属性を表わすものである。概して、属性の許容値は文書型定義の中で定義されている。
Attr オブジェクトは Node インターフェイスを継承するが、それらは実際にはそれらが記述する要素の子ノードではないので、DOMはそれらを文書樹の一部とみなさない。そこで、Node の parentNode, previousSibling, nextSibling は、Attr オブジェクトについては null 値をとる。DOMは、それらの結びつけられている要素からの分離した同一性をもつというよりも、属性は要素のプロパティであるという見方をとる。これは、そうした機能を、与えられた型の要素すべてに結びつけられたデフォルト属性として実装することをより効率的にするはずである。さらに、Attr ノードは、DocumentFragment の直接の子であってはならない。もっとも、DocumentFragment の内部に含まれている Element ノードに結びつけることはできる。要するに、DOMのユーザや実装者は、Attr ノードが、Node インターフェイスを継承している他のオブジェクトには一般的であるものをもつが、大きく異なる点もあるということを意識しなければならないのである
理解の促進
Attrの属性を確認しておく。
See the Pen 001.DOM-005.attr by maat maat (@maatmaat) on CodePen.
インターフェイス Element
文書をトラバースするときに制作者が遭遇するオブジェクト(テキストは別にして)のうちずば抜けて大多数は Element ノードである。以下のXML文書を想定してみよ。
<elementExample id="demo">
<subelement1/>
<subelement2><subsubelement/></subelement2>
</elementExample>
DOMを使って表現すると、トップノードは "elementExample" の Element ノードであり、これが、"subelement1" という要素と "subelement2" という要素の2つの子 Element を内容としている。"subelement1" は子ノードを含んでいない。
要素は、それと結びつけられた属性をもつ場合がある。Element インターフェイスは Node から継承をするので、通有的な Node インターフェイスメソッド getAttributes を使って、要素のすべての属性のセットを引き出してよい。Element インターフェイス上には、名前で Attr オブジェクトを引き出し、または名前で属性値を引き出すためのメソッドがある。XMLでは、属性値はエンティティ参照を含む場合があり、属性値を表現しているおそらく相当に複雑なサブツリーを試すためには、Attr オブジェクトが使われるべきである。他方、HTMLでは、すべての属性が単純な文字列値をもち、属性値に直接にアクセスするためメソッドを、簡便な手段として安心して使うことができる。
理解の促進
normalizeの挙動を確認しておく。
See the Pen 001.DOM-005.element by maat maat (@maatmaat) on CodePen.
インターフェイス Text
Text インターフェイスは、Element または Attr のテキスト的内容(XMLではキャラクタデータと呼ばれる)を表わす。要素の内容の内部にマークアップがない場合には、テキストは、要素の唯一の子である Text インターフェイスを実装した単一のオブジェクトの中に含まれる。マークアップがある場合には、それは、その要素の子のリストを形成する要素と Text ノードとのリストへと解析される。
最初に文書がDOMを経由して利用可能にされたときには、各テキストブロックごとに Text ノードは1つしかない。ユーザは、間に挟まるマークアップなしで、与えられた要素の内容を表わす隣接した Text を作成してもよいが、XMLやHTMLでこれらのノードの間の分離を表わす方法がなく、そのためそれらは(一般的に)DOM編集の期間と期間の間は永続しないことになることを意識して置くべきである。Element オブジェクト上の normalize() メソッドは、そうした隣接する Text オブジェクトを、テキストブロックごとに単一のノードへと併合する。これは、XPointer でのナビゲーションといったような、特定の文書構造に依存する操作を採用するより前に推奨される。
インターフェイス Comment
これは注釈の内容、すなわち、開始記号 '<!--' と終了記号 '-->' との間のすべてのキャラクタを表現する。これはXMLや(HTMLツールの中には完全なSGML注釈構造を実装するものもあるかもしれないけれども実際には)HTMLの注釈の定義であることに注意すること。
DOM1(HTML)
より明確に言うと、この文書は、HTMLのための以下の特化を組み込む。
HTMLDocument インターフェイス。コア Document インターフェイスから派生する。HTMLDocument は、HTML文書上でなしうる操作やクエリーを指定する。
HTMLElement インターフェイス。コア Element インターフェイスから派生する。HTMLElement は、任意のHTML要素上でなしうる操作やクエリーを指定する。HTMLElement 上のメソッドには、すべてのHTML要素に適用される属性の引き出しや修正を可能にするものが含まれる。
HTMLElement インターフェイスで指定されたものを越えて広がる属性をもつすべてのHTML要素のための特化。そうした属性すべてについて、派生された要素のインターフェイスは、値を設定したり取得するための明示的なメソッドを含んでいる。
DOM1は、CSS1を通して指定されたスタイルにアクセスしたり修正する機構を組み込んでいない。その上、HTML文書のためのイベントモデルも定義しない。この機能は、この仕様書の将来の水準で仕様化する計画である。
インターフェイス HTMLCollection
HTMLCollection はノードのリストである。個別のノードは、通常の添え字、またはそのノードの name もしくは id 属性によってアクセスしてよい。注意:HTML DOMにおける集合体は生きているものと想定される。これは、基礎にある文書が変更されたときには自動的に更新されるという意味である。
理解の促進
document.getElementsByTagName('p')
で取れるデータがHTMLCollection
See the Pen 001.DOM-006.HTMLcollection by maat maat (@maatmaat) on CodePen.
インターフェイス HTMLDocument
HTMLDocument は、HTML階層構造のルートであり、内容全体を保持するものである。階層構造へのアクセスを提供することだけでなく、文書からの一定セットの情報にアクセスするための簡便メソッドもいくつか提供する。
インターフェイス HTMLElement
すべてのHTML要素インターフェイスは、このクラスから派生する。HTMLコア属性だけを露出する要素は、ベース HTMLElement インターフェイスによって表わされる。これらの要素は以下の通りである。
インターフェイス HTMLHtmlElement
HTML文書のルート (root)。HTML 4.0 の HTML 要素の定義を見ること。
インターフェイス HTMLHeadElement
文書ヘッダ情報。HTML 4.0 の HEAD 要素の定義を見ること。
その他HTMLに関するインタフェースが羅列されているが書く意味を感じないので割愛。
こんなのがあるのかレベルでさらっと流し読みした。
今後の予定
次はXMLHttpRequestについて学ぶ