LoginSignup
3
2

More than 5 years have passed since last update.

jQuery.prototype.html の仕様を調べてみた

Posted at

概要

jQuery の .html で公式にない仕様を確認した為、jQuery v3.1.1 を元に仕様を調査してみました。

jQuery.prototype

この節は本題とは無関係なので読み飛ばしても構いません。

いわゆる「jQuery オブジェクト」と呼ばれるものは new jQuery のようにして生成されており、jQuery.prototype 上にあるメソッドを扱えます。

console.log(jQuery('p') instanceof jQuery);               // true
console.log(new jQuery('p') instanceof jQuery);           // true
console.log(jQuery('p').html === jQuery.prototype.html);  // true
console.log(jQuery.fn === jQuery.prototype);              // true

jQuery plugin を作る時に jQuery.fn にメソッドを代入していますが、内部的には jQuery.prototype に代入されています。
また、jQuery('p')new jQuery('p') は等価です。

本記事では jQuery.prototype.emptyjQuery#empty と表記します。
jQueryの公式ドキュメント上では jQuery.prototype.html.html() のように表記しています。

.html()

引数なしの .html() は DOM API である element.innerHTML の getter として評価されます。

jQuery#htmlでgetter処理
<div id="sample">This is a sample.</div>

<script>
console.log(jQuery('#sample').html());  // "This is a sample."
</script>

他の多くのgetter系 jQuery API と同じく、.html() は jQuery オブジェクト群の初めの要素ノードに対して処理されます。

jQuery#htmlで先頭の要素に対してgetter処理
<div class="sample">This is a pen.</div>
<div class="sample">This is a book.</div>
<div class="sample">This is a eraser.</div>

<script>
console.log(jQuery('.sample').html());  // "This is a pen.<"
</script>

.html( htmlString )

.html()String 型の引数が与えられた場合、DOM API である element.innerHTML の setter として評価されます。

jQuery#htmlでsetter処理
<div id="sample">This is a sample.</div>

<script>
console.log(jQuery('#sample').html('<strong>This is a jQuery</strong>'));  // [div#sample] ← 評価値は jQuery('#sample') になります

.html(htmlString) は対応する jQuery オブジェクト群の全てに適用されます。

jQuery#htmlで先頭の要素に対してgetter処理
<!-- 下記3つとも "<strong>This is a jQuery</strong>" に置換される -->
<div class="sample">This is a pen.</div>
<div class="sample">This is a book.</div>
<div class="sample">This is a eraser.</div>

<script>
console.log(jQuery('.sample').html('<strong>This is a jQuery</strong>'));  // [div.sample, div.sample, div.sample]
</script>

.html( function )

関数を引数にした .html() はコールバック関数に「インデックス」「element.innerHTML」を渡して全てのjQueryオブジェクトに innerHTML の setter 処理を行います。

jQuery#htmlでコールバック処理
<!-- 下記3つとも '<strong>" + htmlString + '"</strong>'' に置換される -->
<div class="sample">This is a pen.</div>
<div class="sample">This is a book.</div>
<div class="sample">This is a eraser.</div>

<script>
console.log(jQuery('.sample').html(function (index, htmlString) {
  return '<strong>"' + htmlString + '"</strong>';
}));  // [div.sample, div.sample, div.sample]

[隠し仕様] .html( DOMNode or jQueryObject) (v.3.1.1 現在)

公式リファレンスでは言及されていませんが、jQuery v3.1.1 ではDOMノードやjQueryオブジェクトを引数にとることもできるようです。
(注意: この仕様はリファレンスにない以上、公式に認められた仕様ではないので今後の更新で削除される可能性があります。原則として使わない事をお勧めします。)

jQueryオブジェクトが引数にとられた場合、当該要素の子要素を全て削除(jQuery#empty の処理が実行されます)した後に当該jQueryオブジェクトを jQuery#append します。

jQuery#htmlで子要素群をjQueryオブジェクトで上書きする
<div id="sample">This is a sample.</div>

<script>
jQuery('#sample').html(jQuery('<strong>replaced text.</strong>'));
</script>

引数がDOMノードであった場合、一度 jQuery オブジェクトに変換してから先と同様の処理を行います。

jQuery#htmlで子要素群をDOMノードで上書きする
<div id="sample-1">This is a pen.</div>
<div id="sample-2">This is a book.</div>
<script>
/**
 * 要素ノード
 */
var strong = document.createElement('strong');
strong.textContent = 'replaced text 1.';
jQuery('#sample-1').html(strong);

/**
 * DocumentFragment
 */
var df = document.createDocumentFragment(),
    p = document.createElement('p');

for (var i = 1; i < 4; ++i) {
  p.textContent = 'This is a sample-2-' + i;
  df.appendChild(p.cloneNode(true));
}

jQuery('#sample-2').html(df);
</script>

まとめ

公式ドキュメントでは .html() が文字列を対象に取るメソッドと説明されている為、それに則るのが好ましいと思います。
DOMノードが必要なら次の2つの対策が考えられます。

  • jQuery(selector).empty().append(domNode)
  • DOM API で完結したコードを書く (Node#removeChild -> appendChild)
子コード群を削除してDOMノードを上書き挿入する
<div id="parent-1">
  <div id="child-1-1">child-1-1</div>
  <div id="child-1-2">child-1-2</div>
  <div id="child-1-3">child-1-3</div>
</div>

<div id="parent-2">
  <div id="child-2-1">child-2-1</div>
  <div id="child-2-2">child-2-2</div>
  <div id="child-2-3">child-2-3</div>
</div>

<script>
'use strict';
/**
 * createDocumentFragment
 */
function createDFNode (textList) {
  var df = document.createDocumentFragment(),
      p = document.createElement('p');

  for (var i = 0, len = textList.length; i < len; ++i) {
    p.textContent = textList[i];
    df.appendChild(p.cloneNode(true));
  }

  return df;
}

/**
 * jQuery#empty -> jQuery#append (jQuery API)
 */
jQuery('#parent-1').empty().append(createDFNode(['text1-1', 'text1-2', , 'text1-3']));

/**
 * Node#removeChild -> appendChild
 */
var parent = document.getElementById('parent-2');
Array.from(parent.childNodes).forEach(function (node) {
  node.parentNode.removeChild(node);
});
parent.appendChild(createDFNode(['text2-1', 'text2-2', , 'text2-3']));
</script>

参考リンク

「公式リファレンス」と「jquery-3.1.1.js のソースコード(.html の該当行: 5978行目)」。

3
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2