- $()は関数ではあるが「DOM要素」を返していない
- $()の戻り値 ― jQueryオブジェクト
- 中身は配列に近い構造
- なぜわざわざラップしているのか
- $()はセレクタ関数ではない
- jQueryオブジェクトとDOMの違いで起きる問題
- なぜこの設計になったのか
- 現在との違い
- 注意点
- まとめ
$()は関数ではあるが「DOM要素」を返していない
jQueryを触り始めたとき、多くの人がこう思います。
「$('#menu')はmenu要素を取得している」
半分正しく、半分間違いです。
実際には、$()はDOM要素を返していません。
返しているのは「jQueryオブジェクト」です。
この違いを理解しないまま使うと、なぜか動かないコードや、意図しない挙動に悩まされます。
そしてここが、jQueryがただのショートカットではない理由でもあります。
$()の戻り値 ― jQueryオブジェクト
例えば次のコードです。
var el = $("#menu");
このelはHTML要素ではありません。
typeofを確認すると分かります。
console.log(typeof el);
結果は「object」です。
ではDOM要素でしょうか?
console.log(el instanceof HTMLElement);
falseになります。
つまり、$("#menu")はDOMノードではありません。
DOM要素を内部に保持したラッパーオブジェクトです。
中身は配列に近い構造
jQueryオブジェクトの内部は配列に似ています。
console.log(el[0]);
ここで初めてDOM要素が取得できます。
複数要素の場合も同じです。
var items = $(".item"); console.log(items.length); console.log(items[1]);
これは「一致したDOM要素の集合」を1つのオブジェクトとして扱っています。
つまりjQueryの本質は
DOMコレクション操作ライブラリです。
なぜわざわざラップしているのか
理由はメソッドチェーンです。
$("#menu") .addClass("open") .css("color", "red") .fadeIn();
これが成立するのは、各メソッドがDOMではなく
jQueryオブジェクト自身を返しているからです。
もしgetElementByIdが返るだけなら、こうなります。
var el = document.getElementById("menu"); el.classList.add("open"); el.style.color = "red";
1つずつ操作が必要になります。
jQueryは「対象要素の集合」を保持し続けることで、連続操作を可能にしました。
$()はセレクタ関数ではない
$()は単なるセレクタ関数だと思われがちですが、それも正確ではありません。
実は$()は入力によって挙動が変わります。
| 入力 | 動作 |
| 文字列(CSSセレクタ) | 要素検索 |
| HTML文字列 | 要素生成 |
| DOM要素 | ラップ |
| 関数 | ready登録 |
例です。
$("<div>"); // 要素生成 $(document.body); // DOMラップ $(function(){}); // ready
つまり$は「取得関数」ではなく、
統一エントリーポイントです。
jQueryオブジェクトとDOMの違いで起きる問題
ここが重要です。
次のコードはエラーになります。
$("#menu").innerHTML = "変更";
なぜかというと、innerHTMLはDOMのプロパティであり、jQueryオブジェクトには存在しないからです。
正しくはこうです。
$("#menu").html("変更");
逆に、DOMメソッドを使いたい場合はこうします。
$("#menu")[0].innerHTML = "変更";
この違いを理解していないと
「取得できているのに操作できない」という混乱が起きます。
なぜこの設計になったのか
jQueryが作られた当時、問題はブラウザ互換性でした。
- NodeListの扱いが違う
- 配列メソッドが使えない
- forEachが存在しない
そのため、DOM要素をそのまま返すとブラウザ差が露出してしまいます。
そこでjQueryはDOMをラップし、統一APIを提供しました。
つまりjQueryオブジェクトは
互換性レイヤーとして機能しています。
現在との違い
現在は次が使えます。
document.querySelectorAll(".item").forEach(el=>{ el.classList.add("open"); });
NodeListにもforEachがあり、classListも統一されました。
jQueryの必要性は小さくなりました。
ただし、jQueryのチェーン設計は多くのライブラリに影響を与えています。
Promiseの.then()や配列メソッドの連結なども思想的に近いものです。
注意点
jQueryとDOMを混在させるとバグの原因になります。
例えばイベントです。
document.getElementById("btn").addEventListener("click", handler); $("#btn").click(handler);
両方登録すると二重実行されます。
jQueryオブジェクトとDOMは似て非なるものです。
まとめ
$()は要素取得関数ではありません。
- jQueryオブジェクトを生成する
- DOM要素の集合を保持する
- 統一APIを提供する
つまりjQueryの本質は
DOMを操作するための抽象オブジェクトです。
そして$('#id')が短く書けることよりも、
「同じコードがどのブラウザでも同じように動く」ことこそが、$()の本当の価値でした。