JavaScriptには、多数のポリフィルを受け取り、jQuery関数を置き換えることができる多くの素晴らしい更新があります。 しかし、残念ながら、JSはjQueryに存在するほとんどの機能の実行方法をまだ学習していません。
この記事では、最も重要なjQuery関数
jQuery();
。
JQuery();
関数 メインといわゆるカバーの2つの機能で構成されています。 カバーを開始すると、カバーはメイン関数を開始し、そこから結果を返します。
カバーは次のとおりです。
var jQuery = function (selector, context) { return new jQuery.prototype.init(selector, context); };
コードからわかるように、
jQuery();
関数を実行すると
jQuery();
プロトタイプと同じパラメーターを使用して
init
関数を実行し
init
。
init
関数がメインです。
次に、jQuery関数を参照するコンストラクターで、関数のプロトタイプを作成する必要があります。 注:古いバージョンのjQueryでは、
constructor
パラメーターは指定されていません。
jQuery.prototype = { constructor: jQuery };
jQuery.fnプロパティはどこから来たのですか、なぜjQueryオブジェクトに新しい関数を指定できるのですか?
実際、開発者は
と
同一視し、それにより2つのパラメーターに同じオブジェクトを設定して、オブジェクトの新しい関数をより短時間で追加できるようにしました。
jQuery.fn
と
jQuery.fn
同一視し、それにより2つのパラメーターに同じオブジェクトを設定して、オブジェクトの新しい関数をより短時間で追加できるようにしました。
jQuery.fn = jQuery.prototype = { constructor: jQuery };
それでは、メイン関数の作成を始めましょう。 関数の完全な構造をペイントしません。 少なくとも1週間はかかりますが、jQueryの例を使用して短いバージョンを実装する方法を説明します。
jQueryでは、関数全体が、関数が受信したデータを反復処理する条件と、必要な要素がスローされる配列で構成されます。
関数の初期形式は次のようになります。
var init = jQuery.prototype.init = function (selector, context) { /** , */ var array = []; /** , * * HTML */ if (typeof selector === 'string') { /** , DOM */ } else if (selector.nodeType) { /** * * */ } else if ({}.toString.call(selector) === '[object Array]') { /** * , * */ } else if ({}.toString.call(selector) === '[object Object]') { /** , ? */ } else if ({}.toString.call(selector) === '[object HTMLCollection]' || {}.toString.call(selector) === '[object NodeList]') { /** — */ } else if ({}.toString.call(selector) === '[object Function]') { /** , */ } else { return array; } };
最初の条件を考慮してください-セレクタが文字列の場合。 これが文字列である場合、チェックする必要があります:セレクターかHTMLコードか(jQueryはこの方法でHTMLコードを解析できるため)。
jQueryでは、最初の引数がHTMLコードであるかどうかを確認するために、
/** , HTML */ if (selector[0] === "<" && selector[selector.length - 1] === ">" && selector.length >= 3) { /** HTML, */ } else { };
最初の引数がHTMLの場合、次のアクションが発生します。
- 特別な関数を使用して、HTMLコードが解析され、解析関数によって返されるライブ配列がメイン配列と結合されます。
HTMLコードの解析機能の実装と類似-jQuery.parseHTML()残念ながら、この機能の実装方法については説明しません。 彼女にはあまりにも多くの枝があり、それについては別の記事を書くことができます。 しかし、心配しないでください、あなたはすでにこの関数がどのように機能するかについて書きました。 この記事を読むには、次のリンクをクリックしてください: habrahabr.ru/post/164533
この機能を実装できる代替機能について説明します。
- 最初の選択肢は、
innerHTML
の助けを借りてコードを含む行を挿入し、既製のDOM要素を取得する要素を作成することです。
var parseHTML = function (HTML) { /** * , * * — . * * */ if (typeof HTML === 'string' && HTML[0] === "<" && HTML[HTML.length - 1] === ">" && HTML.length >= 3) { /** */ var E = document.createElement('div'); /** HTML */ E.innerHTML = HTML; /** */ return E.childNodes; } else { /** — , */ return []; }; };
- 2番目の選択肢は、
DOMParser();
関数をDOMParser();
してDOMParser();
することDOMParser();
およびその追加関数parseFromString();
。
var parseHTML = function (HTML) { /** * , * * — . * * */ if (typeof HTML === 'string' && HTML[0] === "<" && HTML[HTML.length - 1] === ">" && HTML.length >= 3) { /** HTML */ var DOM = new DOMParser().parseFromString(HTML, 'text/html'); /** */ var DOMList = DOM.body.childNodes; /** */ return DOMList; } else { /** — , */ return []; }; };
- 3番目の方法は、
document.implementation.createHTMLDocument();
関数を使用して解析することdocument.implementation.createHTMLDocument();
。
var parseHTML = function (HTML) { /** * , * * — . * * */ if (typeof HTML === 'string' && HTML[0] === "<" && HTML[HTML.length - 1] === ">" && HTML.length >= 3) { /** HTML */ var DOM = document.implementation.createHTMLDocument(); /** HTML */ DOM.body.innerHTML = HTML; /** */ var DOMList = DOM.body.childNodes; /** */ return DOMList; } else { /** — , */ return []; }; };
ただし、jQuery関数のすべての機能を繰り返す関数が必要です。 したがって、上記の3つのオプションすべてを含む1つの関数を作成します。
var parseHTML = function (data, context, keepScripts) { /** , */ if (typeof data !== 'string') { return []; } /** * context * keepScripts, * true/false */ if (typeof context === 'boolean') { keepScripts = context; context = false; }; var DOM, DOMList; if (!context || context === document) { /** HTML */ DOM = document.implementation.createHTMLDocument() || new DOMParser().parseFromString('', 'text/html'); /** HTML */ DOM.body.innerHTML = data; /** */ DOMList = DOM.body.childNodes; } else if (context.nodeType) { /** , */ DOM = document.createElement('div'); /** */ context.appendChild(DOM); /** */ DOM.innerHTML = data; /** */ DOMList = DOM.childNodes; /** DOM */ DOM.parentNode.removeChild(DOM); }; /** , */ if (keepScripts === true) { /** */ var scripts = DOM.scripts || DOM.querySelectorAll('script'); /** */ if (scripts.length) { /** */ for (var i = 0; i < scripts.length; i++) { /** */ var script = document.createElement('script'); /** */ script.innerHTML = scripts[i].innerHTML; if (scripts[i].attributes) script.attributes = scripts[i].attributes; /** HEAD */ document.head.appendChild(script); /** HEAD */ script.parentNode.removeChild(script); }; }; }; /** */ return (function () { var array = []; for (var i = 0; i < DOMList.length; i++) { array[array.length] = DOMList[i]; }; return array; })(); };
配列を結合する機能の実装と類似-jQuery.merge()jQueryソースを見ると、次のようにこの関数が実装されていることがわかります。
var merge = function( first, second ) { var len = +second.length, /** second.length , , ( - , ) */ j = 0, i = first.length; /** */ for ( ; j < len; j++ ) { /** * * * */ first[ i++ ] = second[ j ]; } /** */ first.length = i; /** */ return first; };
jQuery.merge()
関数に代わるいくつかの選択肢があります。
- 最初の選択肢は
Array.concat();
関数Array.concat();
配列を結合します。
[0, 1, 2].concat([3, 4, 5]); // [0, 1, 2, 3, 4, 5]
ただし、コレクションまたはノードリストをHTML配列にアタッチする場合、この関数は機能しません。これは、配列を結合するのではなく、配列内の配列を取得するためです。
しかし、これは非常に簡単に修正できます。ライブアレイを通常のアレイに変換する必要があります。 これは、[].slice.call()
関数を使用して実行できます。
[0, 1, 2].concat( [].slice.call(document.querySelectorAll(selector)) ); // [0, 1, 2, element, element]
または、生きている配列のすべての要素を調べて、それらを通常の配列に移動することにより、これを行うことができます。
var elements = document.querySelectorAll(selector); var array = []; for (var i = 0; i < elements.length; i++) { array[array.length] = elements[i]; }; [0, 1, 2].concat(array); // [0, 1, 2, element, element]
- 2番目の選択肢は、2番目の配列の要素を反復処理し、それらを最初の配列に転送することです。 同じテクノロジーが標準のjQuery関数で観察できます。
var merge = function (array0, array1) { for (var i = 0; i < array1.length; i++) { array0[array0.length] = array1[i]; /** * array0.push(array1[i]); * */ }; return array0; }; merge([0, 1, 2], [3, 4, 5]); // [0, 1, 3, 4, 5, 6]
- 最初の選択肢は、
-
context
引数がパラメーターを持つオブジェクトかどうかを確認します。 その場合、すべてのパラメーターを引数付きでDOM要素に書き込みます。
if ({}.toString.call(context) === '[object Object]') { for (var i = 0; i < array.length; i++) { for (var argument in context) { array.setAttribute(argument, context[argument]); }; }; };
- 要素を含む完成した配列を出力します
最初の引数がHTMLコードでない場合は、セレクターです。 jQueryでは、セレクター要素はSizzleと呼ばれる別のライブラリーを使用して検索されます。 このライブラリの利点は、セレクタによる検索がIE7 +以降で機能し始めることです。
このライブラリを使用したセレクタによる要素の検索は次のとおりです。
Sizzle( String selector );
しかし、JavaScriptの代替手段である
document.querySelectorAll( String selector );
を使用します
document.querySelectorAll( String selector );
。 Sizzleライブラリの前にあるこのメソッドの唯一の欠点は、IE9 +でのみ動作を開始することです。
セレクターで要素を表示する前に、
context
引数を確認し、セレクターで要素を検索する要素ではないことを確認する必要があり
context
。 コードのすべてのステップを説明したので、すべてのステップをペイントするわけではありません。
/** * , context * , * selector */ /** context */ if (context && context.nodeType) { /** */ var Elements = context.querySelectorAll(selector); /** */ return jQuery.merge(array, Elements); /** context */ } else if ({}.toString.call(context) === '[object HTMLCollection]' || {}.toString.call(context) === '[object NodeList]') { /** * * */ for (var i = 0; i < context.length; i++) { /** */ var Elements = context[i].querySelectorAll(selector); /** */ jQuery.merge(array, Elements); }; /** */ return array; /** context */ } else if (typeof context === 'string') { /** * */ var Parents = document.querySelectorAll(context); /** * * */ for (var i = 0; i < Parents.length; i++) { /** */ var Elements = Parents[i].querySelectorAll(selector); /** */ jQuery.merge(array, Elements); }; /** */ return array; /** * , * */ } else { /** */ var Elements = document.querySelectorAll(selector); /** */ return jQuery.merge(array, Elements); };
jQueryでは、これらすべてのチェックは検索関数
.find();
置き換えられ
.find();
。 したがって、レコード
jQuery(selector, elements);
jQuery(elements).find(selector);
関数
jQuery(elements).find(selector);
ここで、主な機能は次のとおりです。
var init = jQuery.prototype.init = function (selector, context) { /** , */ var array = []; /** , * * HTML */ if (typeof selector === 'string') { /** , HTML */ if (selector[0] === "<" && selector[selector.length - 1] === ">" && selector.length >= 3) { /** HTML */ jQuery.merge(array, jQuery.parseHTML(selector, context && context.nodeType ? context.ownerDocument || context : document, true)); /** , context * . , * DOM . */ if ({}.toString.call(context) === '[object Object]') { for (var i = 0; i < array.length; i++) { for (var argument in context) { array.setAttribute(argument, context[argument]); }; }; }; /** */ return array; /** HTML, */ } else { /** * , context * , * selector */ /** context */ if (context && context.nodeType) { /** */ var Elements = context.querySelectorAll(selector); /** */ return jQuery.merge(array, Elements); /** context */ } else if ({}.toString.call(context) === '[object HTMLCollection]' || {}.toString.call(context) === '[object NodeList]') { /** * * */ for (var i = 0; i < context.length; i++) { /** */ var Elements = context[i].querySelectorAll(selector); /** */ jQuery.merge(array, Elements); }; /** */ return array; /** context */ } else if (typeof context === 'string') { /** * */ var Parents = document.querySelectorAll(context); /** * * */ for (var i = 0; i < Parents.length; i++) { /** */ var Elements = Parents[i].querySelectorAll(selector); /** */ jQuery.merge(array, Elements); }; /** */ return array; /** * , * */ } else { /** */ var Elements = document.querySelectorAll(selector); /** */ return jQuery.merge(array, Elements); } }; /** , DOM */ } else if (selector.nodeType) { /** * * */ } else if ({}.toString.call(selector) === '[object Array]') { /** * , * */ } else if ({}.toString.call(selector) === '[object Object]') { /** , ? */ } else if ({}.toString.call(selector) === '[object HTMLCollection]' || {}.toString.call(selector) === '[object NodeList]') { /** — */ } else if ({}.toString.call(selector) === '[object Function]') { /** , */ } else { return array; } };
次に、セレクターがDOM要素である場合の2番目の条件を検討します。 セレクターがDOM要素の場合、この要素をメイン配列に挿入するだけで、出力します。
/** */ array[0] = selector; /** */ return array;
3番目の条件に移りましょう-セレクターが配列の場合。 配列の場合は、それをメイン配列と組み合わせて印刷します。 上記の関数を使用して配列を結合します。
/** */ jQuery.merge(array, selector); /** */ return array;
4番目の条件について-セレクターがパラメーターを持つオブジェクトである場合。 セレクターがパラメーターを持つオブジェクトの場合、DOM要素の場合のように、オブジェクトを配列に追加して印刷するだけです。
/** */ array[0] = selector; /** */ return array;
5番目の条件を考慮してください-セレクターが生きている配列である場合。 セレクタが生きている配列の場合、要素をメイン配列に転送します。 アクションは配列の場合のように見えます。
/** */ jQuery.merge(array, selector); /** */ return array;
セレクタが関数の場合、最後の条件を考慮する必要があります。 セレクターが関数の場合、
jQuery( Function );
短縮機能
jQuery(document).ready( Function );
。
DOMのロード後にコードを実行する関数の実装と類似物はjQuery(ドキュメント).ready(関数)です。
jQueryソースを見ると、この関数が次のように実装されていることがわかります。
コードを見ると、DOMのロード後にスクリプトを実行するための2つの別個のオプションに基づいて構築されていることがわかります。
DOMを読み込んだ後にスクリプトを実行する方法は他にもあります。
var ready = (function() { var readyList, DOMContentLoaded, class2type = {}; class2type["[object Boolean]"] = "boolean"; class2type["[object Number]"] = "number"; class2type["[object String]"] = "string"; class2type["[object Function]"] = "function"; class2type["[object Array]"] = "array"; class2type["[object Date]"] = "date"; class2type["[object RegExp]"] = "regexp"; class2type["[object Object]"] = "object"; var ReadyObj = { // DOM ? true, . isReady: false, // , , . readyWait: 1, // ( ) holdReady: function(hold) { if (hold) { ReadyObj.readyWait++; } else { ReadyObj.ready(true); } }, // , DOM ready: function(wait) { // , DOMready/load if ((wait === true && !--ReadyObj.readyWait) || (wait !== true && !ReadyObj.isReady)) { // , body , , IE . if (!document.body) { return setTimeout(ReadyObj.ready, 1); } // DOM ReadyObj.isReady = true; // DOM Ready , , , if (wait !== true && --ReadyObj.readyWait > 0) { return; } // , readyList.resolveWith(document, [ReadyObj]); // //if ( ReadyObj.fn.trigger ) { // ReadyObj( document ).trigger( "ready" ).unbind( "ready" ); //} } }, bindReady: function() { if (readyList) { return; } readyList = ReadyObj._Deferred(); // , $(document).ready() // , . if (document.readyState === "complete") { // , return setTimeout(ReadyObj.ready, 1); } // Mozilla, Opera webkit nightlies if (document.addEventListener) { // callback document.addEventListener("DOMContentLoaded", DOMContentLoaded, false); // window.onload, window.addEventListener("load", ReadyObj.ready, false); // IE } else if (document.attachEvent) { // , // , , iframes document.attachEvent("onreadystatechange", DOMContentLoaded); // window.onload, window.attachEvent("onload", ReadyObj.ready); // IE, frame // , var toplevel = false; try { toplevel = window.frameElement == null; } catch (e) {} if (document.documentElement.doScroll && toplevel) { doScrollCheck(); } } }, _Deferred: function() { var // callback callbacks = [], // stored [ context , args ] fired, // , firing, // , cancelled, // deferred = { // done( f1, f2, ...) done: function() { if (!cancelled) { var args = arguments, i, length, elem, type, _fired; if (fired) { _fired = fired; fired = 0; } for (i = 0, length = args.length; i < length; i++) { elem = args[i]; type = ReadyObj.type(elem); if (type === "array") { deferred.done.apply(deferred, elem); } else if (type === "function") { callbacks.push(elem); } } if (_fired) { deferred.resolveWith(_fired[0], _fired[1]); } } return this; }, // resolveWith: function(context, args) { if (!cancelled && !fired && !firing) { // , args = args || []; firing = 1; try { while (callbacks[0]) { callbacks.shift().apply(context, args); //shifts a callback, and applies it to document } } finally { fired = [context, args]; firing = 0; } } return this; }, // resolve: function() { deferred.resolveWith(this, arguments); return this; }, // ? isResolved: function() { return !!(firing || fired); }, // cancel: function() { cancelled = 1; callbacks = []; return this; } }; return deferred; }, type: function(obj) { return obj == null ? String(obj) : class2type[Object.prototype.toString.call(obj)] || "object"; } } // DOM Internet Explorer function doScrollCheck() { if (ReadyObj.isReady) { return; } try { // IE, // http://javascript.nwbox.com/IEContentLoaded/ document.documentElement.doScroll("left"); } catch (e) { setTimeout(doScrollCheck, 1); return; } // ReadyObj.ready(); } // document ready if (document.addEventListener) { DOMContentLoaded = function() { document.removeEventListener("DOMContentLoaded", DOMContentLoaded, false); ReadyObj.ready(); }; } else if (document.attachEvent) { DOMContentLoaded = function() { // , body , , IE (ticket #5443). if (document.readyState === "complete") { document.detachEvent("onreadystatechange", DOMContentLoaded); ReadyObj.ready(); } }; } function ready(fn) { // "" ReadyObj.bindReady(); var type = ReadyObj.type(fn); // callback' readyList.done(fn); // ReadyList _Deferred() } return ready; })();
コードを見ると、DOMのロード後にスクリプトを実行するための2つの別個のオプションに基づいて構築されていることがわかります。
- 最初のオプションは、
DOMContentLoaded
でハングしたDOMContentLoaded
イベントを介してスクリプトを実行することです。 このオプションは、IE9 +以降で機能します。
document.addEventListener('DOMContentLoaded', function() { // }, false);
- 2番目のオプションは、
readystatechange
でハングアップしたreadystatechange
イベントを使用してreadyState
をチェックすることです。 このオプションは古いため、IE4 +以降で動作します。
document.onreadystatechange = function(){ if(document.readyState === 'complete'){ // } };
DOMを読み込んだ後にスクリプトを実行する方法は他にもあります。
- 1つの簡単な方法は、すべての要素の後に
<script></script>
をbody
に移動することです。 この配置では、DOMが最初にロードされ、次にスクリプトがロードされます。
<body> <div>...</div> <script> // </script> </body>
- このオプションは少し奇妙です。 特別な関数を作成し、
body
最後にあるスクリプトを使用して呼び出すことができます。
function onload() { // };
<body> ... <script> onload(); </script> </body>
- 人気のあるオプションの1つは、
body
onload
イベントを設定するbody
です。
function myFunc() { // };
<body onload="myFunc()">...</body>
この関数を、上記で
readystatechange
た
readystatechange
イベントという代替手段の1つに置き換えます。
/** DOM */ document.onreadystatechange = function(){ if(document.readyState === 'complete'){ selector(); }; }; /** */ return selector;
これですべての条件のアクションが記録され、機能はほぼ準備完了です。 メイン関数のプロトタイプをメイン配列の
__proto__
パラメーターに割り当て、jQueryオブジェクトの追加機能を作成できるようにします。 __proto__オブジェクト
__proto__
かなり新しく、IE11 +でのみ動作します。 したがって、ハーフフィルを作成します。
if (array.__proto__) { array.__proto__ = jQuery.prototype; } else { for (var param in jQuery.prototype) { array[param] = jQuery.prototype[param]; }; };
関数の準備ができました。 最終的には、次のようになります。
/** — */ var jQuery = function (selector, context) { return new jQuery.prototype.init(selector, context); }; /** */ jQuery.prototype = { constructor: jQuery }; /** */ var init = jQuery.prototype.init = function (selector, context) { /** , */ var array = []; /** * proto * , * * * jQuery */ /** __proto__ * IE11+ * */ if (array.__proto__) { array.__proto__ = jQuery.prototype; } else { for (var param in jQuery.prototype) { array[param] = jQuery.prototype[param]; }; }; /** , * * HTML */ if (typeof selector === 'string') { /** , HTML */ if (selector[0] === "<" && selector[selector.length - 1] === ">" && selector.length >= 3) { /** HTML */ jQuery.merge(array, jQuery.parseHTML(selector, context && context.nodeType ? context.ownerDocument || context : document, true)); /** , context * . , * DOM . */ if ({}.toString.call(context) === '[object Object]') { for (var i = 0; i < array.length; i++) { for (var argument in context) { array.setAttribute(argument, context[argument]); }; }; }; /** */ return array; /** HTML, */ } else { /** * , context * , * selector */ /** context */ if (context && context.nodeType) { /** */ var Elements = context.querySelectorAll(selector); /** */ return jQuery.merge(array, Elements); /** context */ } else if ({}.toString.call(context) === '[object HTMLCollection]' || {}.toString.call(context) === '[object NodeList]') { /** * * */ for (var i = 0; i < context.length; i++) { /** */ var Elements = context[i].querySelectorAll(selector); /** */ jQuery.merge(array, Elements); }; /** */ return array; /** context */ } else if (typeof context === 'string') { /** * */ var Parents = document.querySelectorAll(context); /** * * */ for (var i = 0; i < Parents.length; i++) { /** */ var Elements = Parents[i].querySelectorAll(selector); /** */ jQuery.merge(array, Elements); }; /** */ return array; /** * , * */ } else { /** */ var Elements = document.querySelectorAll(selector); /** */ return jQuery.merge(array, Elements); } }; /** , DOM */ } else if (selector.nodeType) { /** */ array[0] = selector; /** */ return array; /** * * */ } else if ({}.toString.call(selector) === '[object Array]') { /** */ jQuery.merge(array, selector); /** */ return array; /** * , * */ } else if ({}.toString.call(selector) === '[object Object]') { /** */ array[0] = selector; /** */ return array; /** , ? */ } else if ({}.toString.call(selector) === '[object HTMLCollection]' || {}.toString.call(selector) === '[object NodeList]') { /** */ jQuery.merge(array, selector); /** */ return array; /** — */ } else if ({}.toString.call(selector) === '[object Function]') { /** DOM */ document.onreadystatechange = function(){ if(document.readyState === 'complete'){ selector(); }; }; /** */ return selector; /** , */ } else { return array; } }; jQuery.merge = function (first, second) { var len = +second.length, /** second.length , , */ j = 0, i = first.length; /** */ for (; j < len; j++) { /** * * * */ first[i++] = second[j]; } /** */ first.length = i; /** */ return first; }; jQuery.parseHTML = function (data, context, keepScripts) { /** , */ if (typeof data !== 'string') { return []; } /** * context * keepScripts, * true/false */ if (typeof context === 'boolean') { keepScripts = context; context = false; }; var DOM, DOMList; if (!context || context === document) { /** HTML */ DOM = document.implementation.createHTMLDocument() || new DOMParser().parseFromString('', 'text/html'); /** HTML */ DOM.body.innerHTML = data; /** */ DOMList = DOM.body.childNodes; } else if (context.nodeType) { /** , */ DOM = document.createElement('div'); /** */ context.appendChild(DOM); /** */ DOM.innerHTML = data; /** */ DOMList = DOM.childNodes; /** DOM */ DOM.parentNode.removeChild(DOM); }; /** , */ if (keepScripts === true) { /** */ var scripts = DOM.scripts || DOM.querySelectorAll('script'); /** */ if (scripts.length > 0) { /** */ for (var i = 0; i < scripts.length; i++) { /** */ var script = document.createElement('script'); /** */ script.innerHTML = scripts[i].innerHTML; if (scripts[i].attributes) script.attributes = scripts[i].attributes; /** HEAD */ document.head.appendChild(script); /** HEAD */ script.parentNode.removeChild(script); }; }; }; /** */ return (function () { var array = []; for (var i = 0; i < DOMList.length; i++) { array[array.length] = DOMList[i]; }; return array; })(); };
これで、通常のjQueryのように関数を使用し、プロトタイプを介してオブジェクトの新しい関数を作成できます。
jQuery.prototype.myFunction = function () {...};
これで、この記事を終了します。覚えておくべき主なこと:jQueryはJavaScriptでも書かれています:)