• javascript笔记:临摹jQuery(二)


      在我前一篇博客里有位童鞋问了xQuery.fn.init.prototype = xQuery.fn;写法的目的,这个问题在我临摹jQuery时候也碰到过,最开始我是没有加入这个方法,在firebug里面,方法console.log(xQuery('').xquery);打印出的结果是:undefined,这就表明xquery属性根本就没有定义,我构建的xQuery对象只是保留了在xQuery.fn.init(selector,context);里面存在的属性,如是我做了下面的测试:

    xQuery.fn = xQuery.prototype = {
    	init:function(){
    		return this;
    	},
    	tempquery:'1.0.1',
    	length:23,
    	size:function(){
    		return this.length;
    	}
    };
    
    console.log(xQuery().tempquery);//undefined
    console.log(xQuery().length);//undefined
    console.log(xQuery().size());//error:xQuery().size is not a function
    

      那么xQuery.fn.init.prototype = xQuery.fn;作用到底是怎样的?我做了下面一系列的测试:

      测试一:对于代码:

       

    	var xQuery = function(selector,context){
    		return new xQuery.fn.init(selector,context);
    	}
    

       这是使用了javascript里面的工厂模式构建对象,只不过这个工厂比较特别,让人第一眼觉得是个迭代的调用的工厂模式,因此我写了下面的测试代码:

    var xQuery = function(){
    	return new tempQuery();
    };
    var tempQuery = function(){};
    tempQuery.prototype = {
    	tempquery:'1.0.1',
    	length:4,
    	size:function(){
    		return this.length;
    	}
    };
    
    console.log(xQuery().tempquery);//1.0.1
    console.log(xQuery().length);//4
    console.log(xQuery().size());//4
    console.log(xQuery() instanceof xQuery);//false
    

      这里我另起了一个对象tempQuery ,初始化了tempQuery 的原型链的属性,那么每次调用xQuery()就是在使用作为xQuery构造函数返回值的tempQuery 对象。如果这么做,就存在了javascript里工厂模式的缺点了:1.会产生重复的相似对象,造成系统资源的浪费;2.xQuery对象识别的问题(例如:console.log(xQuery() instanceof xQuery);//false)。

      要解决这些问题,那么xQuery的构造函数应该是构造自己本身,而不是每次构造都是一个新的对象,这样的思路就能避免javascript工厂模式的缺陷,因此我又做了下面测试。

      测试二:

    var xQuery = function(){
           return	new xQuery();//too much recursion new xQuery();//too much recursion,无限递归调用 
    };
    
    xQuery.prototype = {
    	tempquery:'1.0.1',
    	length:8,
    	size:function(){
    		return this.length;
    	}
    };
    
    console.log(xQuery().tempquery);
    console.log(xQuery().length);
    console.log(xQuery().size());
    console.log(xQuery() instanceof xQuery);
    

      最终的结果是会在new xQuery();代码处报出too much recursion new xQuery();//too much recursion,无限递归调用 的错误,也就是所谓的内存溢出了。这种写法真白痴,如果不是为了验证结果,我不会去写这么明显的递归调用的代码的。

      那么有什么更好的写法了,如是我再看看jQuery源码,发现它是使用到了prototype原型链来构造xQuery对象。因此就有下面测试代码:

      测试三:

    var xQuery = function(){
    	return new xQuery.prototype.init();
    };
    xQuery.prototype = {
    	init:function(){
    		return this;
    	},
    	tempquery:'1.0.1',
    	length:8,
    	size:function(){
    		return this.length;
    	}	
    };
    
    console.log(xQuery().tempquery);//undefined
    console.log(xQuery().length);//undefined
    console.log(xQuery() instanceof xQuery);//false
    console.log(xQuery().size());//xQuery().size is not a function
    

      这种写法就没有报内存溢出的错误了,不过也没有达到我们预期的效果xQuery().tempquery和xQuery.length都是undefined,xQuery() 的类型也不是xQuery,size()还没有定义(这个我和文章前面没写xQuery.fn.init.prototype = xQuery.fn;的情况一样),为什么会有这样的结果了?其实从javascript对象的理论老理解这种结果就很简单了。原因分析如下:

      我们知道javascript里面除了string,boolean等基本类型外其他都是object(对象),而对象的名称只是该对象的在栈内存中的地址,换种说法就是该对象的引用。其实我们程序中的return new xQuery.prototype.init();这个只是调用了xQuery.prototype.init();这个引用的所对应的对象,其他的对象里的属性都没管,也就是说代码里的:

    	size:function(){
    		return this.length;
    	}
    

    还没有被调用过,所以我们看到报了size is not a function的错误。呵呵,是不是被我说糊涂了啊,其实这里我们还要了解一个javascript里面的一个知识,javascript是一个脚本语言,他和C、java在编译,运行上有很大不同。javascript里面如果我们定义一个function,例如:

    var ftn = function(){
         alert('Hello World');
    }
    

      页面加载时候,浏览器里面的javascript解释器只是生命了ftn变量,这个过程叫做javasript的预编译,这时候的ftn = undefined,当我们new ftn();时候,也就是我们运行js代码时候,javascript解释器是先编译再执行,而return new xQuery.prototype.init();只是运行了init()对象,而size还没运行,所以运行结果就是size is not a function的错误。
      那么要解决这个问题,我们只要在return new xQuery.prototype.init();时候同时让xQuery.prototype其他代码也运行起来,那么上面的问题不是就解决了吗?

      如是我做了第四个测试。

      测试四:

    var xQuery = function(){
    	return new xQuery.prototype.init();
    };
    xQuery.prototype = {
    	init:function(){
    		return this;
    	},
    	tempquery:'1.0.1',
    	length:8,
    	size:function(){
    		return this.length;
    	}	
    };
    xQuery.prototype.init.prototype = xQuery.prototype;
    
    
    console.log(xQuery().tempquery);//1.0.1
    console.log(xQuery().length);//8
    console.log(xQuery() instanceof xQuery);//true
    console.log(xQuery().size());//8
    

      哈哈,这不就是jQuery的效果啊。我把xQuery.prototype.init引用对应的对象的prototype原型链指向了xQuery.prototype,那么构建 new xQuery.prototype.init();
    时候xQuery.prototype 也同样被构造了,那么我在init里面修改和init平级的属性,效果如何了?

      测试五:

    var xQuery = function(){
    	return new xQuery.prototype.init();
    };
    xQuery.prototype = {
    	init:function(){
    		this.length = 10001;
    		this.tempquery = '1.6.1';
    		return this;
    	},
    	tempquery:'1.0.1',
    	length:8,
    	size:function(){
    		return this.length;
    	}	
    };
    xQuery.prototype.init.prototype = xQuery.prototype;
    

    结果:

    console.log(xQuery().tempquery);//1.6.1
    console.log(xQuery().length);//10001
    console.log(xQuery() instanceof xQuery);//true
    console.log(xQuery().size());//10001
    

      这就说明this指针指向的对象是同一个xQuery对象,表明xQuery.prototype也被构建了。不过上面的写法似乎和jQuery的写法还是有所不同,不过效果一样了哈。

      jQuery里面的jQuery.fn真是没啥好说的,只是jQuery的开发者觉得jQuery.prototype太长了为了节省代码而将jQuery.fn作为jQuery.prototype的别名,下面我把代码修改成jQuery的样式,最终代码如下:

    var xQuery = function(){
    	return new xQuery.prototype.init();
    };
    xQuery.fn = xQuery.prototype = {
    	init:function(){
    		this.length = 10001;
    		this.tempquery = '1.6.1';
    		return this;
    	},
    	tempquery:'1.0.1',
    	length:8,
    	size:function(){
    		return this.length;
    	}	
    };
    xQuery.fn.init.prototype = xQuery.fn;
    
    
    console.log(xQuery().tempquery);//1.6.1
    console.log(xQuery().length);//10001
    console.log(xQuery() instanceof xQuery);//true
    console.log(xQuery().size());//10001
    

      总结下吧:本来我想说这就是jQuery架构的核心,写完后发现其实不然,所以这里的总结只是说jQuery源码里的代码技巧性很高,我下篇博客打算暂停下分析jQuery源码,而将一些基础知识系统的讲解下,javascript是一个常常让人蒙掉的语言,就是它有很多非常规诡异的语法,或许这些大伙都清楚,但是时不时的温故而知新还是相当有好处的。



     

  • 相关阅读:
    刚装的ESET NOD32无法更新
    借ISA东风,安全发布多个网站
    ASP.NET写入XML访问被拒绝
    ADOBE CS3 序列号
    IEPLUS(IE增强性插件)
    joomla 1.5 笔记
    joomla与drupal内核差异分析
    Drupal修改默认后台地址(D6)
    drupal7指定menu高亮问题
    Drupal6 邮件群发到指定角色
  • 原文地址:https://www.cnblogs.com/sharpxiajun/p/2186557.html
Copyright © 2020-2023  润新知