
JavaScriptガチでわからんを脱却するまでの道のり その1
最近立て続けに「ReactやVueみたいなフロントのフレームワークを軽く触れる程度の知識があればもっと上手くできたんだろうなー」と思うような出来事が連続して身の回りで起こりました。
日頃はサーバーサイドエンジニアとして働いており、ちょっとだけnode.jsなんかは触ったことあるのですが、そもそもフロントの基礎やお作法なんかを全く知らず、JavaScriptも動的型付け言語でフロントエンジニアからのヘイトが高いぐらいの知識しかありませんでした。
もちろん、なぜクライアントサイド・スクリプトとして主にJavaScriptが広く使われているかすらよくわかっていません。
そんなフロントよわよわ状態を脱却したくなり、一度本腰を入れて勉強を初めてみることにしました。
JavaScriptガチでわからん状態を脱却したくて、せめて基礎だけでも勉強始めてみた
— あきの/D-En (@DddEndow) October 24, 2020
まだ読み始めたばかりだけど、実際にHTML操作しているの見るだけでも面白いhttps://t.co/Ev0H3Ciwc8
というわけで以前ちらりと見かけたこちらのサイトを参考にサクッと一通りやっていきたいと思います。(今回は2章まで)
基礎〜オブジェクトの解説
ここら辺の話は知ってたから飛ばします。
DOM
・Document Object Model
・プログラムでHTMLやXMLを扱うための仕様。
・DOM Level 1仕様書に一番基本的な部分が書かれている。
<body>
<p id="aaaaa">t<strong>es</strong>t</p>
// JavaScriptはscript要素が読み込まれた時点で即座に実行される。
<script type="text/javascript">
var a = document.getElementById('aaaaa');
console.log(a);
console.log(a.innerHTML);
</script>
</body>
ノード
・文書(document)を構成するもの。
・12種類ある。
・要素を表すオブジェクトはHTMLElementと呼ばれる。
・ノードもある種のオブジェクト。
innerHTML
・実際に新しい中身を代入したら実際に書き換わる。
・木構造を全部壊して、新しい木構造を一から作る事になる。
<body>
<p id="aaaaa">t<strong>es</strong>t</p>
<script type="text/javascript">
var p = document.getElementById('aaaaa');
p.innerHTML = "書き換えました";
</script>
</body>
parentNodeプロパティ
・親ノードが代入されている。
・書き換えられない。(参照のみ)
・タグ名を見る場合→ p.parentNode.tagName
childNodesプロパティ
・子ノードの一覧がNodeListの形で入ってる。
NodeListはいろいろなプロパティを持っている
・lenght:NodeListにあるノードの数。
・item:引数番目のノードを返す。
テキストノードの操作
<body>
<p id="aaaaa">t<strong>es</strong>t</p>
<script type="text/javascript">
var p = document.getElementById('aaaaa');
var children = p.childNodes;
var textnode = children.item(0); //テキストノード
console.log(textnode.nodeValue);
textnode.nodeValue = "書き換えました";
</script>
</body>
・テキストノードはnodeValueというプロパティを持つ。
・参照の他に書き換えることも可能。
子ノードの削除【removeChild】
<body>
<p id="aaaaa">t<strong>es</strong>t</p>
<script type="text/javascript">
var p = document.getElementById('aaaaa');
var children = p.childNodes;
var textnode = children[0]; //テキストノード
p.removeChild(textnode);
</script>
</body>
・自身の子ノードのうち、引数のノードが表すノードを除去するメソッド。
・除去されたノードは木構造から取り除かれただけで、即座に消滅したわけではない。(=また別の場所で使用することができる)
・子ノードが削除されるたびに順番が詰められる。
子ノードを全除去したい場合は基本removeChildを使って一つずつ除去する。
・hasChildNodesを使って子ノードの存在をチェックし、存在すればremoveChildを実行し続けたりなど。
・firstChildやlastChildなどもあるので有効活用する。
ノードの追加
ノードを作る【createElement】
・要素名を指定することで、新しいHTMLElementを作って返す。
・documentが持つメソッド。
document.createElement('p')
console.log(newelement);
// <p></p>
ノードを追加する【appendChild】
・ノードの一番最後に引数のノードが追加される。
var newelement = document.createElement('p');
document.body.appendChild(newelement);
テキストノードを作成する【createTextNode】
・以下のようにテキストノードを作成し、新しく作成したp要素に追加し、それをbody要素に追加する。
var newelement = document.createElement('p');
var newtextnode = document.createTextNode("新しいテキストノード");
newelement.appendChild(newtextnode);
document.body.appendChild(newelement);
木構造の操作:様々な機能
getElementsByTagName
・引数に要素名を渡すと、その要素一覧のNodeListを返す。
・"*"を引数にすると全ての要素を取得できる。
<body>
<p>t<strong>es</strong>t</p>
<p><strong>t</strong>e<strong>st</strong></p>
<script type="text/javascript">
var nodelist = document.getElementsByTagName('strong');
console.log(nodelist.length);
// 3
</script>
</body>
汎用的なHTMLElementのプロパティ
・id
・className
・title
insertBefore
・指定したノードの直前に新しいノードを追加する。
<body>
<p id="aaaaa">t<strong>es</strong>t</p>
<script type="text/javascript">
var a = document.createElement('a');
a.href = "http://www.google.com/";
var textnode = document.createTextNode("Google");
a.appendChild(textnode);
var p = document.getElementById('aaaaa');
p.insertBefore(a, p.firstChild);
</script>
</body>
兄弟ノード【previousSibling, nextSibling】
・previousSibling:一つ前の兄弟
・nextSibling:一つ後の兄弟
・ただし間にテキストノード(改行など)があるとそちらを取得してしまうことがある。
// この場合、p要素を取得するのではなく改行のテキストノードを取得してしまう。
<p>段落1です。</p>
<p id="abc">段落2です。</p>
<p>段落3です。</p>
previousElementSibling, nextElementSibling
・前の要素ノード、次の要素ノードを取得できる。
子ノードを置き換える【replaceChild】
var p = document.getElementById('aaaaa');
var newnode = document.createElement('em');
newnode.appendChild(document.createTextNode('置き換えるノード'));
p.replaceChild(newnode, p.firstChild);
ノードをコピーする【cloneNode】
・ノードはオブジェクトの一種なのでvar b =a;のようにしても同じノードを指してしまいうまくいかない。
・cloneNodeを使用することで新しいノードを作成する。
・引数がtrue:子ノードも全てコピーする。
・引数がfalse:そのノードのみコピーする。
var newnode = p.cloneNode(true);
document.body.appendChild(newnode);
テーブル操作
・table要素の中にtbodyやthead, tfootなどの要素が存在する可能性がある。
・そのため木構造の操作で一元的に扱うのは難しい。
HTMLTableElement
rows
・そのテーブルが持つtr要素全てがまとめられている。
・→テーブルのtr要素を一元的に操作可能。
・HTMLCollectionという。(NodeListと同じように扱える)
<body>
<table id="aaaaa">
<tr>
<td>test1</td>
<td>test2</td>
</tr>
<tr>
<td>test3</td>
<td>test4</td>
</tr>
</table>
<script type="text/javascript">
var table = document.getElementById('aaaaa');
var collection = table.rows;
console.log(collection[0]);
// 以下の値が表示される。
// <tr>
// <td>test1</td>
// <td>test2</td>
// </tr>
</script>
</body>
HTMLTableRowElement
・tr要素のHTMLElement
cells
・rowsプロパティのtd版
・そのtr要素が持つtd要素(とth要素)のHTMLCollection
<body>
<table id="aaaaa">
<tr>
<td>test1</td>
<td>test2</td>
</tr>
<tr>
<td>test3</td>
<td>test4</td>
</tr>
</table>
<script type="text/javascript">
var table = document.getElementById('aaaaa');
var tr = table.rows[0];
var td = tr.cells[0];
td.firstChild.nodeValue = "tttttttt";
// test1がttttttttになる
</script>
</body>
列・セルの追加【insertRow, insertCell】
insertRow
・引数で数値で指定した場所に列を挿入する。
・-1を指定する、または引数を指定しないと最後の列に追加する。
insertCell
・引数で指定した場所にtd要素を追加する。
・insertRowと同じように-1や引数を指定しないと最後に追加される。
<script type="text/javascript">
var table = document.getElementById('aaaaa');
var newtr = table.insertRow( table.rows.length );
for(var i=0;i<2;i++){
var newtd = newtr.insertCell( newtr.cells.length );
newtd.appendChild( document.createTextNode('testtest'+i) );
}
</script>
列・セルの除去【deleteRow, deleteCell】
・子ノードがあっても求めて除去される。
<script type="text/javascript">
var table = document.getElementById('aaaaa');
table.deleteRow(0);
</script>
列やセルの番号を確認する【rowIndex, cellIndex】
・先に除去したいtr要素のHTMLElementがあった場合、それが列やセルのどこにあるのかわからない。
・→rowIndex, cellIndexのプロパティを使用することで何番目の要素か知ることができる。
theadとtfoot
・それぞれテーブルの「ヘッダ」と「フッタ」を記述するためのもの。
・それぞれ何行でもかける。
・thead,tbody,tfootの他にもcaptionやcol,colgroupなどがある。
・thead, tfootはなくても問題ないが、それぞれ一個まで。(tbodyは複数ok)
・thead,tfoot,tbodyのHTMLElementは、HTMLTableSectionElementと呼ばれる。(それぞれにinsertRowとDeleteRowを持っている)
・theadとtfootはcreateTHeadとcreateTFootで取得できる。(返り値はそれぞれのオブジェクト)
・またdeleteTHeadとdeleteTFootで削除可能。
・tbodyは複数ある可能性があるので、table要素のtBodiesというプロパティにHTMLCollectionが入っている。
<script type="text/javascript">
var table = document.getElementById('aaaaa');
var tbody = table.tBodies.item(0);
var newtr = tbody.insertRow(0);
for(var i=0;i<2;i++){
var newtd = newtr.insertCell( newtr.cells.length );
newtd.appendChild( document.createTextNode('testtest'+i) );
}
</script>
img要素
・img要素のHTMLElementは、HTMLImageElementと呼ぶ。
・よく使用されるプロパティとしてsrcやaltなどがあるが、そのままimg要素のsrc属性、alt属性を表す。
<body>
<p><img src="aaaa.gif" alt="aaaa" id="abcd"></p>
<script type="text/javascript">
var img = document.getElementById('abcd');
console.log(img.src);
console.log(img.alt);
</script>
</body>
text
・title要素やscript要素にはtextというプロパティがある。
・その要素の子ノードのテキストのーどの値と同じ。
・書き換え可能。
属性の操作
getAttribute
・ある属性を取得するときに使用する。
・引数は取得する属性の名前を文字列で指定する。
setAttribute
・ある属性を変更する時に使用する。
img.getAttribute("src");
img.setAttribute("alt", "zzzz");
ただしそれぞれ専用のプロパティを使うようにした方が見通しも良くなるので、そちらの方がおすすめ。
スタイルシートの操作
要素のスタイルを変更する
・HTMLElementがstyleというプロパティを持っているので、これをいじることでスタイルを操作できる。
・"background-color"のような場合ローワーキャメルで書く。
<body>
<p style="background-color:yellow">test</p>
<script type="text/javascript">
var p = document.getElementsByTagName('p').item(0);
p.style.border = "10px solid black";
</script>
</body>
フォームの操作
・form要素のHTMLElementは、HTMLFormElementと呼ばれる。
・formsプロパティで操作可能。
・formsにはそのページ内の全てのformが配列で含まれている。
var form = document.forms.item(0);
・HTMLCollectionには番号で要素を取得するほかに、名前で要素を取得する機能がある。
・namedItemメソッド:引数で与えられた名前(id属性 or name属性)を持つ要素を探して返す。
<form id="form1" action="?">
</form>
// 以下のようにプロパティにアクセスできる。
var form = document.forms.namedItem("form1");
var form = document.forms["form1"];
var form = document.forms.form1;
elements
・そのフォームが持つコントロールのHTMLCollection
・コントロールはフォームの中にある操作できるもののこと(select要素、input要素、textarea要素、button要素など)
HTMLFormElementのメソッド
・submitとresetの二つのメソッドを持っている。
・実行すると以下のボタンを押したのと同じ動作をする。
<input type="submit" value="送信">
<input type="reset" value="送信">
HTMLInputElement
汎用のプロパティ
formプロパティ
・書き換えはできない
valueプロパティ
・現在の値を取得できる。
・変更前の元の値を取得するにはdefaultValueプロパティを使用する。
<body>
<form action="?">
<p>
<input id="aaa" type="text" value="testtest">
<input type="button" value="check" onclick="check();">
</p>
</form>
<script type="text/javascript">
function check(){
var input = document.getElementById('aaa');
console.log(input.value);
}
</script>
</body>
disableプロパティ
・disable属性を取得する。
・文字列ではなく真偽値が入っている。
typeプロパティ
・type属性に対応し、そのコントロールの種類が文字列で入っている。
blurメソッド
・コントローラからフォーカスを外す。
focusメソッド
・コントローラにフォーカスを与える。
clickメソッド
・コントロールをクリックしたことにする。
入力ボックス
readOnlyプロパティ
・readonly属性を取得する。
・真偽値が入っている。
selectメソッド
・入力ボックスの文字を全て選択状態にする。
チェックボックス・ラジオボタン
checkedプロパティ
・真偽値でチェックされていればtrue、されていなければfalse。
・現在の状態を取得する。
・最初の状態を取得するにはdefaultCheckedプロパティを使用する。
HTMLSelectElement
・select要素のHTMLElement
options
・select要素の持つoption要素のHTMLOptionsCollection
・optgroupも含まれる。
selecteIndex
・今選択されているoptionの番号を取得するプロパティ。
・何も選択されていない場合は-1が返される。
optionの追加と除去【add, remove】
追加:add
・第一引数は追加するノード、第二引数には追加するところの直後にあるノードを指定する。
var select = document.getElementById('aaa');
var option = document.createElement('option');
option.text="option4";
select.add(option, select.options.item(0) );
除去:remove
・除去するoptionの番号を引数に渡す。
var select = document.getElementById('aaa');
select.remove(0);
最後に
まだまだ始めたばかりですが思っていたよりも数段楽しく学習できています。
今まで感じていた「このページはどうやって動いているんだろう?」という疑問がどんどん氷解していくようで全然飽きがきませんでした。
またブログの書き方がとても丁寧でわかりやすく、サンプルコードが一つ一つ必ず付けられており、とりあえずコピペしてブラウザで動かせば説明されているものがどんなものかわかるようになっているのが素晴らしかったです。
ただブログ内の冒頭でも触れられていますが、書き始めが2010年と長く続けられてたブログなので若干古い情報があったり、そもそも2017年で更新が止まってたりと一部自分で情報をアップデートする必要がある箇所があります。
それを差し引いたとしてもJavaScriptではどんなことができて、何のためにあるのかをざっくり学習できる無料のコンテンツとしてはほぼ最高のものなのではないでしょうか。
このブログを用いた学習の進捗をこれ以上書く予定は今のところないですが、中級者になってフレームワークを触る段階まで進んだらまた書こうと思います。
気軽にクリエイターの支援と、記事のオススメができます!