zoukankan      html  css  js  c++  java
  • jquery源码之工具方法

    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;
    };
    

      

      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 );
    	},
      

       

       接下是最最私有的一个方法,可能除了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;
    	}
    

      

    绕了这么远,其实就是想说,$.extend, $.each, $.access在jquery的构建过程中出现频率比较高。

    还有一些类别判断,数组操作的比较常见的就没列出来了。

    其实说到 $.each 就不得不提传说中的'高阶函数'了。

    '高阶函数'只是将函数作为参数或返回值的函数。

    这只是描述高阶函数的表现形式。

    个人理解,高阶函数是依赖普通函数的一种抽象行为,//高阶函数是提供另类抽象行为的一种接口,

    就比如说 $.each(obj, fn);

    obj在这表示的是可遍历的对象或队列,

    fn则是遍历时的过滤方法,

    对于obj,each就是可定制遍历行为(fn)的接口。

  • 相关阅读:
    JOptionPane&&Exception的使用
    CppUnit在VS2010上的正确使用
    怎样认识比你优秀的人并和他们成为朋友呢?
    二十岁出头的时候上,你一无所有,你拥有一切。
    C语言实现文件复制
    关于二维数组可以开多大
    exit(0)与exit(1)、return区别
    学语言究竟学什么?
    当oracle出现 格式与字符串格式不匹配解决办法
    javascript的系统函数
  • 原文地址:https://www.cnblogs.com/w2154/p/4564987.html
Copyright © 2011-2022 走看看