构造jquery对象

jQuery对象是一个类数组对象。

一)构造函数jQuery()

构造函数的7种用法:

1.jQuery(selector [, context ])

传入字符串参数:检查该字符串是选择器表达式还是HTML代码。如果是选择器表达式,则遍历文档查找匹配的DOM元素,

并创建一个包含这些DOM元素引用的jQuery对象。如果没有匹配的DOM,则创建一个length属性为0的空jQuery对象。

默认情况下对匹配元素的查找从根元素document开始,但也可以传入context参数限制查找范围。

如果选择器表达式是简单的'#id'且没有context参数,则调用document.getElementById()查找。

如果不是则调用jQuery的find()方法。

2.jQuery(html [, ownerDocument])、jQuery(html, props)

如果传入的参数是html代码,则尝试用html代码创建新的DOM元素,并创建包含这些DOM元素引用的jQuery对象。

如果html代码是单独的标签,使用document.createElement()创建DOM元素。如果是复杂的html代码,则使用innerHTML.

参数ownerDocument用于创建新DOM元素的文档对象,如果不传入默认为当前文档对象。

如果html代码是单独标签,第二个参数还可以是props,props是一个包含了属性、事件的普通对象,在调用了document.createElement()

方法创建了DOM元素后,参数props会被传给jQuery的attr()方法,由该方法设置新DOM的属性,事件。

$('<div/>', {
"class": "test",
text: "Click me!",
click: function () {
console.log("log");
}
});

3.jQuery(element)、jQuery(elementArray)

如果传入一个DOM元素或者DOM元素数组,则封装DOM元素到jQuery对象种,并返回该jQuery对象。

$('#aInput').click(function () {
$(this).val("value");
});

4.jQuery(object)

传入一个普通的js对象,则把该对象封装到jQuery对象中,并返回jQuery对象。

这个功能可以方便地在普通js对象上实现自定事件的绑定和触发。

var person = {name: 'Tony', gender: 'man'};
var $person = $(person);
$person.on('custom', function () {
//do sth
});

5.jQuery(callback)

如果传入一个函数,则在document上绑定一个ready事件监听函数,当DOM结构加载完成时执行。

注意:ready事件要早于load事件发生。

6.jQuery(jQuery object)

创建一个副本并返回。

二)总体结构

jQuery对象模块总体结构:

(function ( window, undefined ) {
//构造jQuery对象
var jQuery = (function () {
var jQuery = function (selector,context) {
return new jQuery.fn.init(selector, context, rootjQuery);
}, //一堆局部变量声明 //jQuery.fn成为jQuery.prototype的简写
//覆盖jQuery原型的目的:方便继承,顺便也减少了创建每个jQuery实例所消耗的内存
jQuery.fn = jQuery.prototype = {
constructor: jQuery,
init: function (selector, context, rootjQuery) {},
//一堆原型属性和方法
}; //用jQuery的原型对象覆盖jQuery.fn.init.prototype的原型对象
//使 new jQuery.fn.init()返回的实例也可以构造函数jQuery()的原型方法和属性
        jQuery.fn.init.prototype = jQuery.fn;
        jQuery.extend = jQuery.fn.extend = function () {};
jQuery.extend({
//一堆静态属性和方法
});
return jQuery;
})(); //省略其他模块代码
window.jQuery = window.$ = jQuery;
})(window);

三)jQuery.fn.init(selector, context, rootjQuery)

1.12个分支

2.源码分析

1)定义jQuery.fn.init(selector, context, rootjQuery):

jQuery.fn = jQuery.prototype = {
constructor: jQuery,
init: function( selector, context, rootjQuery ) {
var match, elem, ret, doc;

该构造函数接收三个参数:

selector:

context: 不传入,或者传入DOM元素,jQuery对象,普通js对象之一。

rootjQuery: 包含了document对象的jQuery对象。用于:

1.document.getElementById()查找失败

2.selector是选择器表达式且未指定context

3.selector是函数

2)参数selector可以转换为false

// Handle $(""), $(null), or $(undefined)
if ( !selector ) {
return this;
}

3)参数selector是DOM元素

// Handle $(DOMElement)
if ( selector.nodeType ) {
this.context = this[0] = selector;
this.length = 1;
return this;
}

4)参数selector是字符串'body'

// The body element only exists once, optimize finding it
if ( selector === "body" && !context && document.body ) {
this.context = document;
this[0] = document.body;
this.selector = selector;
this.length = 1;
return this;
}

5)参数selector是其他字符串

先检测selector是HTML代码还是#id

        // Handle HTML strings
if ( typeof selector === "string" ) {
// Are we dealing with HTML string or an ID?
if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) {
// Assume that strings that start and end with <> are HTML and skip the regex check
match = [ null, selector, null ]; } else {
match = quickExpr.exec( selector );
}

1.参数selector是单独标签

则调用document.createElement()创建DOM元素:

//如果是字符串
if (typeof selector === 'string') {
//如果是HTML字符串
if (selector.charAt(0) === '<' && selector.charAt(length-1) === '>' && selector.length >= 3) {
match = [null, selector, null];
} else {
match = quickExpr.exec(selector);
}
} if (match && (match[1] || !context)) {
//HANDLE: $(html) -> $(array)
if (match[1]) {
context = context instanceof jQuery ? context[0] : context;
doc = (context ? context.ownerDocument || context : document); //如果只传入了一个字符串,并且是个简单的html标签
//就调用createElement,跳过剩余部分。
ret = rsingleTag.exec( selector );
if (ret) {
//是否是纯粹对象
if ( jQuery.isPlainObject( context ) ) {
selector = [document.createElement(ret[1])];
jQuery.fn.attr.call( selector, context, true );
} else {
selector = [document.createElement(ret[1])];
} } else {
ret = jQuery.buildFragment( match[1], [doc] ); }

2.参数selector是复杂HTML代码

} else {
ret = jQuery.buildFragment( [ match[1] ], [ doc ] );
selector = ( ret.cacheable ? jQuery.clone(ret.fragment) : ret.fragment ).childNodes;
}
//将创建的DOM元素合并到当前jQuery对象中,并返回
return jQuery.merge( this, selector );

3.参数selector是"#id",且未指定参数context

                // HANDLE: $("#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
if ( elem && elem.parentNode ) {
// Handle the case where IE and Opera return items
// by name instead of 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;
}

4.参数selector是选择器表达式

            // HANDLE: $(expr, $(...))
} else if ( !context || context.jquery ) {
return ( context || rootjQuery ).find( selector ); // HANDLE: $(expr, context)
// (which is just equivalent to: $(context).find(expr)
} else {
return this.constructor( context ).find( selector );
}

5.参数selector是函数

// HANDLE: $(function)
// Shortcut for document ready
} else if ( jQuery.isFunction( selector ) ) {
return rootjQuery.ready( selector );
}

6.参数selector是jQuery对象

if ( selector.selector !== undefined ) {
this.selector = selector.selector;
this.context = selector.context;
}

7.参数selector是其他任意值

如果selector是数组或者伪数组,则都添加到jQuery对象中,如果是JS

对象则作为第一个元素放入。该方法也可将6)中selector包含的全部元素引用复制到当前jQuery

return jQuery.makeArray( selector, this );

四)jQuery.buildFragment(args, nodes, scripts)

1.实现原理

该方法会先创建一个文档片段DocumentFragment,然后调用方法jQuery.clean(elems, context, fragment, scripts)

将HTML代码转换为HTML元素,并存储在创建的DocumentFragment中。

此外,如果HTML代码符合缓存条件,该方法还会把转换后的DOM缓存起来,第三次转换相同的HTML代码时直接从缓存中读取。

2.源码分析

1)参数:

args:数组,含有待转换为DOM元素的html代码

nodes:数组,含有文档对象、jQuery对象或DOM元素,用于修正创建文档片段DocumentFragment的文档对象。

scripts:数组,用于存放HTML代码中的script元素。

2)定义局部变量,修正文档对象doc

*
* fragment:指向创建的DocumentFragment
* cacheable: 是否符合缓存条件
* cacheresult:指向从缓存对象,jQuery.fragments提取到的文档片段,其中包含了缓存的DOM元素
* doc:创建文档片段的文档对象
* */
var fragment, cacheable, cacheresults, doc,
first = args[ 0 ]; // nodes may contain either an explicit document object,
// a jQuery collection or context object.
// If nodes[0] contains a valid object to assign to doc
if ( nodes && nodes[0] ) {
doc = nodes[0].ownerDocument || nodes[0];
} // Ensure that an attr object doesn't incorrectly stand in as a document object
// Chrome and Firefox seem to allow this to occur and will throw exception
// Fixes #8950
if ( !doc.createDocumentFragment ) {
doc = document;
}

3)其他操作

// Only cache "small" (1/2 KB) HTML strings that are associated with the main document
// Cloning options loses the selected state, so don't cache them
// IE 6 doesn't like it when you put <object> or <embed> elements in a fragment
// Also, WebKit does not clone 'checked' attributes on cloneNode, so don't cache
// Lastly, IE6,7,8 will not correctly reuse cached fragments that were created from unknown elems #10501
if ( args.length === 1 && typeof first === "string" && first.length < 512 && doc === document &&
first.charAt(0) === "<" && !rnocache.test( first ) &&
(jQuery.support.checkClone || !rchecked.test( first )) &&
(jQuery.support.html5Clone || !rnoshimcache.test( first )) ) { cacheable = true; cacheresults = jQuery.fragments[ first ];
if ( cacheresults && cacheresults !== 1 ) {
fragment = cacheresults;
}
}
//转换HTML代码为DOM元素
if ( !fragment ) {
fragment = doc.createDocumentFragment();
jQuery.clean( args, doc, fragment, scripts );
}
//把转换后的DOM元素放入缓存对象jQuery.fragments中
if ( cacheable ) {
jQuery.fragments[ first ] = cacheresults ? fragment : 1;
}
//返回文档片段和返回状态
return { fragment: fragment, cacheable: cacheable };
}; jQuery.fragments = {};

五)jQuery.clean(elems, context, fragment, scripts)

1.实现原理

该方法负责把HTML代码转换为DOM元素,并提取其中的script元素。该方法会先创建一个临时

的div元素,并将其插入一个安全的文档片段(能正确渲染HTML5元素的文档片段)中,

然后把HTML代码赋值给div元素的innerHTML属性,最后解析div元素的子元素得到转换后的DOM。

2.源码分析

1)参数:

elems:数组,包含了待转换的html代码

context:文档对象

fragment:文档片段,存放转换后的DOM元素

scripts:数组,存放转换后的DOM元素中的script元素

2)修正文档对象

//ret用于存放转换后的DOM元素
var checkScriptType, script, j,
ret = []; context = context || document; // !context.createElement fails in IE with an error but returns typeof 'object'
if ( typeof context.createElement === "undefined" ) {
context = context.ownerDocument || context[0] && context[0].ownerDocument || document;
}

3)遍历elems数组

//这里使用"!=",可以同时过滤undefined,null的情况,但不会过滤掉0
for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) {
//如果elem是数字,则转换为字符串类型
if (typeof elem === "number") {
elem += "";
} //如果elem是0,此时已经被转换为字符串“0”
if (!elem) {
continue;
}

1.创建文本节点:

如果字符串不包含标签、字符代码和数字代码,则调用原生方法document.createTextNode()方法创建文本节点。

if ( !rhtml.test( elem ) ) {
elem = context.createTextNode( elem );
} else {
rhtml = /<|&#?\w+;/,

为什么不能包含标签、字符代码和数字代码?

因为document.createTextNode()方法对于传给它的字符串不会做转义解析。

而浏览器innerHTML机制可以。

2.修正自关闭标签

else {
// Fix "XHTML"-style tags in all browsers
elem = elem.replace(rxhtmlTag, "<$1></$2>");
rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,

3.创建一个临时的div

// Trim whitespace, otherwise indexOf won't work as expected
var tag = ( rtagName.exec( elem ) || ["", ""] )[1].toLowerCase(),
//从wrapMap提取对应的父标签,因为HTML语法要求这些标签必须包含在父标签中
wrap = wrapMap[ tag ] || wrapMap._default,
//包裹的深度,稍后会根据该变量剥去父元素
depth = wrap[0],
div = context.createElement("div"),
rtagName = /<([\w:]+)/,
wrapMap = {
option: [ 1, "<select multiple='multiple'>", "</select>" ],
legend: [ 1, "<fieldset>", "</fieldset>" ],
thead: [ 1, "<table>", "</table>" ],
tr: [ 2, "<table><tbody>", "</tbody></table>" ],
td: [ 3, "<table><tbody><tr>", "</tr></tbody></table>" ],
col: [ 2, "<table><tbody></tbody><colgroup>", "</colgroup></table>" ],
area: [ 1, "<map>", "</map>" ],
_default: [ 0, "", "" ]
},

4.把临时div插入安全文档中去

                    // Append wrapper element to unknown element safe doc fragment
if ( context === document ) {
// Use the fragment we've already created for this document
safeFragment.appendChild( div );
} else {
// Use a fragment created with the owner document
createSafeFragment( context ).appendChild( div );
}
safeFragment = createSafeFragment( document );
function createSafeFragment( document ) {
var list = nodeNames.split( "|" ),
safeFrag = document.createDocumentFragment(); if ( safeFrag.createElement ) {
while ( list.length ) {
safeFrag.createElement(
list.pop()
);
}
}
return safeFrag;
}

5.转换html代码为DOM元素

// Go to html and back, then peel off extra wrappers
div.innerHTML = wrap[1] + elem + wrap[2]; // Move to the right depth
while ( depth-- ) {
div = div.lastChild;
}

6.移除IE6\7自动插入的空tbody元素

                    // Remove IE's autoinserted <tbody> from table fragments
if ( !jQuery.support.tbody ) { // String was a <table>, *may* have spurious <tbody>
var hasBody = rtbody.test(elem),
tbody = tag === "table" && !hasBody ?
div.firstChild && div.firstChild.childNodes : // String was a bare <thead> or <tfoot>
wrap[1] === "<table>" && !hasBody ?
div.childNodes :
[]; for ( j = tbody.length - 1; j >= 0 ; --j ) {
if ( jQuery.nodeName( tbody[ j ], "tbody" ) && !tbody[ j ].childNodes.length ) {
tbody[ j ].parentNode.removeChild( tbody[ j ] );
}
}
}

7)插入IE6\7\8自动删除的前导空白

// IE completely kills leading whitespace when innerHTML is used
if ( !jQuery.support.leadingWhitespace && rleadingWhitespace.test( elem ) ) {
div.insertBefore( context.createTextNode( rleadingWhitespace.exec(elem)[0] ), div.firstChild );
}

8)取到转换后的DOM元素集合

elem = div.childNodes;

9)修正IE7、8中复选框和单选框选中问题

10)合并转换后的DOM元素

if ( elem.nodeType ) {
ret.push( elem );
} else {
ret = jQuery.merge( ret, elem );
}

4)传入了fragment的情况

if ( fragment ) {
checkScriptType = function( elem ) {
return !elem.type || rscriptType.test( elem.type );
};
for ( i = 0; ret[i]; i++ ) {
script = ret[i];
if ( scripts && jQuery.nodeName( script, "script" ) && (!script.type || rscriptType.test( script.type )) ) {
scripts.push( script.parentNode ? script.parentNode.removeChild( script ) : script ); } else {
if ( script.nodeType === 1 ) {
var jsTags = jQuery.grep( script.getElementsByTagName( "script" ), checkScriptType ); ret.splice.apply( ret, [i + 1, 0].concat( jsTags ) );
}
fragment.appendChild( script );
}
}
} return ret;

六)jQuery.extend()、jQuery.fn.extend()

1.如何使用

用于合并两个或者多个对象的属性到第一个对象,语法:

jQuery.extend([deep], target, object1[, objectN]);

jQuery.fn.extend([deep], target, object1[, objectN]);

deep:布尔值,是否进行递归合并,默认为不递归

target:目标对象

objectN:源对象,包含的待合并的属性

如果仅提供一个对象,参数target将被忽略,当前的jQuery或者jQuery.fn被当作目标对象

通过这种方式在jQuery或者jQuery.fn上添加新的属性或者方法。

2.源码分析

1)定义局部变量

jQuery.extend = jQuery.fn.extend = function() {
var options, name, src, copy, copyIsArray, clone,
target = arguments[0] || {},
i = 1,
length = arguments.length,
deep = false;

options:指向某个源对象

name:指向某个源对象的某个属性名

src:某个目标对象的某个属性原始值

copy:某个源对象的某个属性值

copyIsArray:指示变量copy是否是数组

clone:深度复制时,原始值的修正值

target:指向目标对象

i:源对象的起始下标

length:表示参数的个数,用于修正变量target

deep:是否深度合并,默认为false

jQuery.extend = jQuery.fn.extend = function() {
var options, name, src, copy, copyIsArray, clone,
target = arguments[0] || {},
i = 1,
length = arguments.length,
deep = false; // Handle a deep copy situation
if ( typeof target === "boolean" ) {
deep = target;
target = arguments[1] || {};
// skip the boolean and the target
i = 2;
} // Handle case when target is a string or something (possible in deep copy)
if ( typeof target !== "object" && !jQuery.isFunction(target) ) {
target = {};
} // extend jQuery itself if only one argument is passed
if ( length === i ) {
target = this;
--i;
} for ( ; i < length; i++ ) {
// Only deal with non-null/undefined values
if ( (options = arguments[ i ]) != null ) {
// Extend the base object
for ( name in options ) {
src = target[ name ];
copy = options[ name ]; // Prevent never-ending loop
if ( target === copy ) {
continue;
} // Recurse if we're merging plain objects or arrays
if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {
if ( copyIsArray ) {
copyIsArray = false;
clone = src && jQuery.isArray(src) ? src : []; } else {
clone = src && jQuery.isPlainObject(src) ? src : {};
} // Never move original objects, clone them
target[ name ] = jQuery.extend( deep, clone, copy ); // Don't bring in undefined values
} else if ( copy !== undefined ) {
target[ name ] = copy;
}
}
}
} // Return the modified object
return target;
};

七)原型属性和方法

1. .selector、.jQuery、.length、.size()

1)selector:用于记录jQuery查找和过滤DOM元素时的选择器表达式,可用于调试。

2)jQuery:表示jQuery的版本号

3)length:表示当前jQuery对象中元素的个数

4)方法size():功能上等价于length

    // Start with an empty selector
selector: "", // The current version of jQuery being used
jquery: "1.7.2", // The default length of a jQuery object is 0
length: 0, // The number of elements contained in the matched element set
size: function() {
return this.length;
},

2..toArray()、.get([index])

1.toArray():将当前jQuery对象转换为真正的数组,转换后的数组包含了所有元素。

slice = Array.prototype.slice,
toArray: function() {
return slice.call( this, 0 );
},

2.get([index]):返回当前jQuery对象中指定位置的元素或包含了全部元素的数组(无参)。

    get: function( num ) {
return num == null ? // Return a 'clean' array
this.toArray() : // Return just the object
( num < 0 ? this[ this.length + num ] : this[ num ] );
},

3. .each( function(index, Elment) )、 jQuery.each( collection, callback( indexArray, valueOfValue ) )

1. .each( function(index, Elment) )

遍历当前jQuery对象,并在每个元素上执行回调函数。每当执行回调函数

函数执行时会传递当前循环次数作为参数,更重要的是回调函数在当前

上下文环境中触发,在回调函数中返回false可以终止遍历。

each: function( callback, args ) {
return jQuery.each( this, callback, args );
},

2.jQuery.each( collection, callback ( indexArray, valueOfValue ) )

通用的遍历方法,用于无缝地遍历对象和数组,对于数组和类数组通过下标

遍历,对于其他对象则通过属性名遍历。在遍历过程中如果回调函数返回false则结束遍历。

/* *
* object:待遍历的对象或者数组
* callback: 回调函数,会在数组的每个元素或者对象的每个属性上执行
* args: 传递给回调函数的参数数组,可选,如果没有传入,则执行回调
* 函数时传入两个参数(下标或属性名,元素或属性值),如果传入了参数
* 则把该参数传递给回调函数。
*
* */
each: function( object, callback, args ) {
var name, i = 0,
length = object.length,
isObj = length === undefined || jQuery.isFunction( object ); if ( args ) {
if ( isObj ) {
for ( name in object ) {
if ( callback.apply( object[ name ], args ) === false ) {
break;
}
}
} else {
for ( ; i < length; ) {
if ( callback.apply( object[ i++ ], args ) === false ) {
break;
}
}
} // A special, fast, case for the most common use of each
} else {
if ( isObj ) {
for ( name in object ) {
if ( callback.call( object[ name ], name, object[ name ] ) === false ) {
break;
}
}
} else {
for ( ; i < length; ) {
if ( callback.call( object[ i ], i, object[ i++ ] ) === false ) {
break;
}
}
}
} return object;
},

4. .map( callback(index, domElement) )、 jQuery.map( arrayOrObject, callback(value, indexOrKey) )

1) .map( callback(index, domElement) )

遍历当前jQuery对象,在每个元素上执行回调函数,并将回调函数的返回值放入一个新的jQuery对象中。

map: function( callback ) {
return this.pushStack( jQuery.map(this, function( elem, i ) {
return callback.call( elem, i, elem );
}));
},

2) jQuery.map( arrayOrObject, callback(value, indexOrKey) )

对数组的每个元素或者对象的每个属性调用一个回调函数,并将回调函数的返回值放入一个新的数组中。

执行回调函数时传入两个参数:数组元素或属性值,元素下标或属性名。关键字this指向全局对象window。

//参数arg仅限于jQuery内部使用
map: function( elems, callback, arg ) {
var value, key, ret = [],
i = 0,
length = elems.length,
// jquery objects are treated as arrays
isArray = elems instanceof jQuery || length !== undefined && typeof length === "number" && ( ( length > 0 && elems[ 0 ] && elems[ length -1 ] ) || length === 0 || jQuery.isArray( elems ) ) ; // Go through the array, translating each of the items to their
if ( isArray ) {
for ( ; i < length; i++ ) {
value = callback( elems[ i ], i, arg ); if ( value != null ) {
ret[ ret.length ] = value;
}
} // Go through every key on the object,
} else {
for ( key in elems ) {
value = callback( elems[ key ], key, arg ); if ( value != null ) {
ret[ ret.length ] = value;
}
}
} // Flatten any nested arrays
return ret.concat.apply( [], ret );
},

5. .pushStack( elements, name, arguments )

创建一个新的空jQuery对象,然后把DOM对象元素集合放入对象中,并保留对当前jQuery对象的引用。

//elems: 放入新jQuery对象的元素数组
//name: 产生元素数组的jQuery方法名
//修正原型属性的.selector
pushStack: function( elems, name, selector ) {
// Build a new jQuery matched element set
var ret = this.constructor(); if ( jQuery.isArray( elems ) ) {
push.apply( ret, elems ); } else {
jQuery.merge( ret, elems );
} // Add the old object onto the stack (as a reference)
ret.prevObject = this; ret.context = this.context; if ( name === "find" ) {
ret.selector = this.selector + ( this.selector ? " " : "" ) + selector;
} else if ( name ) {
ret.selector = this.selector + "." + name + "(" + selector + ")";
} // Return the newly-formed element set
return ret;
},

6.  .end()

end: function() {
return this.prevObject || this.constructor(null);
},

7. .eq(index)、 .first()、 .last()、 .slice(start[, end])

    eq: function( i ) {
i = +i;
return i === -1 ?
this.slice( i ) :
this.slice( i, i + 1 );
}, first: function() {
return this.eq( 0 );
}, last: function() {
return this.eq( -1 );
}, slice: function() {
return this.pushStack( slice.apply( this, arguments ),
"slice", slice.call(arguments).join(",") );
},

八)静态属性和方法

1. jQuery.onConflit([removeAll])

用于释放jQuery对全局变量的控制权

// Map over jQuery in case of overwrite
_jQuery = window.jQuery, // Map over the $ in case of overwrite
_$ = window.$,
noConflict: function( deep ) {
if ( window.$ === jQuery ) {
window.$ = _$;
} if ( deep && window.jQuery === jQuery ) {
window.jQuery = _jQuery;
} return jQuery;
},

2.类型检测:jQuery.isFunction(obj)、 jQuery.isArray(obj)、jQuery.isWindow(obj)、

jQuery.isNumeric(value)、jQuery.type(obj)、jQuery.isPlainObject(object)、jQuery.isEmptyObject(object)

isFunction: function( obj ) {
return jQuery.type(obj) === "function";
}, isArray: Array.isArray || function( obj ) {
return jQuery.type(obj) === "array";
}, isWindow: function( obj ) {
return obj != null && obj == obj.window;
}, isNumeric: function( obj ) {
return !isNaN( parseFloat(obj) ) && isFinite( obj );
}, type: function( obj ) {
return obj == null ?
String( obj ) :
class2type[ toString.call(obj) ] || "object";
}, //是否是以{}或者new Object()创建的
isPlainObject: function( obj ) {
// Must be an Object.
// Because of IE, we also have to check the presence of the constructor property.
// Make sure that DOM nodes and window objects don't pass through, as well
if ( !obj || jQuery.type(obj) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) {
return false;
} try {
// Not own constructor property must be Object
//如果obj没有属性constructor,则说明该对象必然是通过对象字面量{}创建
if ( obj.constructor &&
!hasOwn.call(obj, "constructor") &&
!hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) {
return false;
}
} catch ( e ) {
// IE8,9 Will throw exceptions on certain host objects #9897
return false;
} // Own properties are enumerated firstly, so to speed up,
// if last one is own, then all properties are own.
//在for循环中会先枚举非继承属性,再枚举继承属性
var key;
for ( key in obj ) {} return key === undefined || hasOwn.call( obj, key );
}, isEmptyObject: function( obj ) {
for ( var name in obj ) {
return false;
}
return true;
},

3.解析JSON和XML:jQuery.parseJSON(data)、 jQuery.parseXML(data)

1.jQuery.parseJSON(data)

    parseJSON: function( data ) {
if ( typeof data !== "string" || !data ) {
return null;
} // Make sure leading/trailing whitespace is removed (IE can't handle it)
data = jQuery.trim( data ); // Attempt to parse using the native JSON parser first
if ( window.JSON && window.JSON.parse ) {
return window.JSON.parse( data );
} // Make sure the incoming data is actual JSON
// Logic borrowed from http://json.org/json2.js
if ( rvalidchars.test( data.replace( rvalidescape, "@" )
.replace( rvalidtokens, "]" )
.replace( rvalidbraces, "")) ) { return ( new Function( "return " + data ) )(); }
jQuery.error( "Invalid JSON: " + data );
},

2.jQuery.parseXML(data)

    parseXML: function( data ) {
if ( typeof data !== "string" || !data ) {
return null;
}
var xml, tmp;
try {
if ( window.DOMParser ) { // Standard
tmp = new DOMParser();
xml = tmp.parseFromString( data , "text/xml" );
} else { // IE
xml = new ActiveXObject( "Microsoft.XMLDOM" );
xml.async = "false";
xml.loadXML( data );
}
} catch( e ) {
xml = undefined;
}
if ( !xml || !xml.documentElement || xml.getElementsByTagName( "parsererror" ).length ) {
jQuery.error( "Invalid XML: " + data );
}
return xml;
},

4.jQuery.globalEval( code )

用于在全局作用域中执行javascript代码

    globalEval: function( data ) {
if ( data && rnotwhite.test( data ) ) {
// We use execScript on Internet Explorer
// We use an anonymous function so that context is window
// rather than jQuery in Firefox
( window.execScript || function( data ) {
window[ "eval" ].call( window, data );
} )( data );
}
},

5.jQuery.camelCase(string)

转换连字符形式的字符串为驼峰式

6.jQuery.nodeName(elem, name)

用于检查节点名称是否与指定值相等,检查时忽略大小写

nodeName: function( elem, name ) {
return elem.nodeName && elem.nodeName.toUpperCase() === name.toUpperCase();
},

7. 数组操作方法

1.jQuery.makeArray(obj)

将类数组对象转换为真正的数组

// results is for internal usage only
makeArray: function( array, results ) {
var ret = results || []; if ( array != null ) {
// The window, strings (and functions) also have 'length'
// Tweaked logic slightly to handle Blackberry 4.7 RegExp issues #6930
var type = jQuery.type( array ); if ( array.length == null || type === "string" || type === "function" || type === "regexp" || jQuery.isWindow( array ) ) {
push.call( ret, array );
} else {
jQuery.merge( ret, array );
}
} return ret;
},

2. jQuery.inArray(value, array[, fromIndex])

在数组中查找指定的元素并返回其下标,未找到则返回-1

/*
* elem: 要查找的值
* array: 被遍历的数组
* i: 指定开始查找的位置
* */
inArray: function( elem, array, i ) {
var len; if ( array ) {
if ( indexOf ) {
return indexOf.call( array, elem, i );
} len = array.length;
i = i ? i < 0 ? Math.max( 0, len + i ) : i : 0; for ( ; i < len; i++ ) {
// Skip accessing in sparse arrays
if ( i in array && array[ i ] === elem ) {
return i;
}
}
} return -1;
}

3. jQuery.merge(first, second)

用于合并两个数组的元素到第一个数组。

第一个参数也可以时类数组对象(即必须有整型属性length值)。

第二个参数可以是数组,类数组或者有连续整型属性的对象。

    merge: function( first, second ) {
var i = first.length,
j = 0; if ( typeof second.length === "number" ) {
for ( var l = second.length; j < l; j++ ) {
first[ i++ ] = second[ j ];
} } else {
while ( second[j] !== undefined ) {
first[ i++ ] = second[ j++ ];
}
} first.length = i; return first;
},

4.jQuery.grep(array, function(elemOfArray, indexInArray)[, invert])

用于查找数组中满足过滤函数的元素,原数组不受影响。如果invert没有传入,或者传入false.

元素只有在过滤函数返回true时,才会被保存在最终的结果中。如果传入true情况相反。

    grep: function( elems, callback, inv ) {
var ret = [], retVal;
inv = !!inv; // Go through the array, only saving the items
// that pass the validator function
for ( var i = 0, length = elems.length; i < length; i++ ) {
retVal = !!callback( elems[ i ], i );
if ( inv !== retVal ) {
ret.push( elems[ i ] );
}
} return ret;
},

8. jQuery.proxy()

    // Bind a function to a context, optionally partially applying any
// arguments.
proxy: function( fn, context ) {
if ( typeof context === "string" ) {
var tmp = fn[ context ];
context = fn;
fn = tmp;
} // Quick check to determine if target is callable, in the spec
// this throws a TypeError, but we will just return undefined.
if ( !jQuery.isFunction( fn ) ) {
return undefined;
} // Simulated bind
var args = slice.call( arguments, 2 ),
proxy = function() {
return fn.apply( context, args.concat( slice.call( arguments ) ) );
}; // Set the guid of unique handler to the same of original handler, so it can be removed
proxy.guid = fn.guid = fn.guid || proxy.guid || jQuery.guid++; return proxy;
},

9. jQuery.access()

为集合中的元素设置一个或者多个属性值,或者读取第一个元素的属性值。

jquery 1.7.2源码解析(二)构造jquery对象的更多相关文章

  1. jQuery 源码解析二:jQuery.fn.extend=jQuery.extend 方法探究

    终于动笔开始 jQuery 源码解析第二篇,写文章还真是有难度,要把自已懂的表述清楚,要让别人听懂真的不是一见易事. 在 jQuery 源码解析一:jQuery 类库整体架构设计解析 一文,大致描述了 ...

  2. Mybatis源码解析(二) —— 加载 Configuration

    Mybatis源码解析(二) -- 加载 Configuration    正如上文所看到的 Configuration 对象保存了所有Mybatis的配置信息,也就是说mybatis-config. ...

  3. RxJava2源码解析(二)

    title: RxJava2源码解析(二) categories: 源码解析 tags: 源码解析 rxJava2 前言 本篇主要解析RxJava的线程切换的原理实现 subscribeOn 首先, ...

  4. Sentinel源码解析二(Slot总览)

    写在前面 本文继续来分析Sentinel的源码,上篇文章对Sentinel的调用过程做了深入分析,主要涉及到了两个概念:插槽链和Node节点.那么接下来我们就根据插槽链的调用关系来依次分析每个插槽(s ...

  5. Celery 源码解析三: Task 对象的实现

    Task 的实现在 Celery 中你会发现有两处,一处位于 celery/app/task.py,这是第一个:第二个位于 celery/task/base.py 中,这是第二个.他们之间是有关系的, ...

  6. 解析jQuery中extend方法--源码解析以及递归的过程《二》

    源码解析 在解析代码之前,首先要了解extend函数要解决什么问题,以及传入不同的参数,会达到怎样的效果.extend函数内部处理传入的不同参数,返回处理后的对象. extend函数用来扩展对象,增加 ...

  7. jQuery 源码解析(二十八) 样式操作模块 scrollLeft和scrollTop详解

    scrollLeft和scrollTop用于获取/设置滚动条的,如下: scrollLeft(val) ;读取或设置整个页面的水平滚动条距离 scrollTop(val) ;读取或设置整个页面的垂直滚 ...

  8. iOS即时通讯之CocoaAsyncSocket源码解析二

    原文 前言 本文承接上文:iOS即时通讯之CocoaAsyncSocket源码解析一 上文我们提到了GCDAsyncSocket的初始化,以及最终connect之前的准备工作,包括一些错误检查:本机地 ...

  9. Common.Logging源码解析二

    Common.Logging源码解析一分析了LogManager主入口的整个逻辑,其中第二步生成日志实例工厂类接口分析的很模糊,本随笔将会详细讲解整个日志实例工厂类接口的生成过程! (1).关于如何生 ...

  10. erlang下lists模块sort(排序)方法源码解析(二)

    上接erlang下lists模块sort(排序)方法源码解析(一),到目前为止,list列表已经被分割成N个列表,而且每个列表的元素是有序的(从大到小) 下面我们重点来看看mergel和rmergel ...

随机推荐

  1. poj3162 树形dp|树的直径 + 双单调队列|线段树,好题啊

    题解链接:https://blog.csdn.net/shiqi_614/article/details/8105149 用树形dp是超时的,, /* 先求出每个点可以跑的最长距离dp[i][0|1] ...

  2. lsattr chattr 文件安全设置

    [root@test_android_client_download xianlaigames]# lsattr -------------e- ./jilinmj.apk[root@test_and ...

  3. 矩阵乘法的运算量计算(华为OJ)

    题目地址: https://www.nowcoder.com/practice/15e41630514445719a942e004edc0a5b?tpId=37&&tqId=21293 ...

  4. mongodb 安装时错误

    1.安装MongoDB进度条长时间不动 根据在网上搜的步骤安装mongoDB到这步,就基本上卡死不动,在网上查到的办法是死等,等了半个小时,但运气不好半个小时也不一定安装成功. 如果进行到这步,卡死在 ...

  5. MyBatis - 2.全局文件配置

    1.properties 属性 <!--properties 引入外部配置文件 properties 的内容 resource: 引入类路径资源 url: 引入网络资源 --> <p ...

  6. web页在微信中访问增加遮罩层 右上角弹出在浏览器中打开

    https://blog.csdn.net/zgsdzczh/article/details/79744838 web页在微信中访问增加遮罩层 右上角弹出在浏览器中打开   <style typ ...

  7. 一脸懵逼学习Java操作Excel之POI(Apache POI)

    Apache POI是Apache软件基金会的开放源码函式库,POI提供API给Java程序对Microsoft Office格式档案读和写的功能. 1:下面简单的程序来创建一个空白Microsoft ...

  8. (转载)dotnet core 中文乱码 codepages

    引子 转载自:http://www.jianshu.com/p/1c9c59c5749a 参考:.Net Core 控制台输出中文乱码 上文中我查阅了一些cli的源码, 闲来无事就继续翻代码, 冥冥之 ...

  9. noip2012

    题解: 闲着无聊做了一遍noip2012 我觉得出题出的好奇怪啊... 为什么两道倍增两道二分答案??? 两天第一题: 第一天第一题傻逼普及组题没什么好说的了 第二天第一题你会扩欧就秒了 两天第二题: ...

  10. MyBatis的Mapper接口以及Example的实例函数及详解

    来源:https://blog.csdn.net/biandous/article/details/65630783 一.mapper接口中的方法解析 mapper接口中的函数及方法 方法 功能说明 ...