http://www.imooc.com/code/3401

通过new操作符构建一个对象,一般经过四步:

A.创建一个新对象

  B.将构造函数的作用域赋给新对象(所以this就指向了这个新对象)

  C.执行构造函数中的代码

  D.返回这个新对象

最后一点就说明了,我们只要返回一个新对象即可。其实new操作符主要是把原型链跟实例的this关联起来,这才是最关键的一点,所以我们如果需要原型链就必须要new操作符来进行处理。否则this则变成window对象了。

下面这个例子,console结果一样。因为都用了new 。如果不用new就不一样了。

var $$ = ajQuery = function(selector) {
this.selector = selector;//this是aJquery {}name: "sss"__proto__: Object
return this
}
var ins = new $$("111");
console.log(ins);//
var $$2 = ajQuery2 = function(selector) {
this.selector = selector;
}
var ins2 = new $$2("2222");
console.log(ins2);//

去掉new 后。ajQuery里的return this就起了作用。

var $$ = ajQuery = function(selector) {
this.selector = selector;
return this
}
var ins = $$("111");
console.log(ins);//window
var $$2 = ajQuery2 = function(selector) {
this.selector = selector;
}
var ins2 = $$2("2222");
console.log(ins2);//undefined

我们常见的类式写法:

var $$ = ajQuery = function(selector) {
console.log(this instanceof ajQuery);//true ajQuery被new形式调用时,this就是ajQuery的实例
this.selector = selector;
return this
}
ajQuery.fn = ajQuery.prototype = {
selectorName:function(){
return this.selector;
},
constructor: ajQuery
}
var ins = new $$("111");
console.log(ins.selectorName());

首先改造jQuery无new的格式,我们可以通过instanceof判断this是否为当前实例

var $$ = ajQuery = function(selector) {
console.log(this);//先是window,再是ajQuery的实例
if(!(this instanceof ajQuery)){
return new ajQuery(selector);
}
this.selector = selector;
return this
}
ajQuery.fn = ajQuery.prototype = {
selectorName:function(){
return this.selector;
},
constructor: ajQuery
}
var ins = $$("111");
console.log(ins.selectorName());

注意千万不要像下面这样写:

var $$ = ajQuery = function(selector) {
this.selector = selector;
return new ajQuery(selector);
}
Uncaught RangeError: Maximum call stack size exceeded

这样会无限递归自己,从而造成死循环并且溢出。

jQuery为了避免出现这种死循环的问题,采取的手段是把原型上的一个init方法作为构造器。

function aJquery(selector){
return new aJquery.fn.init(selector);
}
aJquery.fn = aJquery.prototype = {
showName:function(){
console.log(this.name)
},
init: function(){
console.log(this);
}
}
var a = aJquery("sss");
a.showName();//报错

这样确实解决了循环递归的问题,但是又问题来了,init是ajQuery原型上作为构造器的一个方法,那么其this就不是ajQuery了,所以this就完全引用不到ajQuery的原型了(showName报错),所以这里通过new把init方法与ajQuery给分离成2个独立的构造器。

静态与实例方法共享设计

jQuery遍历方法:

$(".aaron").each()   //作为实例方法存在
$.each() //作为静态方法存在

这是最常见的遍历方法,第一条语句是给有指定的上下文调用的,就是(".aaron")获取的DOM合集,第二条语句$.each()函数可用于迭代任何集合,无论是“名/值”对象(JavaScript对象)或数组。在迭代数组的情况下,回调函数每次都会传递一个数组索引和相应的数组值作为参数。本质上来说2个都是遍历,那么我们是不是要写2个方法呢?

我们来看看jQuery的源码:

jQuery.prototype = {
each: function( callback, args ) {
return jQuery.each( this, callback, args );
}
}
var Newobj = function(name){
this.name = name;
}
Newobj.showName = function(args){//静态方法:不能被实例对象调用
console.log(args);
}
Newobj.prototype = {
showName: function(args){//实例方法
return Newobj.showName(this.name + args );
}
}
var s = new Newobj("sss");
s.showName("bbb");//sssbbb

实例方法取于静态方法,换句话来说这是静态与实例方法共享设计,静态方法挂在jQuery构造器上,原型方法挂在哪里呢?

我们上节不是讲了内部会划分一个新的构造器init吗?jQuery通过new原型prototype上的init方法当作构造器,那么init的原型链方法就是实例的方法了,所以jQuery通过2个构造器划分2种不同的调用方式一种是静态,一种是原型。

方法是共享的,并且实例方法取于静态方法,2个构造器是完全隔离的 ,这个要如何处理?

看看jQuery给的方案:

画龙点睛的一处init.prototype = jQuery.fn,把jQuery.prototype原型的引用赋给jQuery.fn.init.prototype的原型,这样就把2个构造器的原型给关联起来了。

ajQuery.fn = ajQuery.prototype = {
name: 'aaron',
init: function(selector) {
this.selector = selector;
return this;
},
constructor: ajQuery
}
ajQuery.fn.init.prototype = ajQuery.fn

这段代码就是整个结构设计的最核心的东西了,有这样的一个处理,整个结构就活了!不得不佩服作者的设计思路,别具匠心。

看看init的的构造图:

(单击图片查看大图)

通过原型传递解决问题,把jQuery的原型传递给jQuery.prototype.init.prototype。换句话说jQuery的原型对象覆盖了init构造器的原型对象,因为是引用传递所以不需要担心这个循环引用的性能问题。

var $$ = ajQuery = function(selector) {
//把原型上的init作为构造器
return new ajQuery.fn.init( selector );
}
ajQuery.fn = ajQuery.prototype = {
name: 'aaron',
init: function(selector) {
this.selector = selector;
return this;
},
constructor: ajQuery
}
ajQuery.fn.init.prototype = ajQuery.fn;
ajQuery.fn.foo = function () { alert("foo!"); };
ajQuery(".some-selector").foo();
//挂在ajQuery.fn上的实例方法变成了ajQuery(ajQuery.fn.init)上的原型方法

现在的ajQuery(".some-selector")

原型中有foo有init。

http://stackoverflow.com/questions/1755080/why-jquery-do-this-jquery-fn-init-prototype-jquery-fn

jQuery分离构造器的更多相关文章

  1. jQuery 源码分析 8: 回头看jQuery的构造器(jQuery.fn,jQury.prototype,jQuery.fn.init.prototype的分析)

    在第一篇jQuery源码分析中,简单分析了jQuery对象的构造过程,里面提到了jQuery.fn.jQuery.prototype.jQuery.fn.init.prototype的关系. 从代码中 ...

  2. 【深入浅出jQuery】源码浅析2--奇技淫巧

    最近一直在研读 jQuery 源码,初看源码一头雾水毫无头绪,真正静下心来细看写的真是精妙,让你感叹代码之美. 其结构明晰,高内聚.低耦合,兼具优秀的性能与便利的扩展性,在浏览器的兼容性(功能缺陷.渐 ...

  3. 解密jQuery事件核心 - 委托设计(二)

    第一篇 http://www.cnblogs.com/aaronjs/p/3444874.html 从上章就能得出几个信息: 事件信息都存储在数据缓存中 对于没有特殊事件特有监听方法和普通事件都用ad ...

  4. JQuery源码分析(五)

    分离构造器 通过new 操作符构建一个对象,一般经过四部:   A.创建一个新对象   B.将构造函数的作用域赋给新对象(所以this就指向了这个新对象)   C.执行构造函数中的代码   D.返回这 ...

  5. 【深入浅出jQuery】源码浅析2--使用技巧

    最近一直在研读 jQuery 源码,初看源码一头雾水毫无头绪,真正静下心来细看写的真是精妙,让你感叹代码之美. 其结构明晰,高内聚.低耦合,兼具优秀的性能与便利的扩展性,在浏览器的兼容性(功能缺陷.渐 ...

  6. jquery 使用整理机制

    短路表达式 与 多重短路表达式 短路表达式这个应该人所皆知了.在 jQuery 中,大量的使用了短路表达式与多重短路表达式. 短路表达式:作为"&&"和" ...

  7. jQuery源码浅析2–奇技淫巧

    最近一直在研读 jQuery 源码,初看源码一头雾水毫无头绪,真正静下心来细看写的真是精妙,让你感叹代码之美. 其结构明晰,高内聚.低耦合,兼具优秀的性能与便利的扩展性,在浏览器的兼容性(功能缺陷.渐 ...

  8. jQuery中对象的构建

    <!doctype html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  9. jQuery源码解读----part 2

    分离构造器 通过new操作符构建一个对象,一般经过四步: A.创建一个新对象 B.将构造函数的作用域赋给新对象(所以this就指向了这个新对象) C.执行构造函数中的代码 D.返回这个新对象 最后一点 ...

随机推荐

  1. Makefile中支持的函数大全

    一.描述 Makefile的函数调用,很像变量的使用,也是以"$"来标识的,其语法如下: $(<function> <arguments> ) 或是 ${& ...

  2. [Debug] Use Snippets to Store Behaviors in Chrome DevTools

    Using the Snippets tab in the source devtool you can define and run arbitrary pieces of code in your ...

  3. Java中字节与对象之间的转换

    近期公司里面用到了消息队列,而正如我们知道的是消息队列之间的是通过二进制形式的.以下就分享一下java中字节与对象之间的转换. 主要是用到了ByteArrayOutputStream和ObjectOu ...

  4. [array] leetCode-26. Remove Duplicates from Sorted Array - Easy

    26. Remove Duplicates from Sorted Array - Easy descrition Given a sorted array, remove the duplicate ...

  5. 17、网卡驱动程序-DM9000举例

    (参考:cs89x0.c可以参考) DM9000 芯片实现网络功能的基础,在接收数据时采用中断方式,即当有数据到来并在 DM9000 内部 CRC 校验通过后会产生一个接收中断: 网卡驱动程序框架: ...

  6. Hbase常见异常 分类: B7_HBASE 2015-02-02 16:16 412人阅读 评论(0) 收藏

    1. HBase is able to connect to ZooKeeper but the connection closes immediately hbase(main):001:0> ...

  7. 2016 Java程序员的年终总结(转)

    2016 Java程序员的年终总结 技术积累 (1)代码规范 1.1.1.通常的模块分布:一般如果你要实现一个web 应用,你从后台将数据展示到前端页面,在一个比较大的公司,你少不了跟其他项目有交集( ...

  8. Facebook Hacker Cup 2015 Round 1--Winning at Sports(动态规划)

    原题:pid=688426044611322&round=344496159068801">https://www.facebook.com/hackercup/problem ...

  9. JavaScript实现form表单的多文件上传

    form表单的多文件上传,具体内容如下 formData对象可以使用一系列的键值对来模拟一个完整的表单,然后使用Ajax来发送这个表单 使用<form>表单初始化FormData对象的方式 ...

  10. C++ 计算任意两个日期之间的天数

    C++写的一个计算两个日期之间天数的小程序: #include <Windows.h> #include <stdio.h> struct tagDate { int year ...