【jQuery-1.7.2ソース分析】jQueryオブジェクト
9713 ワード
前言
他の人が書いたソース分析の文章を見て、多くはコードを貼って、注釈を書きます.个人的にはそこから吸収した知识は限られていると思います.このように技术よりも、设计思想よりも軽いので、このシリーズは古い道を缲り返すつもりはありません.もっと多くののののは私のソースコードを见る心得を分かち合うことです.いくつかの普及に値するテクニックについては、文章の最後に専門的にリストされ、検索されます.
jQueryオブジェクトは何ですか.例を挙げると、$('#id')はjQueryオブジェクトを返します.これはjQuery全体の核心です.だから、私は先にそれを分析します.
このコードを初めて見た人は、その構造にめまいがします.このような書き方は本当に珍しいからです.johnの考えについて、私は大胆に推測しました.
1.jQオブジェクトのコンストラクション関数はなぜprotptypeなのか.init?
答え:コンストラクション関数の論理はprototypeの他の属性/方法と関連しています.例えば、selectorやlengthは、一緒に書くと読みやすいです.
Initメソッドを呼び出すと、パラメータが空の場合、jQオブジェクトはprototypeと同等になり、構造が明確に見えます.
パラメータが空でない場合、selectorやlengthなどのprototypeのプロパティが上書きされます.つまり、prototypeのプロパティはデフォルト値を与えるためだけです.また、contextなどのprototypeにリストされていないプロパティも作成されます.これらのプロパティは構造関数に書かれています.しかし同様に,論理をコンパクトに保つためにinitメソッドに併記する.
2.jQはいったいどんなオブジェクトを作りたいのですか?答え:このオブジェクトは配列に似ています.例えば、次のコードです.
そこでfy[0]=「john」と、ちょっと気を失ったのではないでしょうか.これは配列ではありません.あなたの目に隠されないでください.これはオブジェクトで、0は属性名です.なぜなら0=whoは文法を間違えるので、ちょっとしたテクニックを使いました.
さらにprototypeの他の方法、例えばeach、slice、map、push、sort、spliceを見て、配列をシミュレートしているわけではありません.
3.pushStackを説明しましょうか?
答え:その名の通り、スタック操作で、主にundoに使用されています.
4.initをもう一度説明しましょうか.
答え:説明しなければなりませんね.この方法は本当に重要ですね.jQの構造関数は説明しないで何を説明することができますか.
5. 何か言いたいことがありますか.
答え:最後に言いましょう.
どうしてそう書くの?例えば最初の行は、なぜ変数に直接与えずにjQueryに与えられるのか.fn?
1.変数を与えるのはjQというファイルの内部でしか使えないが、jQは強力なプラグインメカニズムがあるので、外部拡張を容易にするためにjQueryに与える.fn.もちろんこの部分を処理しなくても大丈夫です.もっと字を打ってください.しかし、jQはやはり超流行の枠組みで、略語できるのは自分で縮めましょう.他の人はこのような恐れのない労働をします.
2.2行目の書き方はさらに卵が痛い.まずinitは構造関数ですが、私は続けますか?まあ、これは基礎知識だと思いますが.
jQがこの行を書かなければ、obj instanceof jQueryは永遠にfalseになります.
テクニック:
1.オブジェクト上の属性/メソッドは、プロトタイプ上の対応する属性/メソッドを上書きします(overrideの方が良いかもしれません).
2.配列を巧みに使用する方法.
最後の結果はal.length===4で、jQオブジェクトがなぜlength属性を必要とするのかがわかるでしょう
他の人が書いたソース分析の文章を見て、多くはコードを貼って、注釈を書きます.个人的にはそこから吸収した知识は限られていると思います.このように技术よりも、设计思想よりも軽いので、このシリーズは古い道を缲り返すつもりはありません.もっと多くののののは私のソースコードを见る心得を分かち合うことです.いくつかの普及に値するテクニックについては、文章の最後に専門的にリストされ、検索されます.
jQueryオブジェクトは何ですか.例を挙げると、$('#id')はjQueryオブジェクトを返します.これはjQuery全体の核心です.だから、私は先にそれを分析します.
var jQuery = function( selector, context ) {
// The jQuery object is actually just the init constructor 'enhanced'
return new jQuery.fn.init( selector, context, rootjQuery );
};
......
jQuery.fn = jQuery.prototype = {
constructor: jQuery,
init: function( selector, context, rootjQuery ),
selector: "",
jquery: "1.7.2",
length: 0,
size: function(),
toArray: function(),
get: function( num ),
pushStack: function( elems, name, selector ),
each: function( callback, args ),
ready: function( fn ),
eq: function( i ),
first: function(),
last: function(),
slice: function(),
map: function( callback ),
end: function(),
push: push,
sort: [].sort,
splice: [].splice
};
jQuery.fn.init.prototype = jQuery.fn;
このコードを初めて見た人は、その構造にめまいがします.このような書き方は本当に珍しいからです.johnの考えについて、私は大胆に推測しました.
1.jQオブジェクトのコンストラクション関数はなぜprotptypeなのか.init?
答え:コンストラクション関数の論理はprototypeの他の属性/方法と関連しています.例えば、selectorやlengthは、一緒に書くと読みやすいです.
Initメソッドを呼び出すと、パラメータが空の場合、jQオブジェクトはprototypeと同等になり、構造が明確に見えます.
パラメータが空でない場合、selectorやlengthなどのprototypeのプロパティが上書きされます.つまり、prototypeのプロパティはデフォルト値を与えるためだけです.また、contextなどのprototypeにリストされていないプロパティも作成されます.これらのプロパティは構造関数に書かれています.しかし同様に,論理をコンパクトに保つためにinitメソッドに併記する.
2.jQはいったいどんなオブジェクトを作りたいのですか?答え:このオブジェクトは配列に似ています.例えば、次のコードです.
function FuckYou(who) {
this[0] = who;
}
var fy = new FuckYou('john');
そこでfy[0]=「john」と、ちょっと気を失ったのではないでしょうか.これは配列ではありません.あなたの目に隠されないでください.これはオブジェクトで、0は属性名です.なぜなら0=whoは文法を間違えるので、ちょっとしたテクニックを使いました.
さらにprototypeの他の方法、例えばeach、slice、map、push、sort、spliceを見て、配列をシミュレートしているわけではありません.
3.pushStackを説明しましょうか?
答え:その名の通り、スタック操作で、主にundoに使用されています.
/**
*
* ctrl + z
*
*/
pushStack: function( elems, name, selector ) {
// jQ ,API prototype
var ret = this.constructor();
// elems , push
if ( jQuery.isArray( elems ) ) {
push.apply( ret, elems );
// elems , merge(), :
// 1. elems childNodes
// 2. elems this[0], this[1] ,
} else {
jQuery.merge( ret, elems );
}
// $("p").find("span")
// p, span
// ,jQ , ( end())
ret.prevObject = this;
ret.context = this.context;
// , jQ
// name
// selector
// ,jQ DOM , after, find ,
if ( name === "find" ) {
// find , "div span"
ret.selector = this.selector + ( this.selector ? " " : "" ) + selector;
} else if ( name ) {
// ,
// . class, .
// , Sizzle , ,
ret.selector = this.selector + "." + name + "(" + selector + ")";
}
return ret;
}
4.initをもう一度説明しましょうか.
答え:説明しなければなりませんね.この方法は本当に重要ですね.jQの構造関数は説明しないで何を説明することができますか.
init: function( selector, context, rootjQuery ) {
var match, elem, ret, doc;
// $(""), $(null), or $(undefined)
if ( !selector ) {
return this;
}
// $(DOMElement)
if ( selector.nodeType ) {
this.context = this[0] = selector;
this.length = 1;
return this;
}
// body ,
if ( selector === "body" && !context && document.body ) {
this.context = document;
this[0] = document.body;
this.selector = selector;
this.length = 1;
return this;
}
// HTML
if ( typeof selector === "string" ) {
// , <p>,
if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) {
match = [ null, selector, null ];
} else {
// quickExpr = /^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/
//
// quickExpr = /^[^<]*(<(.|\s)+>)[^>]*$|^#([\w-]+)$/
//
// , ,
// location.hash XSS
//
// ,
// 1. ^[^#<]*(<[\w\W]+>)[^>]*$
// 2. ^#([\w\-]*)$
// , ID
// HTML :
// [^#<]* # <
// (<[\w\W]+>) , <div>123</div>
// [^>]*$ >
match = quickExpr.exec( selector );
}
// , ID context
// ID context ? ,ID
if ( match && (match[1] || !context) ) {
// $(html) -> $(array)
if ( match[1] ) {
// context HTMLElement
context = context instanceof jQuery ? context[0] : context;
// doc document
doc = ( context ? context.ownerDocument || context : document );
// rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>)?$/
// , <input /> <div></div>
// , , createElement
ret = rsingleTag.exec( selector );
if ( ret ) {
// ,context ?
// ,context {id: 'id', title: 'title'}
if ( jQuery.isPlainObject( context ) ) {
selector = [ document.createElement( ret[1] ) ];
jQuery.fn.attr.call( selector, context, true );
} else {
selector = [ doc.createElement( ret[1] ) ];
}
} else {
// ,
ret = jQuery.buildFragment( [ match[1] ], [ doc ] );
selector = ( ret.cacheable ? jQuery.clone(ret.fragment) : ret.fragment ).childNodes;
}
return jQuery.merge( this, selector );
// $("#id")
} else {
elem = document.getElementById( match[2] );
// Check parentNode to catch when Blackberry 4.6 returns
// nodes that are no longer in the document #6963
// , , , bugfix jQ
// , IE678? , HTML5
// , fix ?john
if ( elem && elem.parentNode ) {
// IE Opera getElementById name , ID,
if ( elem.id !== match[2] ) {
return rootjQuery.find( selector );
}
// Otherwise, we inject the element directly into the jQuery object
this.length = 1;
this[0] = elem;
}
this.context = document;
this.selector = selector;
return this;
}
// $(expr, $(...)), $(...).find(expr)
// ,jQ
// ,context HTMLElement
// jQ ,
} else if ( !context || context.jquery ) {
return ( context || rootjQuery ).find( selector );
// $(expr, context), $(context).find(expr)
//
} else {
return this.constructor( context ).find( selector );
}
// $(function)
//
} else if ( jQuery.isFunction( selector ) ) {
return rootjQuery.ready( selector );
}
// selector jQ ,
if ( selector.selector !== undefined ) {
this.selector = selector.selector;
this.context = selector.context;
}
// selector this
// ,this
return jQuery.makeArray( selector, this );
}
5. 何か言いたいことがありますか.
答え:最後に言いましょう.
jQuery.fn = jQuery.prototype = {...}
jQuery.fn.init.prototype = jQuery.fn;
どうしてそう書くの?例えば最初の行は、なぜ変数に直接与えずにjQueryに与えられるのか.fn?
1.変数を与えるのはjQというファイルの内部でしか使えないが、jQは強力なプラグインメカニズムがあるので、外部拡張を容易にするためにjQueryに与える.fn.もちろんこの部分を処理しなくても大丈夫です.もっと字を打ってください.しかし、jQはやはり超流行の枠組みで、略語できるのは自分で縮めましょう.他の人はこのような恐れのない労働をします.
2.2行目の書き方はさらに卵が痛い.まずinitは構造関数ですが、私は続けますか?まあ、これは基礎知識だと思いますが.
function jQuery() { }
jQuery.prototype = {
constructor: jQuery
}
jQがこの行を書かなければ、obj instanceof jQueryは永遠にfalseになります.
テクニック:
1.オブジェクト上の属性/メソッドは、プロトタイプ上の対応する属性/メソッドを上書きします(overrideの方が良いかもしれません).
2.配列を巧みに使用する方法.
var push = Array.prototype.push;
function ArrayLike() {
this[0] = 0;
this[1] = 1;
this.length = 2;
}
var al = new ArrayLike();
push.apply(al, [2, 3]);
console.log(al)
最後の結果はal.length===4で、jQオブジェクトがなぜlength属性を必要とするのかがわかるでしょう