jQuery ↔ JavaScript 完全対比リファレンス
ページ読み込みタイミングと初期化
読み込みタイミングの種類と使い分け
1. DOM構築完了時点(HTMLの解析完了、画像等は未完了)
// jQuery - 最もよく使われるパターン
$(function() {
console.log("DOM準備完了")
})
// jQuery - 同じ意味の書き方
$(document).ready(function() {
console.log("DOM準備完了")
})
// jQuery - アロー関数版
$(() => {
console.log("DOM準備完了")
})
// JavaScript - 標準的な方法
document.addEventListener("DOMContentLoaded", function() {
console.log("DOM準備完了")
})
// JavaScript - アロー関数版
document.addEventListener("DOMContentLoaded", () => {
console.log("DOM準備完了")
})
// JavaScript - 関数分離版
function initApp() {
console.log("DOM準備完了")
}
document.addEventListener("DOMContentLoaded", initApp)
2. 全リソース読み込み完了時点(画像、CSS、JSファイル等すべて完了)
// jQuery
$(window).on("load", function() {
console.log("全リソース読み込み完了")
})
// JavaScript
window.addEventListener("load", function() {
console.log("全リソース読み込み完了")
})
3. 即座実行(DOMの状態を問わず)
// jQuery - ページ読み込み前でも実行される
console.log("即座実行")
// JavaScript - 同じく即座実行
console.log("即座実行")
// JavaScript - DOMの状態を確認して分岐
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", initApp)
} else {
initApp() // すでに読み込み済みなら即座実行
}
4. 実用的な汎用関数(jQueryっぽい動作をJSで再現)
// JavaScript - jQueryのready()を再現
function ready(callback) {
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", callback)
} else {
callback()
}
}
// 使用例
ready(function() {
console.log("DOM準備完了またはすでに完了済み")
})
// さらに短縮版
const $ = callback => ready(callback)
$(function() {
console.log("jQueryっぽい書き方")
})
5. 読み込みタイミングの流れ
1. HTMLファイルのダウンロード開始
2. HTMLの解析開始 (document.readyState = "loading")
3. 外部CSS、JSファイルの読み込み開始
4. HTMLの解析完了 → DOMContentLoaded発火 ← ★ここで$(function(){})実行
5. 外部リソース(画像、CSS、JS)の読み込み完了
6. 全リソース完了 → load発火 ← ★ここで$(window).on("load")実行
🔍 要素の選択・取得
基本的な選択
// jQuery
$("#myId") // ID選択
$(".myClass") // クラス選択
$("div") // タグ選択
$("div.myClass") // タグ+クラス
$("#myId .child") // 子孫選択
$("#myId > .child") // 直接の子選択
$(".class1, .class2") // 複数選択
$("input[type='text']") // 属性選択
// JavaScript
document.getElementById("myId")
document.querySelector(".myClass")
document.querySelector("div")
document.querySelector("div.myClass")
document.querySelector("#myId .child")
document.querySelector("#myId > .child")
document.querySelectorAll(".class1, .class2")
document.querySelector("input[type='text']")
複数要素の選択
// jQuery
$(".myClass") // 全ての.myClassを取得
$("div") // 全てのdivを取得
// JavaScript
document.querySelectorAll(".myClass") // NodeList(推奨)
document.getElementsByClassName("myClass") // HTMLCollection
document.querySelectorAll("div")
document.getElementsByTagName("div")
高度な選択
// jQuery
$("div:first") // 最初のdiv
$("div:last") // 最後のdiv
$("div:eq(2)") // 3番目のdiv
$("div:not(.exclude)") // .excludeクラス以外
$("div:contains('テキスト')") // テキストを含む
// JavaScript
document.querySelector("div") // 最初のdiv
document.querySelector("div:last-child") // 最後の子div
document.querySelectorAll("div")[2] // 3番目のdiv
document.querySelector("div:not(.exclude)") // .excludeクラス以外
// containsはカスタム関数が必要
Array.from(document.querySelectorAll("div")).find(el =>
el.textContent.includes("テキスト"))
要素の関係性
// jQuery
$("#element").parent() // 親要素
$("#element").children() // 子要素
$("#element").siblings() // 兄弟要素
$("#element").next() // 次の兄弟
$("#element").prev() // 前の兄弟
$("#element").find(".class") // 子孫から検索
$("#element").closest(".parent") // 最も近い祖先
// JavaScript
const el = document.getElementById("element")
el.parentElement // 親要素
el.children // 子要素(HTMLCollection)
// 兄弟要素は配列操作が必要
Array.from(el.parentElement.children).filter(child => child !== el)
el.nextElementSibling // 次の兄弟
el.previousElementSibling // 前の兄弟
el.querySelectorAll(".class") // 子孫から検索
el.closest(".parent") // 最も近い祖先
📝 DOM操作
テキスト・HTML の取得・設定
// jQuery
$("#element").text() // テキスト取得
$("#element").text("新しいテキスト") // テキスト設定
$("#element").html() // HTML取得
$("#element").html("<b>太字</b>") // HTML設定
// JavaScript
const el = document.getElementById("element")
el.textContent // テキスト取得
el.textContent = "新しいテキスト" // テキスト設定
el.innerHTML // HTML取得
el.innerHTML = "<b>太字</b>" // HTML設定
// 安全なHTML挿入(XSS対策)
el.insertAdjacentHTML("afterbegin", "<b>太字</b>")
フォーム要素の値操作
// jQuery
$("#input").val() // 値取得
$("#input").val("新しい値") // 値設定
$("#select").val() // 選択値取得
$("#checkbox").prop("checked") // チェック状態
$("#checkbox").prop("checked", true) // チェック設定
// JavaScript
const input = document.getElementById("input")
input.value // 値取得
input.value = "新しい値" // 値設定
document.getElementById("select").value // 選択値取得
const checkbox = document.getElementById("checkbox")
checkbox.checked // チェック状態
checkbox.checked = true // チェック設定
属性の操作
// jQuery
$("#element").attr("href") // 属性取得
$("#element").attr("href", "/page") // 属性設定
$("#element").removeAttr("disabled") // 属性削除
$("#element").prop("disabled", true) // プロパティ設定
$("#element").data("id") // data属性取得
$("#element").data("id", "123") // data属性設定
// JavaScript
const el = document.getElementById("element")
el.getAttribute("href") // 属性取得
el.setAttribute("href", "/page") // 属性設定
el.removeAttribute("disabled") // 属性削除
el.disabled = true // プロパティ設定
el.dataset.id // data属性取得
el.dataset.id = "123" // data属性設定
CSS クラスの操作
// jQuery
$("#element").addClass("newClass") // クラス追加
$("#element").removeClass("oldClass") // クラス削除
$("#element").toggleClass("active") // クラス切り替え
$("#element").hasClass("active") // クラス存在確認
// JavaScript
const el = document.getElementById("element")
el.classList.add("newClass") // クラス追加
el.classList.remove("oldClass") // クラス削除
el.classList.toggle("active") // クラス切り替え
el.classList.contains("active") // クラス存在確認
// 複数クラス操作
el.classList.add("class1", "class2") // 複数追加
el.classList.remove("class1", "class2") // 複数削除
CSS スタイルの操作
// jQuery
$("#element").css("color") // スタイル取得
$("#element").css("color", "red") // スタイル設定
$("#element").css({ // 複数スタイル設定
"color": "red",
"font-size": "16px",
"margin": "10px"
})
// JavaScript
const el = document.getElementById("element")
getComputedStyle(el).color // 計算済みスタイル取得
el.style.color = "red" // スタイル設定
// 複数スタイル設定
Object.assign(el.style, {
color: "red",
fontSize: "16px",
margin: "10px"
})
// CSS変数の操作
el.style.setProperty("--main-color", "blue")
👁️ 表示・非表示・アニメーション
基本的な表示制御
// jQuery
$("#element").show() // 表示
$("#element").hide() // 非表示
$("#element").toggle() // 切り替え
$("#element").is(":visible") // 表示状態確認
// JavaScript
const el = document.getElementById("element")
el.style.display = "block" // 表示
el.style.display = "none" // 非表示
// 切り替え
el.style.display = el.style.display === "none" ? "block" : "none"
// 表示状態確認
getComputedStyle(el).display !== "none"
フェード効果(CSS Transition使用)
// jQuery
$("#element").fadeIn(500) // フェードイン
$("#element").fadeOut(500) // フェードアウト
$("#element").fadeTo(500, 0.5) // 透明度指定
// JavaScript - CSS Transitionを使った実装
const el = document.getElementById("element")
// CSS設定(初期化時に設定)
el.style.transition = "opacity 0.5s ease"
// フェードイン
function fadeIn(element) {
element.style.display = "block"
element.style.opacity = "0"
setTimeout(() => element.style.opacity = "1", 10)
}
// フェードアウト
function fadeOut(element) {
element.style.opacity = "0"
setTimeout(() => element.style.display = "none", 500)
}
// 透明度指定
function fadeTo(element, opacity) {
element.style.opacity = opacity
}
スライド効果
// jQuery
$("#element").slideDown(500) // スライドダウン
$("#element").slideUp(500) // スライドアップ
$("#element").slideToggle(500) // スライド切り替え
// JavaScript - CSS Transitionを使った実装
function slideDown(element, duration = 500) {
element.style.display = "block"
element.style.height = "0"
element.style.overflow = "hidden"
element.style.transition = `height ${duration}ms ease`
const height = element.scrollHeight + "px"
setTimeout(() => element.style.height = height, 10)
setTimeout(() => {
element.style.height = ""
element.style.overflow = ""
element.style.transition = ""
}, duration)
}
function slideUp(element, duration = 500) {
element.style.height = element.scrollHeight + "px"
element.style.overflow = "hidden"
element.style.transition = `height ${duration}ms ease`
setTimeout(() => element.style.height = "0", 10)
setTimeout(() => {
element.style.display = "none"
element.style.height = ""
element.style.overflow = ""
element.style.transition = ""
}, duration)
}
🎯 イベント処理
基本的なイベント
// jQuery
$("#button").click(function() {}) // クリック
$("#input").change(function() {}) // 値変更
$("#input").keyup(function() {}) // キー離し
$("#element").hover( // マウスホバー
function() { /* enter */ },
function() { /* leave */ }
)
// JavaScript
const button = document.getElementById("button")
button.addEventListener("click", function() {})
const input = document.getElementById("input")
input.addEventListener("change", function() {})
input.addEventListener("keyup", function() {})
const element = document.getElementById("element")
element.addEventListener("mouseenter", function() {})
element.addEventListener("mouseleave", function() {})
複数イベントの監視
// jQuery
$("#input").on("keyup change paste", function() {
// 複数のイベントで同じ処理
})
// JavaScript
const input = document.getElementById("input")
const events = ["keyup", "change", "paste"]
events.forEach(event => {
input.addEventListener(event, function() {
// 複数のイベントで同じ処理
})
})
// または
function handleInput() {
// 処理内容
}
input.addEventListener("keyup", handleInput)
input.addEventListener("change", handleInput)
input.addEventListener("paste", handleInput)
イベント委譲(動的要素対応)
// jQuery
$(document).on("click", ".dynamic-button", function() {
console.log("動的に追加されたボタンがクリックされた")
})
// JavaScript
document.addEventListener("click", function(e) {
if (e.target.matches(".dynamic-button")) {
console.log("動的に追加されたボタンがクリックされた")
}
})
// より具体的な委譲
document.addEventListener("click", function(e) {
const button = e.target.closest(".dynamic-button")
if (button) {
console.log("動的ボタンまたはその子要素がクリックされた")
}
})
カスタムイベント
// jQuery
$("#element").trigger("myEvent", {data: "test"})
$("#element").on("myEvent", function(e, data) {
console.log(data)
})
// JavaScript
const element = document.getElementById("element")
// カスタムイベント発火
const customEvent = new CustomEvent("myEvent", {
detail: {data: "test"}
})
element.dispatchEvent(customEvent)
// カスタムイベント監視
element.addEventListener("myEvent", function(e) {
console.log(e.detail.data)
})
イベントの削除
// jQuery
$("#element").off("click") // 全クリックイベント削除
$("#element").off("click", handler) // 特定ハンドラー削除
// JavaScript
const element = document.getElementById("element")
// 特定ハンドラー削除(参照を保持しておく必要がある)
element.removeEventListener("click", handler)
// 全イベント削除は新しい要素で置換
const newElement = element.cloneNode(true)
element.parentNode.replaceChild(newElement, element)
🏗️ DOM要素の作成・挿入・削除
要素の作成
// jQuery
$("<div>") // 空のdiv作成
$("<div>", { // 属性付きdiv作成
"class": "myClass",
"id": "myId",
"text": "Hello World"
})
// JavaScript
const div = document.createElement("div")
// 属性設定
div.className = "myClass"
div.id = "myId"
div.textContent = "Hello World"
// またはテンプレートリテラル使用
const template = `
<div class="myClass" id="myId">
Hello World
</div>
`
要素の挿入
// jQuery
$("#parent").append("<div>末尾に追加</div>")
$("#parent").prepend("<div>先頭に追加</div>")
$("#element").after("<div>後ろに挿入</div>")
$("#element").before("<div>前に挿入</div>")
// JavaScript
const parent = document.getElementById("parent")
const element = document.getElementById("element")
// HTML文字列での挿入
parent.insertAdjacentHTML("beforeend", "<div>末尾に追加</div>")
parent.insertAdjacentHTML("afterbegin", "<div>先頭に追加</div>")
element.insertAdjacentHTML("afterend", "<div>後ろに挿入</div>")
element.insertAdjacentHTML("beforebegin", "<div>前に挿入</div>")
// 要素オブジェクトでの挿入
const newDiv = document.createElement("div")
newDiv.textContent = "新しい要素"
parent.appendChild(newDiv) // 末尾に追加
parent.insertBefore(newDiv, parent.firstChild) // 先頭に追加
要素の削除・置換
// jQuery
$("#element").remove() // 要素削除
$("#element").empty() // 中身削除
$("#element").replaceWith("<div>新要素</div>")
// JavaScript
const element = document.getElementById("element")
element.remove() // 要素削除
element.innerHTML = "" // 中身削除
element.outerHTML = "<div>新要素</div>" // 要素置換
🔄 ループ処理
each ループ
// jQuery
$(".items").each(function(index, element) {
$(this).text("アイテム " + index)
console.log(element)
})
// JavaScript
const items = document.querySelectorAll(".items")
items.forEach(function(element, index) {
element.textContent = "アイテム " + index
console.log(element)
})
// for文版
for (let i = 0; i < items.length; i++) {
items[i].textContent = "アイテム " + i
}
// for...of文版
for (const [index, element] of items.entries()) {
element.textContent = "アイテム " + index
}
配列・オブジェクトのループ
// jQuery
$.each(["a", "b", "c"], function(index, value) {
console.log(index, value)
})
// JavaScript
["a", "b", "c"].forEach(function(value, index) {
console.log(index, value)
})
// オブジェクトのループ
const obj = {a: 1, b: 2, c: 3}
Object.entries(obj).forEach(([key, value]) => {
console.log(key, value)
})
🌐 Ajax(非同期通信)
GET リクエスト
// jQuery
$.get("/api/data")
.done(function(data) {
console.log("成功:", data)
})
.fail(function(xhr, status, error) {
console.log("エラー:", error)
})
// JavaScript (Fetch API)
fetch("/api/data")
.then(response => {
if (!response.ok) {
throw new Error("Network response was not ok")
}
return response.json()
})
.then(data => console.log("成功:", data))
.catch(error => console.log("エラー:", error))
// async/await版
async function fetchData() {
try {
const response = await fetch("/api/data")
if (!response.ok) throw new Error("Network error")
const data = await response.json()
console.log("成功:", data)
} catch (error) {
console.log("エラー:", error)
}
}
POST リクエスト
// jQuery
$.post("/api/data", {
name: "太郎",
email: "taro@example.com"
})
.done(function(data) {
console.log("送信成功:", data)
})
// JavaScript (Fetch API)
fetch("/api/data", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
name: "太郎",
email: "taro@example.com"
})
})
.then(response => response.json())
.then(data => console.log("送信成功:", data))
.catch(error => console.log("エラー:", error))
フォームデータの送信
// jQuery
$("#form").serialize() // URLエンコード形式
$("#form").serializeArray() // 配列形式
// JavaScript
const form = document.getElementById("form")
const formData = new FormData(form) // FormDataオブジェクト
// URLエンコード形式に変換
const params = new URLSearchParams(formData)
console.log(params.toString())
// オブジェクト形式に変換
const data = {}
for (let [key, value] of formData.entries()) {
data[key] = value
}
// Fetchで送信
fetch("/api/submit", {
method: "POST",
body: formData // FormDataをそのまま送信
})
📐 要素のサイズ・位置
サイズ情報
// jQuery
$("#element").width() // 幅(コンテンツのみ)
$("#element").height() // 高さ(コンテンツのみ)
$("#element").innerWidth() // 幅(パディング含む)
$("#element").outerWidth() // 幅(ボーダー含む)
$("#element").outerWidth(true) // 幅(マージン含む)
// JavaScript
const el = document.getElementById("element")
const rect = el.getBoundingClientRect()
const style = getComputedStyle(el)
el.clientWidth // 幅(パディング含む)
el.clientHeight // 高さ(パディング含む)
el.offsetWidth // 幅(ボーダー含む)
el.offsetHeight // 高さ(ボーダー含む)
rect.width // 幅(ボーダー含む、小数点あり)
rect.height // 高さ(ボーダー含む、小数点あり)
// コンテンツのみの幅(jQueryのwidth()相当)
el.clientWidth - parseFloat(style.paddingLeft) - parseFloat(style.paddingRight)
位置情報
// jQuery
$("#element").offset() // ドキュメントからの位置
$("#element").position() // 親要素からの位置
// JavaScript
const el = document.getElementById("element")
const rect = el.getBoundingClientRect()
// ドキュメントからの位置(offset相当)
const offset = {
top: rect.top + window.scrollY,
left: rect.left + window.scrollX
}
// 親要素からの位置(position相当)
const position = {
top: el.offsetTop,
left: el.offsetLeft
}
// ビューポートからの位置
const viewport = {
top: rect.top,
left: rect.left
}
スクロール情報
// jQuery
$(window).scrollTop() // スクロール位置取得
$(window).scrollTop(100) // スクロール位置設定
$("#element").scrollTop() // 要素内スクロール
// JavaScript
window.scrollY // スクロール位置取得
window.scrollTo(0, 100) // スクロール位置設定
window.scrollTo({ // スムーススクロール
top: 100,
behavior: "smooth"
})
const el = document.getElementById("element")
el.scrollTop // 要素内スクロール取得
el.scrollTop = 100 // 要素内スクロール設定
📋 フォーム操作
フォーム値の取得・設定
// jQuery
$("#text").val() // テキスト値
$("#select").val() // 選択値
$("#radio:checked").val() // 選択されたラジオボタン
$("#checkbox:checked").map(function() { // チェックされたチェックボックス
return $(this).val()
}).get()
// JavaScript
document.getElementById("text").value
document.getElementById("select").value
document.querySelector("input[name='radio']:checked")?.value
Array.from(document.querySelectorAll("input[name='checkbox']:checked"))
.map(input => input.value)
フォームバリデーション
// jQuery
$("#email").val().includes("@") // メール形式チェック
$("#required").val() !== "" // 必須チェック
// JavaScript
const email = document.getElementById("email").value
email.includes("@") && email.includes(".")
document.getElementById("required").value.trim() !== ""
// HTML5バリデーション
document.getElementById("email").checkValidity()
document.getElementById("form").checkValidity()
🎨 便利なユーティリティ
文字列操作
// jQuery
$.trim(" 文字列 ") // 前後空白削除
// JavaScript
" 文字列 ".trim() // 前後空白削除
" 文字列 ".trimStart() // 前空白削除
" 文字列 ".trimEnd() // 後空白削除
数値・型判定
// jQuery
$.isNumeric("123") // 数値判定
$.isArray([1, 2, 3]) // 配列判定
$.isEmptyObject({}) // 空オブジェクト判定
// JavaScript
!isNaN(parseFloat("123")) && isFinite("123") // 数値判定
Array.isArray([1, 2, 3]) // 配列判定
Object.keys({}).length === 0 // 空オブジェクト判定
オブジェクト操作
// jQuery
$.extend({}, obj1, obj2) // オブジェクト結合
$.extend(true, {}, obj1, obj2) // ディープコピー結合
// JavaScript
Object.assign({}, obj1, obj2) // オブジェクト結合
{...obj1, ...obj2} // スプレッド構文版
JSON.parse(JSON.stringify(obj)) // ディープコピー(単純な場合)
structuredClone(obj) // ディープコピー(モダン)
配列操作
// jQuery
$.map([1, 2, 3], function(item) { // マップ
return item * 2
})
$.grep([1, 2, 3, 4], function(item) { // フィルター
return item > 2
})
// JavaScript
[1, 2, 3].map(item => item * 2) // マップ
[1, 2, 3, 4].filter(item => item > 2) // フィルター
[1, 2, 3].reduce((sum, item) => sum + item, 0) // リデュース
[1, 2, 3].find(item => item > 2) // 検索
[1, 2, 3].includes(2) // 含有チェック
💡 実用的なパターン集
アコーディオン
// jQuery
$(".accordion-header").click(function() {
$(this).next(".accordion-content").slideToggle()
$(this).toggleClass("active")
})
// JavaScript
document.querySelectorAll(".accordion-header").forEach(header => {
header.addEventListener("click", function() {
const content = this.nextElementSibling
const isVisible = content.style.display !== "none"
content.style.display = isVisible ? "none" : "block"
this.classList.toggle("active")
})
})
タブ切り替え
// jQuery
$(".tab-button").click(function() {
const target = $(this).data("target")
$(".tab-button").removeClass("active")
$(".tab-content").removeClass("active")
$(this).addClass("active")
$("#" + target).addClass("active")
})
// JavaScript
document.querySelectorAll(".tab-button").forEach(button => {
button.addEventListener("click", function() {
const target = this.dataset.target
// 全てのタブボタンとコンテンツからactiveクラスを削除
document.querySelectorAll(".tab-button").forEach(btn =>
btn.classList.remove("active"))
document.querySelectorAll(".tab-content").forEach(content =>
content.classList.remove("active"))
// クリックされたタブボタンと対応するコンテンツにactiveクラスを追加
this.classList.add("active")
document.getElementById(target).classList.add("active")
})
})
モーダルウィンドウ
// jQuery
$(".modal-trigger").click(function() {
const modalId = $(this).data("modal")
$("#" + modalId).fadeIn()
})
$(".modal-close, .modal-overlay").click(function() {
$(this).closest(".modal").fadeOut()
})
// JavaScript
document.querySelectorAll(".modal-trigger").forEach(trigger => {
trigger.addEventListener("click", function() {
const modalId = this.dataset.modal
const modal = document.getElementById(modalId)
modal.style.display = "flex"
// フェードイン効果
modal.style.opacity = "0"
setTimeout(() => modal.style.opacity = "1", 10)
})
})
document.querySelectorAll(".modal-close, .modal-overlay").forEach(closeElement => {
closeElement.addEventListener("click", function() {
const modal = this.closest(".modal")
modal.style.opacity = "0"
setTimeout(() => modal.style.display = "none", 300)
})
})
// Escキーでモーダルを閉じる
document.addEventListener("keydown", function(e) {
if (e.key === "Escape") {
const openModal = document.querySelector(".modal[style*='flex']")
if (openModal) {
openModal.style.display = "none"
}
}
})
ドロップダウンメニュー
// jQuery
$(".dropdown-toggle").click(function(e) {
e.stopPropagation()
$(this).next(".dropdown-menu").toggle()
})
$(document).click(function() {
$(".dropdown-menu").hide()
})
// JavaScript
document.querySelectorAll(".dropdown-toggle").forEach(toggle => {
toggle.addEventListener("click", function(e) {
e.stopPropagation()
const menu = this.nextElementSibling
// 他のドロップダウンを閉じる
document.querySelectorAll(".dropdown-menu").forEach(otherMenu => {
if (otherMenu !== menu) {
otherMenu.style.display = "none"
}
})
// クリックされたドロップダウンを切り替え
menu.style.display = menu.style.display === "block" ? "none" : "block"
})
})
document.addEventListener("click", function() {
document.querySelectorAll(".dropdown-menu").forEach(menu => {
menu.style.display = "none"
})
})
無限スクロール
// jQuery
$(window).scroll(function() {
if ($(window).scrollTop() + $(window).height() >= $(document).height() - 100) {
loadMoreContent()
}
})
// JavaScript
let isLoading = false
window.addEventListener("scroll", function() {
if (isLoading) return
const scrollTop = window.scrollY
const windowHeight = window.innerHeight
const documentHeight = document.documentElement.scrollHeight
if (scrollTop + windowHeight >= documentHeight - 100) {
isLoading = true
loadMoreContent().then(() => {
isLoading = false
})
}
})
// Intersection Observer API を使った効率的な方法
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting && !isLoading) {
isLoading = true
loadMoreContent().then(() => {
isLoading = false
})
}
})
})
// 監視対象要素(ページ底部に配置)
const loadTrigger = document.getElementById("load-trigger")
observer.observe(loadTrigger)
画像の遅延読み込み(Lazy Loading)
// jQuery
$(window).scroll(function() {
$("img[data-src]").each(function() {
const $img = $(this)
if ($(window).scrollTop() + $(window).height() > $img.offset().top) {
$img.attr("src", $img.data("src")).removeAttr("data-src")
}
})
})
// JavaScript - Intersection Observer API使用(推奨)
const imageObserver = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const img = entry.target
img.src = img.dataset.src
img.removeAttribute("data-src")
imageObserver.unobserve(img)
}
})
})
document.querySelectorAll("img[data-src]").forEach(img => {
imageObserver.observe(img)
})
スムーススクロール
// jQuery
$("a[href^='#']").click(function(e) {
e.preventDefault()
const target = $($(this).attr("href"))
$("html, body").animate({
scrollTop: target.offset().top
}, 500)
})
// JavaScript
document.querySelectorAll("a[href^='#']").forEach(link => {
link.addEventListener("click", function(e) {
e.preventDefault()
const targetId = this.getAttribute("href")
const target = document.querySelector(targetId)
if (target) {
target.scrollIntoView({
behavior: "smooth",
block: "start"
})
}
})
})
// より細かい制御が必要な場合
function smoothScrollTo(element, duration = 500) {
const targetPosition = element.offsetTop
const startPosition = window.scrollY
const distance = targetPosition - startPosition
let startTime = null
function animation(currentTime) {
if (startTime === null) startTime = currentTime
const timeElapsed = currentTime - startTime
const run = easeInOutQuad(timeElapsed, startPosition, distance, duration)
window.scrollTo(0, run)
if (timeElapsed < duration) {
requestAnimationFrame(animation)
}
}
// イージング関数
function easeInOutQuad(t, b, c, d) {
t /= d / 2
if (t < 1) return c / 2 * t * t + b
t--
return -c / 2 * (t * (t - 2) - 1) + b
}
requestAnimationFrame(animation)
}
🔧 実用的なヘルパー関数
jQueryライクなヘルパー関数
// 簡易的な$関数を作成
function $(selector) {
if (typeof selector === "function") {
// $(function() {}) のパターン
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", selector)
} else {
selector()
}
return
}
// 要素選択のパターン
return document.querySelector(selector)
}
// 複数要素選択
function $(selector) {
return document.querySelectorAll(selector)
}
// 使用例
$(function() {
console.log("DOM準備完了")
})
const element = $("#myId")
const elements = $(".myClass")
よく使う処理をまとめたユーティリティ
const Utils = {
// 要素の表示/非表示
show: (element) => element.style.display = "block",
hide: (element) => element.style.display = "none",
toggle: (element) => {
element.style.display = element.style.display === "none" ? "block" : "none"
},
// クラス操作
addClass: (element, className) => element.classList.add(className),
removeClass: (element, className) => element.classList.remove(className),
toggleClass: (element, className) => element.classList.toggle(className),
hasClass: (element, className) => element.classList.contains(className),
// 配列化
toArray: (nodeList) => Array.from(nodeList),
// 要素作成
createElement: (tag, options = {}) => {
const element = document.createElement(tag)
Object.entries(options).forEach(([key, value]) => {
if (key === "text") {
element.textContent = value
} else if (key === "html") {
element.innerHTML = value
} else if (key === "class") {
element.className = value
} else {
element.setAttribute(key, value)
}
})
return element
},
// 簡易Ajax
get: async (url) => {
const response = await fetch(url)
if (!response.ok) throw new Error("Network error")
return response.json()
},
post: async (url, data) => {
const response = await fetch(url, {
method: "POST",
headers: {"Content-Type": "application/json"},
body: JSON.stringify(data)
})
if (!response.ok) throw new Error("Network error")
return response.json()
}
}
// 使用例
const element = document.getElementById("myElement")
Utils.show(element)
Utils.addClass(element, "active")
const newDiv = Utils.createElement("div", {
class: "my-class",
id: "my-id",
text: "Hello World"
})
⚠️ 移行時の注意点とベストプラクティス
1. エラー対策
// jQuery - 要素が存在しなくてもエラーにならない
$("#nonexistent").hide()
// JavaScript - 要素の存在確認が必要
const element = document.getElementById("nonexistent")
if (element) {
element.style.display = "none"
}
// Optional Chaining(ES2020以降)
document.getElementById("nonexistent")?.style.setProperty("display", "none")
2. NodeListとHTMLCollectionの違い
// NodeList(querySelectorAllで取得)- forEachが使える
const nodeList = document.querySelectorAll(".class")
nodeList.forEach(element => {
console.log(element)
})
// HTMLCollection(getElementsで取得)- 配列変換が必要
const htmlCollection = document.getElementsByClassName("class")
Array.from(htmlCollection).forEach(element => {
console.log(element)
})
3. イベントリスナーのメモリリーク対策
// 悪い例 - 匿名関数では削除できない
element.addEventListener("click", function() {
console.log("クリック")
})
// 良い例 - 関数に名前をつけて削除可能にする
function handleClick() {
console.log("クリック")
}
element.addEventListener("click", handleClick)
// 必要に応じて削除
element.removeEventListener("click", handleClick)
4. パフォーマンス最適化
// 悪い例 - DOMを何度も検索
for (let i = 0; i < 100; i++) {
document.getElementById("element").textContent = i
}
// 良い例 - 一度だけ検索して変数に保存
const element = document.getElementById("element")
for (let i = 0; i < 100; i++) {
element.textContent = i
}
5. ブラウザ対応
// モダンブラウザのみ対応
element.remove()
element.closest(".parent")
Array.from(nodeList)
// IE対応が必要な場合
element.parentNode.removeChild(element)
// polyfillの使用を検討
// またはbabelでトランスパイル
📚 学習リソース
段階的な学習アプローチ
-
基本的な要素選択から始める -
getElementById,querySelector -
イベント処理を覚える -
addEventListener -
DOM操作をマスターする -
createElement,appendChild -
Ajax通信を学ぶ -
fetch API -
モダンJSの機能を活用 -
async/await, アロー関数, テンプレートリテラル
実践的な練習方法
- 既存のjQueryコードを1つずつバニラJSに変換
- 小さなコンポーネント(アコーディオン、タブ等)を作成
- エラーハンドリングを必ず含める
-
console.logでデバッグしながら理解を深める
追加
| メソッド | 戻り値 | 注意点 |
|---|---|---|
parentNode |
Node(要素以外も含む) | テキストノード、コメント等も返す可能性 |
parentElement |
Element(要素のみ) | HTMLElement のみ返す(安全) |
closest() |
Element(条件にマッチする祖先) | セレクタで条件指定可能(最も便利) |
// 元のjQuery
id = $(this).parents("[id]").attr("id");
// 1. parentNode版(非推奨)
let parent = this.parentNode;
while (parent && parent.nodeType === 1) {
if (parent.id) {
id = parent.id;
break;
}
parent = parent.parentNode;
}
// 2. parentElement版(まあまあ)
let parent = this.parentElement;
while (parent) {
if (parent.id) {
id = parent.id;
break;
}
parent = parent.parentElement;
}
// 3. closest版(推奨)
id = this.closest("[id]").id;