zoukankan      html  css  js  c++  java
  • javascript笔记:临摹jQuery(一)

      多年的软件开发经验让我知道,做技术不管怎么看都不如做一下,就算是读源码,也不应该只是读,更多还是动手练习,做的时候身临其境体会大师们设计的巧妙。

      临摹就是一个很不错的练习方式,大学读书时候我的专业是工业设计,大一大二有很多素描色彩课,那时候老师总是布置临摹的作业,当时自己悟性太低,把临摹当做抄袭,很少动脑筋去思考临摹到底是咋回事,现在做软件了,想临摹jQuery的框架时候才发现,这是件非常困难的事情,真正的临摹是要领悟作者的思路,只有理解了作者为什么这么做,才知道如何去临摹作者的作品。

      好了不说这些华而不实的大话了。上篇博文里我通过学习javascript正则表达式,读了下jQuery里面选择造器的代码,通过传入到jQuery里面参数的不同,分析了下jQuery选择器整个代码的运行,但是如果只是做到这些,上篇文章的大众意义就比较差了,很难让人理解jQuery到底为什么会设计选择器,选择器在jQuery里的地位等等。所以前一篇对jQuery源码的分析有点断章取义,所以我今天查阅了一些资料,也静下心来好好琢磨了下jQuery的框架,根据以前调试程序的经验,我想深入理解jQuery,第一步就是要明白jQuery对象是如何构造的。

      我研究的主要是jquery-1.4.1.js,这是我使用最多的一个版本,而且我经常使用的帮助文档也是这个版本的,另外一个是jquery-1.6.1.js,这个做为1.4.1的配合版本,通过比较二者差异来体会作者在改进jquery的着力点在哪里,其次我手头的资料都是用jquery-1.2.x.js作为分析对象。我临摹时候讲jQuery的名称改为了xQuery,意思是扩展的jQuery,也标示它和原始的jQuery的某些不同(不同是指有时候我会根据代码的特点,讲1.4.1和1.61的代码进行混搭)。代码如下:

    (注意:我写的代码要在装有firebug的firefox里面运行)

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title> xQuery study</title>
    <script type="text/javascript">
    (function(window,undefined){
    	var document = window.document,navigator = window.navigator,location = window.location;
    
    	var xQuery = function(selector,context){
    		return new xQuery.fn.init(selector,context);
    	},
    	// 检测HTML代码,ID表达式
    	quickExpr = /^[^<]*(<[\w\W]+>)[^>]*$|^#([\w-]+)$/;
    
    	xQuery.fn = xQuery.prototype = {
    		constructor:xQuery,
    		init:function(selector,context){
    			var match,elem,ret,doc;
    			
    			//xQuery(''),xQuery(null),or xQuery(undefined);
    			if (!selector)
    			{
    				return this;
    			}
    			
    			//xQuery(DOMElement)
    			if (selector.nodeType)
    			{
    				this.context = this[0] = selector;
    				this.length = 1;
    				return this;
    			}
    			
    			// body元素在页面里面只会有一个,没必要遍历DOM进行查找,这是一个优化
    			// 写法,我是在jquery-1.6.1.js里面有下面的写法
    			if (selector === 'body' && !context && document.body)
    			{
    				this.context = document;
    				this[0] = document.body;
    				this.selector = selector;
    				this.length = 1;
    				return this;
    			}
    			
    			// 当selector是一个字符串的时候
    			if (typeof selector === 'string')
    			{
    				//首先我们要确定我们处理的字符串到底是HTML代码还是ID表达式
    				//在jquery-1.6.1里面,增加了一个对传入字符串开始结束字符是否都是
    				// <>的判断,如果是的话就不做正则表达式的校验了
    				if (selector.charAt(0) === "<" && selector.charAt(selector.length-1) === '>' && selector.length >= 3)
    				{
    					match = [ null, selector, null ];//match里面的值,参见我前一篇博文
    				}else{
    					match = quickExpr.exec( selector );
    				}
    				
    				//quickExpr.exec( selector );表达式执行的结果(详细解释参见上一篇博文)
    				//只有当selector字符是带有#号前缀字符串或者是字符串里包含有用<>包含的字符串时候
    				//match才不能为空,当selector是带#号的字符串时候,match[1]==undefined,而包含有
    				//用<>包含的字符串的时候match[1]是不为空的,因此下面的if...else...就清晰了
    				//注意:我研究的前提都是在context为空的情况下,因此!context一直都是true
    				if (match && (match[1] || !context))//当match不为空,在我研究前提下这个总为true
    				{
    					//这个if就是匹配上了有HTML语句以及有带#号的字符串的情况
    					if (match[1])//HTML语句
    					{
    						//这里的代码我现在还没读懂,所以不提供代码,统一返回this
    						return this;
    					}else{//xQuery("#id")的情况
    						//这里面的代码取自jquery-1.6.1
    						elem = document.getElementById(match[2]);
    						//下面是针对IE和Opera浏览器下的特别处理,因为在这两个浏览器的某些版本里
    						//document.getElementById有可能用name替代了ID
    						if ( elem && elem.parentNode )
    						{
    							// 在1.4.1里面是没有&& elem.parentNode,注释说这是针对黑莓手机的处理
    							//看来jQuery的触角已经延伸到了手机领域了,等我研究完javascript就研究
    							//android,那时再瞧瞧这些
    							if ( elem.id !== match[2] ) {
    							 //return rootjQuery.find( selector );
    							 //find方法还没仔细阅读,因此不提供代码,统一返回this
    							 return this;
    						    }
    							this.length = 1;
    							this[0] = elem;
    						}
    						this.context = document;
    						this.selector = selector;
    						return this;
    					}
    				}else if (!context && /^\w+$/.test( selector )){//这个是xQuery('div'),字符串是HTML标签
    					// 对于HTML标签是直接使用document.getElementsByTagName,但是这时候并没有返回jQuery对象
    					// 代码还会走到if (!context || context.xquery)里面再进行返回
    					this.selector = selector;
    					this.context = document;
    					selector = document.getElementsByTagName( selector );					
    				}else if (!context || context.xquery) {//xQuery('div .red'),xQuery('div')最终也是走到这个里面再进行return
    					//return (context || rootjQuery).find( selector );
    					//find方法还没仔细阅读,因此不提供代码,统一返回this
    					return this;
    				}else {//这个else是针对这样的情况xQuery(expr, context),就是context不为空的情况
    					//return jQuery( context ).find( selector );
    					//find方法还没仔细阅读,因此不提供代码,统一返回this
    					return this;
    				}	
    			}
    			
    			//其他代码省略,主要还没深入到某些jQuery方法里面,对某些方法的源码理解不够,这边先不写了
    			return this;//其他情况统一返回jQuery对象
    		},
    		selector:"",
    		xquery:"1.0",
    		length:0,
    		size:function(){
    			return this.length;
    		}
    	};
    	
    	xQuery.fn.init.prototype = xQuery.fn;
    	
    	window.xQuery = window.$ = xQuery;
    })(window);
    
    function main()
    {
    	console.log(xQuery(''));
    	console.log(xQuery(null));
    	console.log(xQuery(undefined));
    	console.log(xQuery('').xquery);
    	console.log(xQuery('') instanceof xQuery);
    	console.log(xQuery('#txt01'));
    	console.log(xQuery('#txt01')[0].value);
    	console.log(xQuery(document.getElementById('txt01')));
    	console.log(xQuery(document.getElementById('txt01'))[0].value);
    }
    
    //window.onload = main();//error
    </script>
    </head>
    <body>
    <form>
    	<input type="text" id="txt01" name="txt01" value="Test xQuery"/>
    	<input type="button" value="BTN" onclick="main()"/>
    </form>
    </body>
    </html>
    
     结果如下:

    另外我用jQuery实现同样的功能,代码如下:
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>jQuery Test</title>
    </head>
    
    <body>
    <form>
    	<input type="text" id="txt01" name="txt01" value="Test xQuery"/>
    	<input type="button" value="BTN" onclick="main()"/>
    </form>
    </body>
    </html>
    <script src="jquery-1.4.1.js"></script>
    <script type="text/javascript">
    function main()
    {
    	console.log(jQuery(''));
    	console.log(jQuery(null));
    	console.log(jQuery(undefined));
    	console.log(jQuery('').jquery);
    	console.log(jQuery('') instanceof jQuery);
    	console.log(jQuery('#txt01'));
    	console.log(jQuery('#txt01')[0].value);
    	console.log(jQuery(document.getElementById('txt01')));
    	console.log(jQuery(document.getElementById('txt01'))[0].value);
    }
    </script>
    
    结果如下:

    呵呵,能打印出具体值的结果是差不多的。
    我临摹的框架还不完善,但我自己觉得大致有jQuery的雏形了,现在满足的功能也比较有限,只有jQuery里面参数为jQuery(''),jQuery(null),jQuery(undefined),jQuery('#txt01'),jQuery(document.getElementById('txt01'))这些功能还是按照jQuery代码实现了,其他的参数因为这些代码还没有阅读,先不给出来,另外xQuery对象的也构建的不全,这些以后也会补充进去。
    不过上面的代码用javascript基础知识来分析,就能研究出很多有趣的特性,下面的几篇博文会围绕我这个不完善的代码进行详尽分析。分析完后,我接下逐步完善xQuery,让他和jQuery长得一模一样。
  • 相关阅读:
    [LintCode] 1563. Shortest path to the destination
    [LintCode] 1835. Number of Ways to Stay in the Same Place After Some Steps I
    [Algo] 140. Maximum Path Sum Binary Tree III
    [Algo] 141. Binary Tree Path Sum To Target III
    [LintCode] 597. Subtree with Maximum Average
    [LintCode] 596. Minimum Subtree
    [LC] 16. 3Sum Closest
    [Algo] 182. 2 Sum All Pair II
    [Algo] 181. 2 Sum All Pair I
    创建ORACLE 查询用户
  • 原文地址:https://www.cnblogs.com/sharpxiajun/p/2185566.html
Copyright © 2011-2022 走看看