构造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()
为集合中的元素设置一个或者多个属性值,或者读取第一个元素的属性值。
来源:https://www.cnblogs.com/Shadowplay/p/9773439.html