jQuery源码学习之四 (jQUery对象的实例属性和方法)
1、get()
参数为null则返回DOM数组,否则返回相应的下标DOM元素(支持负数)
jQuery.fn = jQuery.prototype = { ... get: function( num ) { return num == null ?this.toArray() :( num < 0 ? this[ this.length + num ] : this[ num ] ); }, ... };2、pushStack():jQuery的栈方法,与end()方法对应
this.constructor指向函数jQuery,则 ret = jQuery.merge( this.constructor(), elems ) 将创建返回一个jQuery实例ret,然后将传入的elem扩充进去。通过ret.prevObject = this;指向调用pushStack()方法的jQuery实例对象。进一步可通过end()方法 返回上一个jQuery对象。(jQuery内部多处使用)
jQuery.fn = jQuery.prototype = { ... pushStack: function( elems ) { var ret = jQuery.merge( this.constructor(), elems ); ret.prevObject = this; ret.context = this.context; return ret; } ... end: function() { return this.prevObject || this.constructor(null); } ... };
3、each() : 调用$.each();
jQuery.fn = jQuery.prototype = { ... each: function( callback, args ) { return jQuery.each( this, callback, args ); }, <pre name="code" class="html">... }
$.each()源码:
if 中提供的方法是jQuery的API中没有提供的,jQuery的API中提供的方法在else中(也是我们平时使用的$.each()的用法)。
先看外层else中代码:
if 传入的第一个参数是数组[]或类数组eg:{0:"a",1:"b","length":2},则for循环,调用毁掉函数callback.call(obj[i],i,obj[i]),this指向obj[i],并将i,obj[i],作为参数传入。else 如果传入的是对象则用for in 进行循环。
外层if 中代码和外层else 中原理大致一样,只不过是接受了 第三个参数args,并利用了apply修改callback的this指向(args可以是数组或者类数组)
each: function( obj, callback, args ) { var value, i = 0, length = obj.length, isArray = isArraylike( obj ); if ( args ) { if ( isArray ) { for ( ; i < length; i++ ) { value = callback.apply( obj[ i ], args ); if ( value === false ) { break; } } } else { for ( i in obj ) { value = callback.apply( obj[ i ], args ); if ( value === false ) { break; } } } // A special, fast, case for the most common use of each } else { if ( isArray ) { for ( ; i < length; i++ ) { value = callback.call( obj[ i ], i, obj[ i ] ); if ( value === false ) { break; } } } else { for ( i in obj ) { value = callback.call( obj[ i ], i, obj[ i ] ); if ( value === false ) { break; } } } } return obj; }
涉及到的函数$.isArraylick(),源码如下:
function isArraylike( obj ) { var length = obj.length, type = jQuery.type( obj ); if ( jQuery.isWindow( obj ) ) { return false; } if ( obj.nodeType === 1 && length ) { return true; } return type === "array" || type !== "function" && ( length === 0 || typeof length === "number" && length > 0 && ( length - 1 ) in obj ); }
涉及到的函数:isWIndow()、$.type()
isWindow: function( obj ) { return obj != null && obj === obj.window; }, type: function( obj ) { if ( obj == null ) { return String( obj ); } // Support: Safari <= 5.1 (functionish RegExp) return typeof obj === "object" || typeof obj === "function" ? class2type[ core_toString.call(obj) ] || "object" : typeof obj; },
$().ready
$().slice()
core_slice其实等价于[].slice,调用的其实是数组的slice方法,并用apply更改this指向,用pushStack重新生成新的jQuery对象并返回.
slice: function() { return this.pushStack( core_slice.apply( this, arguments ) ); },$().eq()
first()、last() 都是调用eq()(支持负数的传入),用pushStack重新生成新的jQuery对象并返回.
first: function() { return this.eq( 0 ); }, last: function() { return this.eq( -1 ); }, eq: function( i ) { var len = this.length, j = +i + ( i < 0 ? len : 0 ); return this.pushStack( j >= 0 && j < len ? [ this[j] ] : [] ); },$().map 调用$.map()
map: function( callback ) { return this.pushStack( jQuery.map(this, function( elem, i ) { return callback.call( elem, i, elem ); })); },
相关jQUery源码:
jQuery.fn = jQuery.prototype = { // The current version of jQuery being used jquery: core_version, constructor: jQuery, init:{ ... }, selector: "", // The default length of a jQuery object is 0 length: 0, toArray: function() { return core_slice.call( this ); }, // Get the Nth element in the matched element set OR // Get the whole matched element set as a clean array get: function( num ) { return num == null ? // Return a 'clean' array this.toArray() : // Return just the object ( num < 0 ? this[ this.length + num ] : this[ num ] ); }, // Take an array of elements and push it onto the stack // (returning the new matched element set) pushStack: function( elems ) { // Build a new jQuery matched element set var ret = jQuery.merge( this.constructor(), elems ); // Add the old object onto the stack (as a reference) ret.prevObject = this; ret.context = this.context; // Return the newly-formed element set return ret; }, // Execute a callback for every element in the matched set. // (You can seed the arguments with an array of args, but this is // only used internally.) each: function( callback, args ) { return jQuery.each( this, callback, args ); }, ... end: function() { return this.prevObject || this.constructor(null); }, // For internal use only. // Behaves like an Array's method, not like a jQuery method. push: core_push, sort: [].sort, splice: [].splice };