标签:
jQuery 作为时下前端的"霸主"。它的强大已毋庸置疑。简洁,效率,优雅,易用等优点让人很容易对它珍爱有加。
作为js的小菜,为了提升自我等级,根据各大神博客精辟的解析,硬啃了jQuery源码。在此,并不是要解析啥源码啥的(也没到那个级别哈),读书笔记,仅此而已。
所谓磨刀不误砍柴功,jQuery在大展神通之前也做了许多准备工作。比如说他的一些工具方法:
首当其冲的是他的继承扩展方法: jQuery.extend
其实也不是传统意义的继承,说mixin可能更恰当一些。
// 首先看看它的用法
// var a = {name:‘zhangsan‘, age:13}
// var b = {name:‘wangwu‘}
// $.extend(a, b)
// a; --> {name:‘wangwu‘,age:13}
// 显而易见,该方法会将后面的参数mixin到前面的参数。
// 如果不存在后续参数呢
// $.extend({hello:function(){alert(‘hello‘);}});
// $.hello() --> 好吧,糅杂到调用者身上了。
// 另外第一个参数也可能为 deep 是否深拷贝。
// 具体看源码吧
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] || {};
// 跳过参数boolean和已经替换为target的第二个参数 // skip the boolean and the target i = 2; } // 处理目标是一个string或者其他东西(可能出现在深度拷贝的情况中) 则初始化target
// Handle case when target is a string or something (possible in deep copy) if ( typeof target !== "object" && !jQuery.isFunction(target) ) { target = {}; } // 如果i为参数的长度,则将目标指向调用者,
// 即糅杂入调用者本身,通常用来扩展jquery
// extend jQuery itself if only one argument is passed if ( length === i ) { target = this; --i; } // 接下来for循环处理相关复制,深度拷贝可能还得递归调用本身,
// 最后返回target 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; };
接下来就是类别判断方法:
// Populate the class2type map
var class2type = {};
// each方法是自定义的多功能遍历方法
// 在这里的作用主要是生成对应的类型字典,用来给type方法查阅匹配类型
jQuery.each("Boolean Number String Function Array Date RegExp Object".split(" "), function(i, name) {
class2type[ "[object " + name + "]" ] = name.toLowerCase();
});
type: function( obj ) {
return obj == null ? String( obj ) : class2type[ core_toString.call(obj) ] || "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 if ( obj.constructor && !core_hasOwn.call(obj, "constructor") && !core_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. var key; for ( key in obj ) {} return key === undefined || core_hasOwn.call( obj, key ); }, isEmptyObject: function( obj ) { var name; for ( name in obj ) { return false; } return true; },
jquery.each很便捷的多功能遍历方法
// args is for internal usage only each: function( obj, callback, args ) { var name, i = 0, length = obj.length, isObj = length === undefined || jQuery.isFunction( obj ); // 主要针对 是否有参数 与 是否为对象,
// 如果是有参数,则传递参数,
// 否则如果是数组 则传递 index,val
// isObj 则传递 key, val
// 如果在遍历的过程中有返回false 则终止遍历。
if ( args ) { if ( isObj ) { for ( name in obj ) { if ( callback.apply( obj[ name ], args ) === false ) { break; } } } else { for ( ; i < length; ) { if ( callback.apply( obj[ i++ ], args ) === false ) { break; } } } // A special, fast, case for the most common use of each } else { if ( isObj ) { for ( name in obj ) { if ( callback.call( obj[ name ], name, obj[ name ] ) === false ) { break; } } } else { for ( ; i < length; ) { if ( callback.call( obj[ i ], i, obj[ i++ ] ) === false ) { break; } } } } return obj; },
同样与遍历有关的还有map, grep
这两个方法很简单,代码都是逻辑代码,根据功能很容易看懂
map 则为遍历数组或对象,返回过滤方法过滤的值并将不为空的值,添加入新数组。
grep 则是遍历数组或对象, 筛选出方法过滤指定值的选项,并添加入新数组。
merge: function( first, second ) { var l = second.length, i = first.length, j = 0; if ( typeof l === "number" ) { for ( ; j < l; j++ ) { first[ i++ ] = second[ j ]; } } else { while ( second[j] !== undefined ) { first[ i++ ] = second[ j++ ]; } } first.length = i; return first; }, grep: function( elems, callback, inv ) { var retVal, ret = [], i = 0, length = elems.length; inv = !!inv; // Go through the array, only saving the items // that pass the validator function for ( ; i < length; i++ ) { retVal = !!callback( elems[ i ], i ); if ( inv !== retVal ) { ret.push( elems[ i ] ); } } return ret; }, // arg is for internal usage only 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 ); },
// Bind a function to a context, optionally partially applying any
// arguments.
// 代理函数,即绑定作用域,
// 还可以传递指定数量的参数、
proxy: function( fn, context ) {
var tmp, args, proxy;
if ( typeof context === "string" ) {
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
args = core_slice.call( arguments, 2 );
proxy = function() {
return fn.apply( context, args.concat( core_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 || jQuery.guid++;
return proxy;
}
接下是最最私有的一个方法,可能除了jquery作者,谁也不知道能拿他干啥了(当然这只是小菜我的个人观点,可能我目光太浅,看不到作者深刻的主题思想)
access 百度翻译是:入口,出口; 接近,进入;
好吧,他可能是操作dom元素各种重载方法的统一入口了。
// Multifunctional method to get and set values of a collection // The value/s can optionally be executed if it‘s a function access: function( elems, fn, key, value, chainable, emptyGet, pass ) { var exec, bulk = key == null, i = 0, length = elems.length; // Sets many values if ( key && typeof key === "object" ) { for ( i in key ) { jQuery.access( elems, fn, i, key[i], 1, emptyGet, value ); } chainable = 1; // Sets one value } else if ( value !== undefined ) { // Optionally, function values get executed if exec is true exec = pass === undefined && jQuery.isFunction( value ); if ( bulk ) { // Bulk operations only iterate when executing function values if ( exec ) { exec = fn; fn = function( elem, key, value ) { return exec.call( jQuery( elem ), value ); }; // Otherwise they run against the entire set } else { fn.call( elems, value ); fn = null; } } if ( fn ) { for (; i < length; i++ ) { fn( elems[i], key, exec ? value.call( elems[i], i, fn( elems[i], key ) ) : value, pass ); } } chainable = 1; } return chainable ? elems : // Gets bulk ? fn.call( elems ) : length ? fn( elems[0], key ) : emptyGet; }
标签:
原文地址:http://www.cnblogs.com/w2154/p/4564987.html