備忘と現場で使える JavaScript Tips
はじめに
現場でコードを書いていると、以前学習したことをすっかり忘れており時間をロスしてしまうことがあったりする。
案件が終わったタイミングでその都度備忘とTipsを纏められたら良いのだが、業務内にその時間の確保するのがけっこう難しくて今年もそれができなかった。
コロナの影響で例年以上に時間に余りある正月休みになっているので、お酒でも飲みながらゆるっと思い出せるかぎりの備忘とTipsを残していこうと思う。大した内容でもないがどこぞの誰かにとっての一助になれば嬉しい。
備忘とTipsの線引きはけっこう適当である。
では備忘。
element.querySelectorAll()
element.querySelectorAll は、NodeList
を取得していることを忘れがちになる。
element.querySelector だと Element
を取得するので、つい同じ感覚で扱おうとして画面に現れるこいつ。
Uncaught TypeError: hogeList.map is not a function (なんでや)
配列として扱えるようになるには Array.from
を使って新しい配列インスタンスを生成してからであることを覚えておきたい。
// 前提として dummyElement はすでに取得済みのElementノード const hogeList = Array.from(dummyElement.querySelectorAll('.targetClass'));
Function.prototype.apply()
apply()
は、thisを指定してFunctionを呼び出し、配列を引数にして関数を呼び出すことができる。
例えば Math.max()
で引数に配列渡して最大値取り出そうと思ったら配列渡せないわ、みたいなことがたまに現場で遭遇してた。
別に reduce
とか使えば最大値は取り出せるけど、楽に取り出したいときは、断然以下の方法が簡単だったりするので apply()
は覚えておきたい。
const compareArray = [1, 2, 3, 4, 5]; const maxNum = Math.max.apply(null, compareArray); // Mathは組み込みオブジェクトだから this 指定は null で問題なし( this 指定は省略できない)
更に apply()
はスプレッド構文で置き換えることができるので、その方が短く書けるし、見通しもまあ良いので以下のように書きたい。
const compareArray = [1, 2, 3, 4, 5]; const max = Math.max(...compareArray);
DOM操作(要素の取得, 追加, 書き換え)
コードを書いていて、この辺りの操作をしたいけど何を使えば良いんだっけ・・・とかよく詰まっていた気がする。
頻繁に書くようなものでもないので、たまに遭遇して困っていたので纏めておく。
innerHTML
シリアライズされるので結果としてHTML文字列が返される。
InnerHTML
に値を設定すると、要素のすべての子孫を削除して、与えられたHTML文字列をパースして構築されたノードに置き換えられる。
InnerHTML
を使って書き換える場合に起こる順番として、挿入先の要素を一旦全てシリアライズして、全ての子孫を削除して、代入するHTML文字列をパースして、構築したノードで置き換える。
もし挿入先の要素にあらかじめイベントを付与していた場合、この過程でイベントは削除されることを覚えておきたい。
HTMLパースされるのが、外部から指定されたHTML文字列の場合はサニタイズしないとXSSの原因となるので、サニタイズ用の関数などでエスケープして無害化してあげると良い。
サニタイズの参考サイト
How to sanitize third-party content with vanilla JS to prevent cross-site scripting (XSS) attacks | Go Make Things
insertAdjacentHTML
第二引数で指定されたHTML文字列がパースされて、その結果であるノードを第一引数で指定した箇所に挿入する。
挿入先の要素を再度パースしないので、既存の要素や要素に付与されているイベントは削除されない。
InnerHTML
と違って、余分なシリアル化がされないので InnerHTML
への代入による直接的な操作より高速なのでこっちの方が良い場合はこっち使う。
element.parentNode
たまに、取得した要素の親要素を起点として要素の追加をしたい場面に遭遇したりする。
そんなときは element.parentNode
で親ノードを取得すれば、簡単に実現可能なので、parentNode
は覚えておきたい。
取得しているのは Element
ではなく Node
なので、以下のメソッドなどが使える。
このあたり一覧でまとまってるサイトないか探したところ以下のサイトがすごく見やすく纏まってたので参考に載せる。
https://www.wakuwakubank.com/posts/306-javascript-dom/
ではTips。
spliceで一部の配列を取り出して別の配列で組み替えたい
Array.prototype.splice()
で一部の配列を他の配列で組み替えたいときにワンライナーで書ける方法。めちゃ楽だけど僕には思いつけない。
思いついた人はほんと天才だと思った。こういう閃きはどうやったら養えるのだろうか。
参考文献
まず Function.prototype.apply()
を使う方法。
const testArray01 = [{aa: 1}, {aa: 2}, {aa: 3}, {aa: 4}, {aa: 5}, {aa: 6}, {aa: 7}, {aa: 8}, {aa: 9}, {aa: 10}]; const testArray02 = [{bb: 1}, {bb: 2}, {bb: 3}, {bb: 4}, {bb: 5}, {bb: 6}, {bb: 7}, {bb: 8}, {bb: 9}, {bb: 10}]; testArray01.splice.apply(testArray01, [1*5, 1].concat(testArray02)); // output は以下 // Array [Object { aa: 1 }, Object { aa: 2 }, Object { aa: 3 }, Object { aa: 4 }, Object { aa: 5 }, Object { bb: 1 }, Object { bb: 2 }, Object { bb: 3 }, Object { bb: 4 }, Object { bb: 5 }, Object { bb: 6 }, Object { bb: 7 }, Object { bb: 8 }, Object { bb: 9 }, Object { bb: 10 }, Object { aa: 7 }, Object { aa: 8 }, Object { aa: 9 }, Object { aa: 10 }]
備忘で書いた通り、スプレッド構文でより短く書ける。
const testArray01 = [{aa: 1}, {aa: 2}, {aa: 3}, {aa: 4}, {aa: 5}, {aa: 6}, {aa: 7}, {aa: 8}, {aa: 9}, {aa: 10}]; const testArray02 = [{bb: 1}, {bb: 2}, {bb: 3}, {bb: 4}, {bb: 5}, {bb: 6}, {bb: 7}, {bb: 8}, {bb: 9}, {bb: 10}]; testArray01.splice(...[1*5, 1].concat(testArray02));
飲んでたお酒もなくなってしまった。
正月休み中にもう少し書こうと思う。
読んでくれた方々ありがとうございました。