例如,在下面示例中,jQuery 原型对象中包含一个 length 属性,同时 init() 从一个普通的函数转身变成了构造器,它也包含一个 length 属性和一个 test() 方法。运行该示例,我们可以看到,this 关键字引用了 init() 函数作用域所在的对象, 此时它访问 length 属性时,返回0. 而 this 关键字也能够访问上一级对象 jQuery.fn 对象的作用域,所以 $().jquery 返回 "1.3.2" 。但是调用 $().size() 方法时,返回的是 0, 而不是 1 。
[html] view plain
这种设计思路很容易破坏作用域的独立性,对于 jQuery 这样的框架来说,很可能会造成消极影响。因此,我们可以看到 jQuery 框架是通过下面的方式调用 init() 初始化构造函数的。<script type="text/javascript">
var $ = jQuery = function(){
return new jQuery.fn.init(); // 实例化 init 初始化类型,分隔作用域
};
</script>
这样就可以把 init() 构造器中的 this 和 jQuery.fn 对象中的 this 关键字隔离开来,避免相互混淆。但是,这种方式也会带来另一个问题:无法访问 jQuery.fn 对象的属性或方法。例如,在下面的示例中,访问 jQuery.fn 原型对象的 jquery 属性和 size() 方法时就会出现这个问题。
[html] view plain
2.2.4 生长 -- 跨域访问如何做到既能够分隔初始化构造器函数与 jQuery 原型对象的作用域,又能够在返回实例中访问 jQuery 原型对象呢?
jQuery 框架巧妙地通过原型传递解决了这个问题,它把 jQuery.fn 传递给 jQuery.fn.init.prototype ,也就是说用 jQuery 的原型对象覆盖 init 构造器的原型对象,从而实现跨域访问,其代码如下所示。
[html] view plain
这是一招妙棋,new jQuery.fn.init() 创建的新对象拥有 init 构造器的 prototype 原型对象的方法,通过改变 prototype 指针的指向,使其指向 jQuery 类的 prototype ,这样创建出来的对象就继承了 jQuery.fn 原型对象定义的方法。
2.2.5 成熟 -- 选择器jQuery 返回的是 jQuery 对象,jQuery 对象是一个类数组的对象,本质上它就是一个对象,但是它拥有数组的长度和下标,却没有继承数组的方法。
很显然,上面几节的讲解都是建立在一种空理论基础上的,目的是希望读者能够理解 jQuery 框架的核心构建过程。下面,我们就尝试为 jQuery() 函数传递一个参数,并让它返回一个 jQuery 对象。
jQuery() 函数包含两个参数 selector 和 context ,其中 selector 表示选择器,而 context 表示选择的内容范围,它表示一个 DOM 元素。为了简化操作,我们假设选择器的类型仅限定为标签选择器。实现的代码如下所示。
[html] view plain
在上面示例中,$("div") 基本拥有了 jQuery 框架中 $("div") 语法的功能,使用它可以选取页面中指定范围的 div 元素。同时,调用 size() 方法可以返回 jQuery 对象集合的长度。