今日は、もりけん塾のJavaScript課題2を終えて学んだことをアウトプットしていきます。
こんにちは。Webコーダーのはるです。
現在、所属している「もりけん塾」でハンズオン課題 に取り組み、レビューをいただいています。
今日は、課題2 についてアウトプットをしていきます!
前回のアウトプットは、こちらです。
【もりけん塾】JavaScript課題 2で学んだこと まとめ
今回、取り組んだ課題はこちらです。
(もりけんさんのJavaScriptハンズオン課題より)
この課題から学んだこと
・属性を書き換える setAttributeと.プロパティの違い
・insertAdjacentElementとinsertBeforeの違い
・メソッドチェーンの使い方
一つずつまとめていきます。
用語:DOM、ノード、API
初歩的な言葉ですが、なんとなくわかる→自分の言葉で説明できるようにと思い、調べました。
DOM
- DOMとは、Document Object Modelの略。大まかに言うとJavaScript側からHTMLを操作するための仕組みのことです。(※JavaScriptではなく、他のほとんどの言語でも存在する仕組みですが、今回はJavaScriptで表現)
- DOMは、ノード※を取得・追加・置換・削除するための手段を提供するAPI※
- DOMは、HTMLを文書ツリーとして解釈する。下図のように全ての要素をツリー構造にします。
(引用:正しいHTMLとドキュメントツリーを理解しよう より拝借) - 個人的に、stackOverflow引用の以下の説明がわかりやすかったです。
Document object model.
The DOM is the way Javascript sees its containing pages’ data. It is an object that includes how the HTML/XHTML/XML is formatted, as well as the browser state.A DOM element is something like a DIV, HTML, BODY element on a page. You can add classes to all of these using CSS, or interact with them using JS.
(Document Object Modelの略。
DOMとは、Javascriptがページのデータを見るためのものです。それは、HTML/XHTML/XMLがどのようにフォーマットされているか、また、ブラウザの状態を含むオブジェクトです。DOM 要素は、ページ上の DIV、HTML、BODY 要素のようなものです。これらすべてにCSSでクラスを追加したり、JSで操作したりすることができます。)
ノード
- 節、点、集合点 などの意味をもつ単語。
- HTML文書におけるノードは、要素・属性・テキストなどのオブジェクトのことを指す。
・<title>を要素ノード
・idを属性ノード
・haru logをテキストノード
と呼ぶ。
API
「APIとは、あるプログラムを、外部から使用する時の規約を定めたもの」という書き方をしている文書が多かったです。
厳密には規約のことだけれど、あるプログラムを外部から使用するときの”窓口”と考えたほうがわかりやすいと下記サイトに書いてあり、確かにイメージができました。
今回の使われどころは「DOMは、ノード※を取得・追加・置換・削除するための手段を提供するAPI※」だったので、ここまで調べた内容で書き換えてみます。
「DOMは、HTMLの要素を取得・追加・置換・削除するための手段を提供するプログラムの規約(≒窓口)」と言うことですね。
DOMという仕組を通じて、JavaScriptでノードをいじることができるとわかりました。
ここまでの用語は、以下のサイトとJavaScript本格入門本で調べました。
属性を書き換える setAttributeと.プロパティの違い
さて、課題に戻ります。課題をもう一度貼ります。
JavaScriptで<li>~を差し込む機能を作っていきます。
<a><img>のノードを作るために、createElement()で作成した要素ノードにそれぞれ必要な属性を追加しました。
属性の追加や書き換えは、2つの手段がありますが私は.プロパティの書き方を採用しました。
anchor.href = "1.html";
.hrefのように、属性を.プロパティでつなげることで参照や書き換えをする方法です。
わたしが採用した根拠1は、「JavaScript本格入門」本に
・setAttributeは文字列として指定できるので、取得・設定する属性名をスクリプトから動的に変更できる
・そのときの状況に応じて使い分ける
・属性とプロパティの名前の違いを意識したくないならば、setAttributeを利用してください
と書かれていたからです。
属性とプロパティの名前の違いとは、
- href属性を付けたいときは.hrefプロパティを使用
- src属性を付けたいときは.srcプロパティを使用
- class属性を付けたいときは.classNameプロパティを使用
最後のclassのように、異なる場合もあると言うことです。
属性名を動的に変更する場合を除いて、普段は.プロパティを使用するのが良いかなと思いました。
また、根拠2として NEWBEDEV.に
You should always use the direct .attribute form (but see the quirksmode link below) if you want programmatic access in JavaScript. It should handle the different types of attributes (think “onload”) correctly.
Use getAttribute/setAttribute when you wish to deal with the DOM as it is (e.g. literal text only).(JavaScriptでプログラム的にアクセスしたい場合は、常にダイレクトな.attribute形式(ただし、下記のquirksmodeのリンクを参照)を使うべきです。これは、異なるタイプの属性(”onload “を考えてください)を正しく処理します。
DOMをそのまま扱いたい場合は、getAttribute/setAttributeを使ってください(例:リテラルテキストのみ)。)
とも書かれています。
ちなみに、setAttributeを使うと以下のように書くことができます。もともと属性がついている場合は属性値を書き換え、新規の場合は追加されます。
setAttribute("type","属性値")
//
*この後、塾のDiscordでsetAttributeと検索入れてみたら…すでに議論されていました…!!
参考資料が貼られていたので、ご紹介します。@_syoyamamoto_さんありがとうございます🙇♀️
以下は、先生がまとめてくださったものです。とてもわかりやかったので、参照されることをお勧めいたします。
先生の記事より引用させていただきます。
- DOM propertyとして標準で持っているプロパティなら
elem.id = "js-hoge"
setAttribute
はDOMが持っていないカスタムな属性を付与したい時に使う
inputElement
に対してset/getAttribute
を使うと静的な値しか取れない(現在の値にアクセスしたい場合はプロパティを直接参照したり代入したりする)
3のように、set/getAttributeを使うと意図しない動作になることがあります。通常は、.プロパティで対応しようと思います。
insertAdjacentElementとinsertBeforeの違い
課題に戻ります。次に、調べたのは指定の場所にノードを挿入する方法です。
前回は、最後の子要素として挿入するappendChildを使用しましたが、今回は指定の場所に挿入したいのでこのメソッドは使えません。
そこでinsertAdjacentElementとinsertBeforeを調べました。
insertAdjacentElement
構文はこちらです。
Element.insertAdjacentElement(追加したい場所,追加したい要素);
追加したい場所に、追加したい要素を挿入するメソッドです。
【指定のポジション】
- beforebegin: 指定したelementオブジェクトの直前
- afterbegin: 指定したelementオブジェクトの最初の子要素の前
- beforeend: 指定したelementオブジェクトの最後の子要素の後
- afterend: 指定したelementオブジェクトの直後
insertAdjacentはMDNに日本語訳がありませんでした。ブラウザは2021.07現在、フルサポートです。
insertBefore
構文はこちらです。
Element.insertBefore(追加したい要素, 追加したい場所);
追加したい要素を、追加したい場所(要素)の直前に挿入するメソッドです。
直前というのが特徴です。
insertBeforeの対としてinsertAfterというメソッドは存在しません。代わりに、以下のように書くと指定した場所の直後に挿入することができます。
Element.insertBefore(追加したい要素, null);
こちらはMDNに日本語訳がありました。こちらも、2021.07現在ブラウザフルサポートです。
//
ここまで、insertAdjacentElement と insertBeforeの使い方をアウトプットしました。
今回の課題の「<a> の子ノードの直前に<img>を挿入したい」場面で、どちらのメソッドも使用可能だったのですがinsertAdjacentElementを選択しました。
3年前の記事だったのですが、stackOverflowにパフォーマンスに関する記述を見つけました。
Overall speed is the bottom line, repaints is just one part of a bigger world that is the DOM. On Chrome both
insertAdjacentElement/HTML
were considerably faster thaninsertBefore()
(by @10%), while in Firefox only marginally (by .55%).(全体的な速度が重要であり、repaintsはDOMという大きな世界の一部分に過ぎません。ChromeではinsertAdjacentElement/HTMLの両方がinsertBefore()よりもかなり速く(10%程度)、Firefoxではわずかに(0.55%程度)しか速くなりませんでした。)
パフォーマンスに関する記事や、どちらかを使うときのデメリットなどを他に見つけることができなかったため、inserAdjacentElementを選択しました。
どちらかを使うメリット・デメリットなどがあればぜひご教授いただきたいです。
メソッドチェーンの使い方
今回のPR (プルリクエスト)で塾生のsenさん(@websen5)にレビューをいただいたのでアウトプットです。
課題の最後、作成したElementを組み立てるとき、わたしが書いたコードです。
ul.appendChild(li);
li.appendChild(anchor);
anchor.insertAdjacentElement('afterbegin',img);
レビューをいただいて修正したコードは以下です。
ul.appendChild(li).appendChild(anchor).insertAdjacentElement('afterbegin',img);
一行でスッキリ書くことができました!
これは、メソッドチェーンという書き方を使用しています。
メソッドチェーンは、オブジェクト.メソッド1().メソッド2()… のように、一つのオブジェクトに対してメソッドを複数つなげられる記法です。前のメソッドの戻り値に対して、次のメソッドが実行されます。
今回のコードだと、
・appendした要素に対して、次のメソッドが実行される
このように説明することができます。
ただし、メソッドチェーンは繋げすぎるとデバックが大変になるというデメリットもあるので注意が必要です。
塾生のsenさん(@websen5)に教えていただいた記事と、
以下の記事を参考にしました。
//
学習に使用している本は、もりけん先生推奨のこちらです。
あとがき
MDNなどで使うメソッドのことをよく調べてから実装しています。
それぞれのメソッドがどのような働きをして、他のメソッドとどう違うのか一つずつ理解しています。
今回コードを見てくださった、もりけん先生(@terrace_tec)と塾生のsenさん(@websen5)に感謝です!ありがとうございました。
わたしの書いたコードはこちらから確認できます。
今日は以上です。
【もりけん塾で勉強しています】
Thanks:師匠「もりけんさん」(@terrace_tec)
もりけんさんのHPはこちら