核心(我)的jQuery2.0.3源代码分析的整体架构
在开源框架中,最想学习的是设计理念和实现技巧。废话不说,这么多年的jQuery都写烂了,已经读过了,
但在过去的几年里,这是一个移动终端,把Zepto,最近花了一些时间来打扫jQuery再次。
我不会随声附和书上说的翻译来源,结合自己的实际阅读经验!
在GitHub上最新的是jQuery的主人,加入AMD的规范,我会把最新官方2.0.3
整体架构
jQuery框架的核心是匹配HTML文档中的元素并执行它的操作,
例如:
复制代码代码如下所示:
$()。find()Css()
$()隐藏()Html(…)。隐藏()。
上述方法至少可以找到2个问题。
1施工。jQuery对象
调用2.jquery方法
分析1:jQuery的非新构造
Javascript是一种函数式语言,函数可以是类,而类是面向对象编程中最基本的概念。
复制代码代码如下所示:
VaR查询=功能(选择器,上下文){
构造函数
}
aquery.prototype = { {
原型
名称:函数(){ },
年龄:函数(){ }
}
创建一个新的查询();
A.name();
这是通常使用它的方式,很明显jQuery没有这样玩。
jQuery不使用新的运行字符来实例化jQuery显示或直接调用它的函数。
根据jQuery的写作风格
复制代码代码如下所示:
$()Ready()
$()NoConflict()。
为了做到这一点,jQuery将被视为一个类,然后$()应该是返回类的一个实例。
所以改变代码:
复制代码代码如下所示:
VaR查询=功能(选择器,上下文){
返回新的查询();
}
aquery.prototype = { {
名称:函数(){ },
年龄:函数(){ }
}
通过新的查询(),但回归是一个例子,但也可以看到明显的问题,死循环!
那么如何返回正确的实例呢
在Javascript中,此实例仅与原型相关。
然后你可以使用作为一个创建一个实例并将此方法用于jquery.prototye原型工厂方法jQuery类
复制代码代码如下所示:
VaR查询=功能(选择器,上下文){
返回aquery.prototype.init();
}
aquery.prototype = { {
init:函数(){
返回此;
}
名称:函数(){ },
年龄:函数(){ }
}
当实例查询()返回执行:
It is clear that aQuery () returns an instance of the aQuery class, and then the this in init is actually an instance of the aQuery class pointing to it
问题是,它的这个点的查询类,如果init函数也可以用来作为一个构造函数,如何处理内部这吗
复制代码代码如下所示:
VaR查询=功能(选择器,上下文){
返回aquery.prototype.init();
}
aquery.prototype = { {
init:函数(){
this.age = 18
返回此;
},
名称:(函数){ },
年龄:20
}
查询()。年龄 / / 18
在这种情况下,它是错误的,因为这只指向查询类,所以你需要设计一个单独的范围
jQuery框架分隔范围的处理
复制代码代码如下所示:
函数(选择器,上下文){
jQuery对象实际上只是 / init constructor'enhanced
返回新的jquery.fn.init(选择器,语境,rootjquery);
},
很明显,每次构建一个新init实例对象都是通过构建一个新的init init函数来分离的,避免交互混乱。
所以既然不是同一个物体,就一定会有新的问题。
例如:
复制代码代码如下所示:
VaR查询=功能(选择器,上下文){
返回新的aquery.prototype.init();
}
aquery.prototype = { {
init:函数(){
this.age = 18
返回此;
},
名称:(函数){ },
年龄:20
}
/ /未捕获的错误类型:对象对象对象} {没有method'name
console.log(查询(),叫())
无法通过抛出错误找到该方法,因此很明显,新的init与jQuery类的此项分离。
如何访问jQuery类原型上的属性和方法
可以隔离jQuery原型对象的范围,并在返回实例中访问jQuery的原型对象。
实施要点
复制代码代码如下所示:
将init函数作为稍后实例化的原型。
jquery.fn.init.prototype = jquery.fn;
通过原型来解决问题,通过jQuery原型jquery.prototype.init.prototype
换句话说,jQuery的原型对象覆盖了init构造函数的原型对象。
因为它是一个被引用的性能问题,因此它不需要担心这个循环引用。
复制代码代码如下所示:
VaR查询=功能(选择器,上下文){
返回新的aquery.prototype.init();
}
aquery.prototype = { {
init:函数(){
返回此;
},
名称:函数(){
返回this.age
},
年龄:20
}
aquery.prototype.init.prototype = aquery.prototype;
console.log(查询(),叫()) / / 20
由百度网友绘制的地图,方便直观:
FN解释说,事实上,这个FN没有任何特殊的意义,只是一个参考jquery.prototype
分析二:链调用
链调用处理:
1。保存js代码。
2。返回的是同一个对象,这可以提高代码的效率。
跨浏览器链调用是通过简单地扩展原型方法并使用返回的形式实现的。
使用js下的简单工厂模式为同一DOM对象的所有操作指定相同的实例。
这个原理很简单。
复制代码代码如下所示:
查询()Init()的名字()。
分解
一个查询();
A.init()
A.name()
为了分解代码,很明显,链的基本条件是存在一个实例,这个实例和同一个实例。
复制代码代码如下所示:
aquery.prototype = { {
init:函数(){
返回此;
},
名称:函数(){
返回此
}
}
因此我们可以以链式方式访问这个,因为我们返回到当前实例的这个,然后我们可以访问自己的原型。
复制代码代码如下所示:
AQuery.init()的名字()。
优点:节省代码,提高代码效率,看起来更优雅。
最糟糕的是,对象的所有方法都返回到对象本身,也就是说,没有返回值,这在任何环境中都不一定是合适的。
javascript是一种非阻塞语言,所以他没有被阻塞,但是不能被阻塞,所以他需要通过事件驱动,一些需要完成异步阻塞的进程操作,这个处理是同步链,异步链jQuery从一开始就承诺从1.5,jQuery推迟讨论。
分析三:插件接口
这是jQuery的主要框架,但根据设计者的习惯,如果你想jquery jQuery原型或如果您要添加属性的方法,也为开发者提供扩展的方法,从包装的角度不应该是一个接口来读取是字面的可扩展功能,但它不是直接修改用户友好的界面原型,
jQuery支持自己的扩展属性,它提供了一个接口jquery.fn.extend()向对象添加方法
正如你可以看到从jQuery的源代码,jquery.extend和jquery.fn.extend实际上是不同的参考方法
复制代码代码如下所示:
jquery.extend = jquery.fn.extend =函数(){()
jquery.extend扩展jQuery本身的属性和方法
jquery.fn jquery.fn.extend扩展的属性和方法
通过扩展()函数,可以快速、快速地扩展功能,不会破坏jQuery的原型结构。
jquery.extend = jquery.fn.extend =函数(){…};这是一个连接,即2点,相同的功能,不同的功能如何实现这就是这个的力量!
FN和jQuery实际上是2个不同的对象:
当jquery.extend称,这是针对jQuery对象(jQuery是一个函数,和对象的对象!所以,它扩展到jQuery。
当jquery.fn.extend电话,这一点与FN的对象,jquery.fn和jquery.prototype指向同一对象,扩展FN是jquery.prototype原型对象的扩展。
这里是原型方法的添加,也就是对象方法,所以jQuery的API提供了上述2个扩展函数。
实施扩大
复制代码代码如下所示:
jquery.extend = jquery.fn.extend =函数(){()
VaR的SRC,copyisarray,拷贝,名称,选择克隆,
目标=论点{ 0 } { } / / | |,常用的jquery.extend(obj1,obj2),此时,目标参数{ 0 }
我= 1,
长度= arguments.length,
深=假;
深拷贝情况
如果(typeof目标=布尔){ / /如果第一个参数是真实的,即jquery.extend(真的,obj1,obj2);。
深=目标
目标=论点{ 1 } | | { }; / /目标obj1
布尔值和目标跳过
我= 2;
}
当目标是字符串或其他东西时(可能是深拷贝)
如果(typeof = =对象的目标!jquery.isfunction!(目标)){ / /面对陌生的情况,如jquery.extend(你好{尼克:'casper })。
目标{ };
}
如果只传递一个参数,则扩展jQuery本身。
如果(长度=我){ / /这种情况下jquery.extend(obj),或jquery.fn.extend(obj)
目标为本; / / jquery.extend,这是jQuery;jquery.fn.extend,这是jquery.fn
——我;
}
为(;;i;<长度;i + +){
处理非空的/未定义的值
如果(选项=参数{ })!= null){ / /如jquery.extend(obj1,obj2,OBJ3,ojb4),选择obj2,OBJ3…
基本对象扩展
对于(选项中的名称){
目标= { };
复制=选项{名称};
永不终止循环
如果(目标=复制)防止自我引用,请不要详细说明。
继续;
}
递归如果我们合并普通的对象或数组
如果它是深度复制,复制和属性值本身就是一个对象。
如果(深拷贝(jquery.isplainobject(复印件)| |(copyisarray = jquery.isarray(副本)))){
如果(copyisarray){ / /复制属性的值是一个数组
copyisarray = false;
钢骨混凝土(SRC)克隆= jquery.isarray SRC:{ };
{ }其他属性值,复制是一个plainobject,如{尼克:'casper}
钢骨混凝土(SRC)克隆= jquery.isplainobject SRC:{ };
}
移动原始的 /不存在对象,克隆它们
目标{名称= jquery.extend(深、克隆、复制); / /递归。
输入未定义的值
否则如果}(副本)!=未定义的)浅拷贝,属性值未定义。
目标{ } =复制;
}
}
}
}
修改后的对象返回
将目标;
总结:
建筑与新jquery.fn.init初始化构造函数的原型对象的新对象的方法()
通过改变该prorotype指针的方向,新的对象也指向jQuery类原型
因此,建立继续这样的所有方法jquery.fn原型定义的对象