Old-School Front-End / 2026 ・ No.14

いにしえのフロントエンド入門

第14回 jQuery ── 同じ画面を「$」で書き直して、並べて比べる

公開

2つの申請フォームを左右に並べたもの。左は素の JavaScript の form.html、右は jQuery 4.0.0 の form-jq.html。どちらも件名ニューヨーク出張(10月13日〜16日)、明細3行(成田エクスプレス 3070 円、ホテル1泊 189.50 ドル、会議の参加費 100 ドル)、合計 46,851 円、「合計が3万円以上なので、領収書の添付が必要です。」、ドルは 1ドル = 151.23円 で換算、と同じ表示
今回のゴール。左が第8〜10回の素の JavaScript、右が jQuery で書き直した版。見た目も動きも同じ(筆者のデモページを、練習用のサーバー経由でクラウド上の Chromium で撮影。Playwright で実際に入力・クリックしたところ。2026年10月19日撮影、ページの時計は 2026年10月17日 15:00 に固定。アカウントはデモ専用の架空のもの。ブラウザの枠は説明のために描き足したもの)

AI に頼まず、一行ずつ手で書く「いにしえの」フロントエンド入門。第14回は jQuery です。
第8〜10回で手で書いた申請フォームの JavaScript を、jQuery 4.0.0 でそっくり書き直します。
そして、2つの版を同じ手順で動かし、本当に同じ動きになるかを確かめます。
書き直すと分かるのは、jQuery の便利さと、素の JavaScript がどれだけ追いついたか、そして踏みやすい罠です。

一

今回のゴール

古井今日は jQuery だ。わしが若いころ、ウェブの画面は全部これで書いた。

新井ドルマークだらけのやつですね。古いサイトの保守で見たことあります。読めませんでした。

古井読めないと困る。世の中のサイトの6割以上が、まだ使っているからな。今日は第8〜10回の申請フォームを、jQuery でそっくり書き直す。

新井動いているものを、わざわざ書き直すんですか。

古井同じものを2通りで書くと、どっちの良さも悪さもよく見える。翻訳の練習みたいなものだ。

いまここ:第14回

1 準備 2 HTML の骨組み 3 フォーム 4 CSS の基本 5 レイアウト 6 Bootstrap 7 JS の基本 8 DOM・イベント 9 入力チェック 10 通信 11 ログイン 12 承認の流れ 13 集計と印刷 14 jQuery 15 仕上げ いまここ 準備 HTML CSS JavaScript 実戦 仕上げ
  • $ が返すものを知る ── 要素そのものではなく「入れ物」。読むのは最初の1つ、書くのは全部
  • 書き直す ── 行の追加・削除、入力チェックのまとめ、サーバーとのやりとり。計算(app.js)とチェック(validate.js)はそのまま使う
  • 同じ動きか確かめる ── 2つの版を同じ手順で操作して、画面の様子を記録して比べる
  • 罠を試す ── 書き直しでつまずいたところを、試すページにまとめて実際に動かす

使うのは jQuery 4.0.0 です。2026年1月17日に出た、約10年ぶりの大きな版です。比べるために、ひとつ前の 3.7.1 も試します。

二

$ が返すもの

jQuery の中心は、$ という名前の関数です。CSS のセレクタを渡すと、見つかった要素を入れ物に入れて返します。この入れ物には、要素をまとめて扱うメソッドがたくさん付いています。

$() が返すのは、要素を入れた入れ物

$('[name="amount"]') jQuery の入れ物 [0] <input value="3070"> [1] <input value="189.50"> [2] <input value="100"> length: 3 .val() → "3070" 読むのは最初の1つだけ .addClass('x') → 3つとも 書くときは全部に効く [0] → <input> 中のふつうの要素 .textContent → undefined 入れ物は要素ではない $('#nothing') 空の入れ物(length: 0) .text('x') 黙って何もしない 読むメソッドは最初の1つ、書くメソッドは全部(暗黙の繰り返し) 見つからなくても黙っている。打ち間違いに気づきにくい
# lab.html で実際に動かした結果(Chromium、jQuery 4.0.0)
# 試したこと 結果
1 $('#total') に textContent を聞く undefined
2 $('#total')[0] にすると 46,851
3 $('[name="amount"]').val()(3つある) "3070"
4 map(…).get() で全部 ["3070","189.50","100"]
5 無い要素に $('#nothing').text('x') エラーなし(length = 0)
6 無い要素に querySelector('#nothing').textContent = 'x' TypeError: Cannot set properties of null (setting 'textContent')
  • 入れ物は要素ではないので、textContent を聞いても undefined。中の要素は [0] で取り出す
  • .val() のように「読む」メソッドは、最初の1つしか読まない。全部ほしいときは map(…).get()
  • 反対に .addClass() のように「書く」メソッドは、入っている要素の全部に効く(暗黙の繰り返し)。for を書かなくていいのが、jQuery の気持ちよさ
  • 見つからなくても、空の入れ物が返るだけでエラーにならない。素の JavaScript なら null にぶつかって止まるところを、jQuery は黙って何もしない。セレクタの打ち間違いに気づきにくい

そこで、入れ物を入れる変数には頭に $ を付けて($tbody など)、ふつうの要素と見分けられるようにします。昔からの習慣です。

三

読み込む

Bootstrap(第6回)と同じく、ファイルを vendor/jquery/ に置いて読み込みます。jQuery を使う form-jq.js より先に読み込むのが決まりです。どれも defer なので、書いた順に動きます。

<script src="vendor/jquery/jquery.min.js" defer></script>
<script src="js/app.js" defer></script>
<script src="js/auth.js" defer></script>
<script src="js/validate.js" defer></script>
<script src="js/form-jq.js" defer></script>

大きさを比べました。

# 大きさ(バイト。gzip は圧縮したときの目安)
ファイル バイト gzip 行(コメントと空行を除く)
form.js(素の JS)  10,398  4,096  185
form-jq.js(jQuery)   8,830  3,732  168
jquery.min.js 4.0.0  78,748 27,519 
jquery.slim.min.js 4.0.0  56,032 19,424 
jquery.min.js 3.7.1  87,533 30,336 
(参考)bootstrap.bundle.min.js  80,496 23,743 

書き直した form-jq.js は、元の form.js より1割ほど短くなりました。ただし、そのために約 79KB(圧縮して約 27KB)の jquery.min.js を毎回読み込みます。Bootstrap の JavaScript と同じくらいの重さです。slim 版は小さいですが、通信($.ajax)が入っていません(八で確かめます)。今回は通信を書き直すので、ふつうの版を使います。

四

行の追加・削除を書き直す

まず第8回の、明細の行の番号を振り直す関数です。上が素の JavaScript、下が jQuery 版です。

/** 行番号に合わせて、読み上げ用の名前を付け直す */
function renumber() {
  [...tbody.rows].forEach((row, i) => {
    const n = i + 1;
    for (const field of row.querySelectorAll('[data-label]')) {
      const label = field.dataset.label;
      field.id = `${field.name}-${n}`; // まとめのリンク用の id(第9回)
      field.setAttribute('aria-label', `${n}行目の${label}`);
    }
    row.querySelector('[data-action="remove"]').setAttribute('aria-label', `${n}行目を削除`);
  });
  addButton.disabled = tbody.rows.length >= MAX_ROWS; // 10行になったら追加できなくする
}
/** 行番号に合わせて、読み上げ用の名前を付け直す */
function renumber() {
  const $rows = $tbody.children('tr');
  $rows.each(function (i) { // each の中の this は、その行(ふつうの DOM の要素)
    const n = i + 1;
    $(this).find('[data-label]').each(function () {
      $(this).attr({ id: `${this.name}-${n}`, 'aria-label': `${n}行目の${$(this).data('label')}` });
    });
    $(this).find('[data-action="remove"]').attr('aria-label', `${n}行目を削除`);
  });
  $addButton.prop('disabled', $rows.length >= MAX_ROWS); // disabled のような「状態」は prop、HTML に書く「属性」は attr
}
  • for…of の代わりに .each(function () {…})。中の this は、その回の要素(入れ物ではない、ふつうの要素)
  • 属性は .attr()、disabled や checked のような「いまの状態」は .prop()。.attr() にはオブジェクトでまとめて渡せる

次はイベントの委任(第8回)です。ここは jQuery がいちばん得意なところです。

// 入力のたびに合計を計算し直す(後から足した行にも効くよう、tbody で受ける)
tbody.addEventListener('input', (event) => {
  const name = event.target.name;
  if (name === 'amount' || name === 'currency') updateTotal();
});

// 「削除」ボタン(これも tbody で受ける)
tbody.addEventListener('click', (event) => {
  const button = event.target.closest('[data-action="remove"]');
  if (button) removeRow(button.closest('tr'));
});

addButton.addEventListener('click', () => addRow());
// イベントの委任(第8回)は、on の2番目に「どの子で起きたら」を書くだけ
$tbody.on('input', '[name="amount"], [name="currency"]', updateTotal);
$tbody.on('click', '[data-action="remove"]', function () {
  removeRow($(this).closest('tr'));
});
$addButton.on('click', () => addRow());

.on() の2番目に「どの子で起きたら」をセレクタで書くと、closest で探す手間を jQuery が引き受けてくれます。そのとき this は、押されたボタンそのものになります。ただし、これは function で書いたときだけです。

# lab.html で実際に動かした結果(Chromium、jQuery 4.0.0)
# 試したこと 結果
13 on の中のアロー関数の this window
14 on の中の function の this <button id="lab-btn">

アロー関数は自分の this を持たないので、外側(ここでは window)になります。jQuery の this を使うところは function、使わないところはアロー関数、と使い分けます。

五

まとめの表示を書き直す

第9回の、エラーのまとめを出す関数です。要素を作って中身を入れる、という仕事が多いところです。

/** チェックの結果を画面に出す(赤い枠と、上のまとめ) */
function showErrors(errors) {
  for (const field of form.querySelectorAll('.is-invalid')) {
    field.classList.remove('is-invalid');
    field.removeAttribute('aria-invalid');
  }
  const items = errors.map(({ field, message }) => {
    const el = document.getElementById(field);
    el.classList.add('is-invalid');
    el.setAttribute('aria-invalid', 'true');
    const a = document.createElement('a');
    a.href = '#' + field;
    a.className = 'alert-link';
    a.textContent = message; // 文言は textContent で(第8回)
    const li = document.createElement('li');
    li.append(a);
    return li;
  });
  summary.querySelector('ul').replaceChildren(...items);
  summary.querySelector('h2').textContent = `入力内容を確認してください(${errors.length}件)`;
  summary.hidden = errors.length === 0;
}
/** チェックの結果を画面に出す(赤い枠と、上のまとめ) */
function showErrors(errors) {
  $form.find('.is-invalid').removeClass('is-invalid').removeAttr('aria-invalid');
  const items = errors.map(({ field, message }) => {
    $(document.getElementById(field)).addClass('is-invalid').attr('aria-invalid', 'true'); // id に記号が入っていても困らないよう、要素は getElementById で探して包む
    return $('<li>').append($('<a>', { href: '#' + field, class: 'alert-link', text: message })); // text: で渡すと textContent と同じ(第8回。html: にすると XSS の入り口)
  });
  $summary.find('ul').empty().append(items);
  $summary.find('h2').text(`入力内容を確認してください(${errors.length}件)`);
  $summary.prop('hidden', errors.length === 0);
}

$('<a>', { … }) のように、タグと属性をまとめて渡すと、要素が1行で作れます。.removeClass().removeAttr() のように、メソッドをつなげて書けるのも jQuery らしさです(メソッドチェーン)。

文字を入れるところには注意がいります。第8回で、innerHTML ではなく textContent を使う理由を見ました。jQuery では .html() が innerHTML、.text() が textContent にあたります。

# lab.html で実際に動かした結果(Chromium、jQuery 4.0.0)
# 試したこと 結果
19 .html(文字) にスクリプト入りの img 実行された
20 .text(文字) に同じもの 実行されない(文字として表示)

.html() に入れた img の onerror は、本当に動きました。人が書いた文字は .text()(または text:)で入れます。古い jQuery のコードには .html() で文字をつなげて入れている所がよくあるので、読むときの要注意ポイントです。

六

通信を書き直す

第10回の、申請をサーバーへ送る関数です。fetch を $.ajax に置き換えます。

/** 申請をサーバーへ送る */
async function send(data, button) {
  setSending(true, button);
  try {
    const url = form.getAttribute('action'); // form.action だと name="action" のボタンが返ってくる(実測)
    const res = await fetch(url, { method: 'POST', body: data, signal: AbortSignal.timeout(15000) }); // 15秒で諦める
    if (res.status === 401) { // ログインが切れていた(第11回)
      showResult('danger', 'ログインの有効期限が切れました。もう一度ログインしてください(入力した内容は、この画面に残っています)。');
      return;
    }
    if (res.status === 400) { // サーバーのチェックに引っかかった(第9回と同じ形で返ってくる)
      const body = await res.json();
      showErrors(body.errors);
      summary.focus();
      return; // return しても finally は動く
    }
    if (!res.ok) throw new Error(`HTTP ${res.status}`);
    const body = await res.json();
    showResult('success', body.draft ? `下書きを保存しました(${body.id})。` : `申請を受け付けました。申請番号は ${body.id} です。`);
  } catch (error) {
    showResult('danger', '送信できませんでした。通信の状態を確かめて、もう一度押してください。入力した内容は消えていません。');
  } finally {
    setSending(false, button); // うまくいっても、失敗しても、ボタンを元に戻す
  }
}
/** 申請をサーバーへ送る */
async function send(data, button) {
  setSending(true, button);
  try {
    const body = await $.ajax({
      url: $form.attr('action'), // attr は属性を読むので、name="action" のボタンに邪魔されない(第10回の罠)
      method: 'POST',
      data, // FormData は 4.0 ならそのまま渡せる(3.x では processData: false と contentType: false が要る。六で実測)
      dataType: 'json',
      timeout: 15000,
    });
    showResult('success', body.draft ? `下書きを保存しました(${body.id})。` : `申請を受け付けました。申請番号は ${body.id} です。`);
  } catch (xhr) { // 400 や 401 も、ここに来る
    if (xhr.status === 401) {
      showResult('danger', 'ログインの有効期限が切れました。もう一度ログインしてください(入力した内容は、この画面に残っています)。');
      return;
    }
    if (xhr.status === 400) {
      showErrors(xhr.responseJSON.errors);
      $summary.trigger('focus');
      return;
    }
    showResult('danger', '送信できませんでした。通信の状態を確かめて、もう一度押してください。入力した内容は消えていません。');
  } finally {
    setSending(false, button);
  }
}

いちばん大きな違いは、400 や 401 がどこへ行くかです。

fetch は「返事が来たか」、$.ajax は「うまくいったか」で分ける

fetch $.ajax 200 / 201 うまくいった then then 400 入力がおかしい then catch 401 / 403 ログイン・権限 then catch 500 サーバーの故障 then catch 通信の失敗 切断・時間切れ catch catch fetch は「返事が来たか」、$.ajax は「うまくいったか」で分ける 書き直すときは、400 や 401 の処理を then 側から catch 側へ移す
# lab.html で実際に動かした結果(Chromium、jQuery 4.0.0)
# 試したこと 結果
7 $.ajax の data に FormData だけ(4.0.0) status 400 / Content-Type: multipart/form-data
8 同じことを 3.7.1 で TypeError: Illegal invocation
9 $.ajax で 400 が返ると 失敗(catch へ) status 400 / responseJSON.errors 2
10 fetch で 400 が返ると 成功(then へ) ok false / status 400
11 jQuery のイベントの event.submitter undefined
12 event.originalEvent.submitter <button value="submit">
  • fetch は、返事が来れば 400 でも成功扱い。だから第10回では res.status を見て分けた。$.ajax は 400 で失敗扱いになり、catch に来る。返事の JSON は xhr.responseJSON に入っている
  • FormData は、jQuery 4.0.0 ならそのまま data に渡せる。Content-Type もブラウザが付けた(multipart/form-data)。3.7.1 で同じことをすると TypeError: Illegal invocation で止まる。3.x のコードでは processData: false と contentType: false の2行が要る
  • jQuery のイベントには submitter(押された送信ボタン)が無い。元のイベント(originalEvent)から取る
$form.on('submit', async function (event) {
  event.preventDefault();
  $result.prop('hidden', true);
  const button = event.originalEvent.submitter; // jQuery のイベントには submitter が無い。元のイベント(originalEvent)から取る
  if (!button.formNoValidate) {
    const errors = validateClaim(readClaim(), localDate(), rate);
    showErrors(errors);
    if (errors.length > 0) {
      $summary.trigger('focus');
      return;
    }
  }
  await send(new FormData(this, button), button);
});

なお、$.ajax の返り値は await で待てます(jQuery の Deferred は、Promise と同じように待てる形をしています)。昔のコードでは .done() と .fail() をつなげて書くのが定番でした。

七

同じ動きか確かめる

書き直しで一番こわいのは、「だいたい同じ」で終わることです。そこで、2つの版を同じ手順で Playwright に操作させ、各場面で画面の様子(合計、お知らせ、エラーのまとめ、赤い枠、結果、ボタン、行の数、読み上げ用の名前、フォーカスの位置など)を記録して、比べました。

jQuery 版の3つの場面。1 何も書かずに「申請する」を押すと、上のまとめに「入力内容を確認してください(3件)」と3つのリンク、件名の欄が赤い枠。2 申請を送ると、緑の帯で「申請を受け付けました。申請番号は EXP-2026-0013 です。」。3 ログインが切れた状態で下書き保存を押すと、赤い帯で「ログインの有効期限が切れました。もう一度ログインしてください(入力した内容は、この画面に残っています)。」
jQuery 版の①入力チェック、②送信、③ログイン切れ。文言もフォーカスも、素の JavaScript 版と同じ(筆者のデモページを、練習用のサーバー経由でクラウド上の Chromium で撮影。Playwright で実際に入力・クリックしたところ。2026年10月19日撮影、ページの時計は 2026年10月17日 15:00 に固定。アカウントはデモ専用の架空のもの。ブラウザの枠は説明のために描き足したもの)
# 同じ手順で操作して、画面の様子を記録して比べた(Chromium。3言語とも)
場面 素の JS(form.js) jQuery(form-jq.js) 同じ?
何も書かずに「申請する」 3 / focus error-summary 3 / focus error-summary 同じ
「行を追加」 focus date-2 focus date-2 同じ
3行入れて合計 46,851 円 46,851 円 同じ
4行目を足して消す 3 / focus add-row 3 / focus add-row 同じ
送信中 [x]下書き保存 [x]送信中… [x]下書き保存 [x]送信中… 同じ
送れた success 申請を受け付けました… success 申請を受け付けました… 同じ
ログイン切れで下書き保存 danger ログインの有効期限が… danger ログインの有効期限が… 同じ

# 記録した14項目(合計・3つのお知らせ・まとめの見出しと中身・赤い枠・結果・ボタン・aria-busy・行数・読み上げ用の名前・「行を追加」の可否・フォーカス)が、8 場面とも一致

3つの言語のどれでも、8つの場面すべてで、記録した値が一致しました。特にフォーカスの行き先(エラーのまとめ、足した行の日付、消したあとの「行を追加」)まで同じなのは、第8〜9回で決めた「キーボードの人が迷わない」動きを、書き直しでも落とさなかった、ということです。

新井全部「同じ」ですね。じゃあ jQuery 版のほうが短いし、こっちでいいのでは?

古井短くなったのは1割、増えたのは 79KB だ。それに、短くなったのは for と closest のあたりだけ。第8回のときに素の DOM の書き方を覚えたから、比べられる。

八

3.x から 4.0 へ

世の中の jQuery の多くは 3.x です。4.0.0 で何が変わったかを、同じページに 3.7.1 と slim 版も読み込んで確かめました。

「jQuery の罠を試す」ページ。20 行の表で、試したことと結果が並ぶ。$('#total') に textContent を聞くと undefined、val() は最初の1つ “3070” だけ、無い要素への $('#nothing').text('x') はエラーなし、$.ajax で 400 は失敗(catch へ)、fetch で 400 は成功(then へ)、jQuery のイベントの submitter は undefined、$.trim は 4.0.0 で undefined、フォーカスのイベントの順番が 3.7.1 と 4.0.0 で違う、.html() に入れたスクリプトは実行された、など
jQuery の罠を、ページを開いたときに実際に動かして表にした練習用のページ(筆者のデモページを、練習用のサーバー経由でクラウド上の Chromium で撮影。Playwright で実際に入力・クリックしたところ。2026年10月19日撮影、ページの時計は 2026年10月17日 15:00 に固定。アカウントはデモ専用の架空のもの。ブラウザの枠は説明のために描き足したもの)
# lab.html で実際に動かした結果(Chromium、jQuery 4.0.0)
# 試したこと 結果
15 typeof $.trim(4.0.0 / 3.7.1) undefined / function
16 typeof $.ajax(slim 版 / ふつうの版) undefined / function
17 フォーカスを A から B へ(3.7.1) A:focusout → A:blur → B:focusin → B:focus
18 フォーカスを A から B へ(4.0.0) A:blur → A:focusout → B:focus → B:focusin
  • $.trim、$.isArray、$.parseJSON など、ブラウザに同じものがある関数は消えた。' a '.trim()、Array.isArray()、JSON.parse() を使う
  • slim 版には $.ajax が無い(Deferred も無い)。通信を使うなら、ふつうの版か fetch
  • フォーカスのイベントの順番が、ブラウザ本来の順番(W3C の順番)に変わった。順番に頼っていたコードは動きが変わる

入力欄 A から B へ移ったときのイベントの順番

jQuery 3.7.1 A focusout A blur B focusin B focus jQuery 4.0.0 A blur A focusout B focus B focusin Chromium で実測。4.0.0 はブラウザ本来の順番に合わせた 順番に頼ったコードは、3.x から上げると動きが変わることがある

ほかにも、IE10 以前と古い Edge への対応が終わり、ソースが ES モジュールになり、FormData を自動で扱うようになりました。上げるときは、公式の移行ガイドと、古い書き方を警告してくれる jQuery Migrate を使うのが近道です。

九

いま jQuery とどう付き合うか

書き直してみると、jQuery のメソッドのほとんどに、素の JavaScript の相手がいることが分かります。

jQuery と素の JavaScript の対応

jQuery 素の JavaScript $('#total') document.querySelector('#total') $tbody.on('click', 'sel', fn) addEventListener + closest('sel') $el.addClass('x') el.classList.add('x') $el.text(s) el.textContent = s $el.attr(k, v) / .prop(k, v) el.setAttribute(k, v) / el[k] = v $('<a>', { text: s }) document.createElement('a') $rows.each(function () {…}) for (const row of rows) {…} await $.ajax({…}) await fetch(url, {…}) 今はどれも、素の JavaScript に同じ働きのものがある(第8〜10回で使ったもの) jQuery が生まれた2006年には、この右側の多くがまだ無かった

jQuery が生まれた2006年、ブラウザごとに DOM の書き方がばらばらで、querySelector も classList も fetch もありませんでした。jQuery はその差を埋める、なくてはならない道具でした。いまは右側が標準になり、どのブラウザでも同じように動きます。jQuery の考え方(セレクタで探す、まとめて扱う)が、ブラウザの標準に取り込まれた、とも言えます。

それでも、まだ多くのサイトで動いている

jQuery を使っているサイト 64.5% そのうちの版 3.x 78.8% 1.x 17.0% ・ 2.x 4.2% すべてのウェブサイトのうち 4.x はまだ表に出ていない 新しく作るサイトより、昔からあるサイトに残っている 1.x のまま動き続けているサイトも、まだ2割近くある W3Techs、2026年10月19日の値
  • 新しく作るなら ── 素の JavaScript で十分。この連載の申請フォームも、jQuery なしで全部書けた
  • すでに jQuery で動いているなら ── 無理に書き換えなくていい。直すときに読める力が要る。上げるなら 3.x の最新から 4.0 へ、移行ガイドを見ながら
  • どちらにしても ── 中で何が起きているかは、素の DOM の言葉で理解しておく。jQuery の罠は、だいたい「入れ物と要素の違い」と「黙って何もしない」から来る
POINT

jQuery は「素の JavaScript を短く書くための道具」です。道具が何を代わりにやってくれているのかが分かっていれば、jQuery のコードも、AI が書いたコードも、落ち着いて読めます。書き直して、記録して、比べる。今回やったのは、古いコードに手を入れるときの基本の手順そのものです。

結 — 一枚まとめと次回予告

  1. $() が返すのは入れ物。読むのは最初の1つ、書くのは全部。中の要素は [0]。見つからなくても黙っている。
  2. jQuery の得意技は、on の委任・メソッドチェーン・要素を1行で作ること。each の中は function で this。
  3. 文字を入れるのは .text()。.html() は innerHTML と同じで、スクリプトが動く。
  4. $.ajax は 400 や 401 で catch へ。fetch とは逆。4.0 は FormData をそのまま渡せる(3.x は 2行足す)。
  5. 同じ手順で動かして記録し、書き直しが同じ動きか確かめる。今回は 8 場面 × 14 項目 × 3 言語で一致。
  6. 新しく作るなら素の JavaScript、動いている jQuery は読めるように。

新井なんだか、古いコードがこわくなくなりました。

古井次はいよいよ最終回、仕上げだ。品質・安全・公開。それから、React や Vue のような「フレームワーク」の入口を少しだけのぞく。いにしえの道具で作ったものを、いまの世界に送り出すぞ。

新井最終回……。打ち上げは経費で落ちますか?

参考

ページの写真は、筆者が作ったデモページを、練習用のサーバー(Node.js)経由で2026年10月19日にクラウド上の Chromium(Playwright)で撮影したものです(ページの時計は 2026年10月17日 15:00 に固定)。撮影環境には Hiragino Sans がないため、日本語は Noto Sans CJK JP で表示されています。アカウント・申請は、練習用サーバーの架空のデータです。2つの版を同じ手順で操作した記録、ファイルの大きさ、試すページ(lab.html)の結果は、同じ Chromium を Playwright で操作・実行して記録した実際の値です。jQuery は npm の jquery 4.0.0 と 3.7.1 の配布ファイルを使いました。jQuery の利用率は W3Techs の 2026年10月19日の値です。各ページの HTML は Nu Html Checker(vnu)でエラーがないことを確かめています。登場人物は架空の人物です。

いにしえのフロントエンド入門 第14回 — jQuery / 2026.10

← 記事一覧へ