2.1对象的构建
面向对象的语言都有一个特点,他们都会有类的这一概念,通过类可以抽象出创建具体相同方法与属性的对象。
函数在充当构造器时,原型prototype是一个重要的概念。prototype是构造函数的一个属性,该属性指向一个对象。而这个对象将作为该构造函数所创建的所有实例的基引用,可以把对象基引用想象成一个自动创建的隐藏属性。当访问对象的一个属性时,首先查找对象本身,找到则返回;若不则查找基引用指向的对象的属性(如果还找不到实际上还会沿着原型链向上查找,直至到根)。只要没有被覆盖的话,对象原型的属性就能在所有的实例中找到。
类一:
<span style="font-size:10px;"><span style="font-size:10px;">function ajQquery(){ this.name = 'jQuery'; this.sayName = function(){ return this.name; } } var a = new ajQquery(); var b = new ajQquery();</span></span>类二:
<span style="font-size:10px;">function ajQuery(){ this.name = 'jQuery'; } ajQquery.prototype = { sayName: function(){ return this.name; } } var a = new jQuery(); var b = new jQuery();</span>类一要为每个每个实例都复制一个sayName方法,每个方法都占用了一定的内存空间,所以把属性方法写在声明的构造函数中,会浪费很多空间。类二则三个实例对象则共享了原型的sayName方法。
jQuery = function(selector, context){ return new jQuery.fn.init(selector, context); } jQuery.fn = jQuery.prototype = { init: function(){ return this }, jquery: version, contructor: jQuery, ..... } var a = $();使用原型结构,性能上得到了优化。
2.2分离构造器
通过new操作符构建一个对象,一般经过四个步骤:
A.创建一个新对象
B.将构造函数的作用域链给新对象(所以this就指向了这个新对象)
C.执行构造函数中的代码
D.返回这个新对象
如果我们需要原型链就必须要new操作符来进行处理,主要是把原型链跟实例的this关联起来,否则this对象就变成window对象了。
var $$ = ajQuery = function(selector){ this.selector = selector; return this; } ajQuery.fn = ajQuery.prototype = { selectorName:function(){ return this.selector; }, construtor: ajQuery } var a = new $$('aaa'); a.selectorName();//aaa2.3静态与实例分享设计
画龙点睛之处:init.prototype = jQuery.fn,把jQuery.prototype原型的引用赋给jQuery.fn.init.prototype的原型,这样就把2个函数构造器的原型给关联起来了。
ajQuery.fn = ajQuery.prototype = { name:'Leeon', init: function(selector) { this.selector = selector; return this; }, constructor: jQuery; } ajQuery.fn.init.prototype = ajQuery.fn;通过原型传递解决问题,把jQuery的原型传递给jQuery.prototype.init.prototype。换句话说jQuery的原型对象覆盖了init构造器的原型对象。
2.4方法链式调用的实现
jQuery的这种管道风格的链式代码,总的来说:
A.节约JS代码;
B.所返回的都是同一个对象,可以提高代码的效率。
我们看一段链式代码:
end() 方法结束当前链条中的最近的筛选操作,并将匹配元素集还原为之前的状态。
$('input[type="button"]').eq(0).click(function(){ alert('点击我!'); }).end().eq(1).click(function(){ $('input[type="button"]:eq(0)').toggle('click'); }).end().eq(2).toggle(function(){ $('aa').hide('slow'); },function(){ $('aa').show('slow'); });跨浏览器的链式调用实现:简单扩展原型方法,return this的形式。
aQuery.prototype = {
init:function(){
return this;//返回当前实例的this,又可以访问自己的原型(节省代码量,提高代码效率)
}
name:function(){
return this;
}
}
缺点:所有对象都没有返回值,返回对象本身。
2.5插件接口的设计
jQuery插件的开发分为两种:
1>挂在jQuery命名空间下的全局函数,也可以称为静态方法;
2>jQUery对象级别的方法,即挂在jQuery原型下的方法,这样通过过滤选择器获取的jQuery对象实例也能共享该方法。
提供的接口:
$.extend(target, [object1], [objectN])
接口的使用:
jQuery.extend({//指向jQuery的构造器
data:function(){},
removeData:function(){}
})
jQuery.fn.extend({//指向jQuery构造器的实例对象 fn与jQuery是两个不同的对象,jQuery.fn.extend调用的时候,this指向了fn对象,jQuery.fn和jQuery.prototype
data:function(){},//指向同一对象,扩展fn也就是扩展prototyoe原型对象。所以增加的原型方法也就是对象的方法了。
removeData:function(){}
})
注:js上下文调用方式有方法调用模式、构造器模式、函数调用模式、apply调用模式
2.6回溯处理设计
比如说有有一个ul,里面有很多li,当我们给il绑定一个事件很简单,即aaron.find("li").click(function(){});,如果又想给父元素添加点击事件,又需要在arrion上绑定一次,会很麻烦,所以引入了一种简单的寻址机制,可以回溯到之前的Dom元素集合,通过end()方法实现。
addback()调用它在栈中回溯的位置,然后把两个位置的元素组合起来并把这个新的组合起来的元素推入到栈的上方。
2.7end与addback
end方法是回溯到上一个DOM合集,因此对于链式操作与优化,这个方法还是很有意义的。
源码实现:
end:function(){ return this.prevObject || this.constructor(null); }2.8栈和队列的操作
jQuery是模仿的数组结构,肯定需要一套类数组的方法。提供了:get()、:index()、:it()、:gt()、:even()、:odd()等这类索引值相关的筛选器。
get方法:通过检索匹配jQuery对象得到对应的DOM元素。如下代码实现“
get:function(num){ return num != null ? //Reuturn just the one element from the set (num < 0 ? this[num + this.length] : this[num]): //Return all the elements in a clean array slice.call(this); }由于数组的关系,所以有快速方法:
first : function(){ return this.eq(0); }, last : function(){ return this.eq(-1); },2.9get与eq的区别
.eq():减少匹配元素的集合,根据index索引值,精确指定索引对象
.get()通过检索jQuery对象得到对应的DOM元素
区别:
1>eq返回的是一个jQuery对象,get返回的是一个DOM对象。
<span style="white-space:pre"> </span>$("li").get(0).css("color", "red");//错误,返回的是DOM节点 $("li").eq(0).css("color", "red");//正确 var li = $("li").get(0); $(li).css("color", "red");//正确,将dom对象转变为jQuery对象,但是分两步很麻烦,建议用eq()eq()的实现原理:
eq(): function(i){ var len = this.length, j = +i + (i < 0 ? len : 0); return this.pushStack(j >= 0 && j < len ? [this[j]] : []); }eq()只能产生一个新对象,因为是数组,所以需要一个集合,可以用.slice(strat[, end]);
var arr = [];
arr.push(this.slice(strat[, end]));
this.pushStack(arr);
2.10迭代器
$.each()是一个典型的迭代器。可以传入额外的function。
迭代的特点:
1>访问一个集合对象的内容无需暴露它的内部。
2>为遍历不同的集合结构提供统一的接口,从而支持同样的算法在不同的集合结构上进行操作。
3>遍历的同时更改迭代器所在的集合结构可能会导致问题。
实现一个简单回调:
function each(obj, callback, context, arg){ var i = 0; var value; var length = obj.length; for(; i < length; i++){ callback.call(context || null, obj[i], arg); } } var arr = ['a', 'b', 'c']; each(arr, function(name, arg){ console.log(name, arg, this); }, this, 'aaa');
当根据回调的处理,从而判断是否要立刻中止这个循环,从而节约性能,也是很简单的,通过获取处理返回值即可。
function each(obj, callback, context, arg){ var i = 0; var value; var length = obj.length; for(; i < length; i++){ callback.call(context || null, obj[i], arg); if(value == false){ break; } } }2.11jQuery的each迭代器
$.each()函数用于迭代任何集合
$(selector).each()用来专门遍历一个jQuery对象的