見出し画像

「getElementByIdの括弧の中に書くのはtarget?、それとも'target'?」がわかるようになるコラム(もしくはMDNの読み解き方)

今年は 256times で JavaScript が学べるクラスを展開していこうと思っているのですが、「質問が来るに違いない…」と思われるものを先回りしてコラムにしておきます。

【はじめに】
学習の段階にもよりますが、少し難しめのコラムとなっています。最初からすべてを理解する必要はないので、わからなければ「命令の仕様とか文字列とかいろいろあるのね」という意識だけ今は持っておいて、必要なときにまた見返してみると良いでしょう。

シングルクォーテーションはいつつけるの?

JavaScript の学習を始めた方からよくいただく質問として、以下のようなものがあります。

「次の 2 つのコードはどう違うの?シングルクォーテーションをつけるときとつけないときの違いは?つけたらエラーになったりならなかったり、どちらが正しいのかわかりません。

document.getElementById('target')
document.getElementById(target)

…ですよね、わかります。このコラムではこれらの違いが理解できるように、順を追って説明していきます。

命令には仕様がある

まずシングルクォーテーション云々の前に、「document.getElementById()」などの命令にはかっちりとした仕様が定められていて、それについて理解することが最初のステップになります。

そして JavaScriptの仕様ですが、HTML / CSS 同様、MDN で調べるのが良いでしょう。「getElementById mdn」などで検索すると以下のページがヒットしますね。

「メソッドって…なんだろう?」などなどが気になりますが、大事なのはその下にある「構文」です。

この構文をみると「getElementById() の括弧のなかには id を入れてね」と書かれています。そして id については下の「引数」に書かれています(「引数」は雑にいうと括弧のなかに入れる値のことです)。

上を見ると「 id は探したい要素の ID(HTML でつけた id 属性の値)で、文字列でないといけない」と書かれています。慣れないと少し難しいのですが、ここまでをまとめると以下のようになります。

  • getElementById() などの命令には仕様が定められているので MDN で調べよう!

  • getElementById() については、括弧のなかにいれるのは要素の ID を表す文字列にしないといけない。

では次に、その「文字列」について見ていきましょう。

文字列はコード内でどう表現される?

さて、getElementById の括弧に「(ID を表す)文字列」を渡せばいいとわかったのですが、コード内で文字列はどう表現されるでしょうか?

少しでも JavaScript を学習した人なら「文字列はシングルクォーテーションか、ダブルクオーテーションで囲ったものでしょ?あ、だったら『'target'』としたものが正解か!」と思うかもしれません。

document.getElementById('target')

これは半分正解ですが、「文字列にはいつでもシングルクォーテーションがつている」、したがって、「シングルクオーテーションがついていないものは文字列ではない」と考えていると罠にハマります…。

結論からいうと、コード内で文字列を表現するには以下の 3 つの書き方があいます。

  • シングル(or ダブル)クオーテーションをつけたもの → 文字列のリテラル表現 → 『'target'』のような書き方

  • 変数名 → たとえば「target」は有効な変数名で、この変数に文字列が代入されていたらこれも文字列です。

  • 最終的に文字列として評価される式 → たとえば『'tar' + 'get'』は文字列の連結で、最終的に「'target`」となるのでこれも文字列です。

したがって単に「シングルクオーテーションがついてたら文字列、ついていなかったら文字列ではない」と判断してはいけない、ということがわかりますね。

ではここまでの話を踏まえて、冒頭の例を振り返ってみましょう。

どちらが正しい?

さて冒頭のコードを見てみましょう。まず最初の命令では、getElementById に 'target' という文字列のリテラル表現を渡しているので、構文として正しいといえます(文書内に id 属性が target である要素が存在していれば動きます)。

document.getElementById('target')

一方、次の表現はどうでしょうか。

document.getElementById(target)

ここで target にはシングルクオーテーションがついていないので、これは変数による表現であることがわかります。

そしてこの場合、この target という変数に何が代入されているのかが重要になります。文字列が代入されていれば良いのですが、よくあるケースとして、target という変数がそもそも定義されていないという場合もあります。その場合、target は文字列ではなくて undefined になってしまうのでエラーになってしまいます。

したがって 2 つめの命令においては「target にシングルクオーテーションがついていないからこれは文字列ではない、これは間違いではある」、ではなくて、「target という変数に文字列(か、最終的に文字列として評価される値)が代入されていたら OK、それ以外が代入されていたら(少なくとも構文的には)NG」と解釈すべきです。


少し長い道のりでしたが、JavaScript においては命令の構文を確認して、正しい値を使っていく必要があります。

「シングルクオーテーションをつけるの?つけないの?」ではなくて、上記のような考え方ができるようになっておくといいでしょう。

【長めのおまけ】 次の場合は?

さらに理解を深めるために、もう一つ例を出しておきましょう。次のような質問もよく受けたりします。

getElementById で動いていた命令を querySelector に変えたら動かなくなったのですが、なぜですか?

これはたとえば次のようなケースですね。

// 動く
document.getElementById('target').textContent = 'Hello';
// 動かない
document.querySelector('target').textContent = 'Hello';

まず、上で見た通り getElementById には文字列を渡す必要があって、 'target' という文字列のリテラル表現が渡されているので、1 つめの命令はOKですね。

一方、2 つめの命令については「querySelector も同じようなものでしょ?なぜ動かないの?」と思ってしまうかもしれません。しかしそう考えるのは早計で、これまで述べてきたように、まずは落ち着いて MDN で構文を確認するべきです。

では「querySelector mdn」で検索してみると…、以下のページがヒットしますね。

そして構文を調べると以下のように書かれています。

ここからわかるのは以下の 2 点です。

  • querySelector の括弧のなかに入る selectors は、文字列でないといけない。

  • その文字列は妥当な CSS セレクターでないといけない。

ではふりかえって 2 つめの命令を見てみましょう。

// 動かない
document.querySelector('target').textContent = 'Hello';

まずわかるのは、「querySelector の括弧には、シングルクオーテーションで囲われた文字列のリテラル表現を入れているので、文字列になっているのは間違いない」ということですね。

ただし、それが「妥当な CSS セレクターである」かはよく考えないといけません。もし target が妥当な CSS セレクターであるとしたら以下のような CSS を書くことになりますが….、これでは HTML に <target> という要素がなくてはいけません。

target {
  font-size: 14px;
}

そうではなくて、getElementById('target') が動いていたことを考えると、Id 属性が target である要素が存在していることが想定されます。その場合、それを指し示す、「妥当な CSS セレクター」は id 属性を示す # を使って「#target」とする必要がありますね。

以上をまとめると、getElementById は単に querySelector で置きかえればいい、というわけではなくて、仕様を確認したうえで、以下のように「妥当な CSS セレクターを表す文字列(今回だと '#target')」に書き換えないといけません。

// 動く
document.getElementById('target').textContent = 'Hello';
// 動かない
document.querySelector('target').textContent = 'Hello';
// これなら動く
document.querySelector('#target').textContent = 'Hello';

以上、JavaScriptでよく聞かれる質問を例に出しながら、「どうやって仕様を読み解いていくべきか?」について紹介してみました。

「え・・・そんなに面倒なことをしないといけないの?」と思ったかもしれませんが、慣れてくると自然にできるようになります。「エンジニアの人はこうやって確認していくのだな」というケーススタディの一例として、参考にしていただければと思います。



いいなと思ったら応援しよう!