首页 > 代码库 > 由Jquery创建对象引发的思考

由Jquery创建对象引发的思考

问题1 Jquery 中创建对象的奥秘
问题2 JavaScript中this的指向问题
问题3 return this 的作用
问题4 instanceof / 对象和类之间的关系


//代码1(Jquery 创建对象)

var iQuery=function (){name="iQuery"; //4return new iQuery.prototype.init(); //1};iQuery.prototype={init : function(){name="iQueryPrototypeInit"; //5return this; //2},name : "iQueryPrototype" //6};iQuery.prototype.init.prototype=iQuery.prototype; //3

这时我有问题了,//1 处有无new 的区别。//2 处有无 return this 的区别。 //3处的作用

在这里我通过对//代码1 进行分解来回答 问题1 到 问题4

//代码2 我将//代码1 中的 //3 处去掉 //2 处去掉 //1 处去掉

var iQuery=function (){name="iQuery";return iQuery.prototype.init();};iQuery.prototype={init : function(){name="iQueryPrototypeInit"; //5},name : "iQueryPrototype"};iQuery().name; //结果为 VM105:1 Uncaught TypeError: Cannot read property ‘name‘ of undefined(…)

分析: iQuery.prototype.init() 是调用了init函数,由于函数没有返回值,所以只返回了控制

所以 return iQuery.prototype.init() 也没有返回值 所以 iQuery().name;会有以上错误提示


//代码3

var iQuery=function (){name="iQuery"; //4return new iQuery.prototype.init(); //1};iQuery.prototype={init : function(){name="iQueryPrototypeInit"; //5},name : "iQueryPrototype" //6};iQuery().name; //结果为 undefined 这里并不提示错误,而是说name没有定义;

分析: //4处 name为iQuery 的局部变量,//5 处name是init的局部变量 执行 iQuery()

时创建了一个init的对象,这时init是构造函数,执行时流程
1 创建一个对象
2 返回新建的对象
这就是有无 new 的区别


//代码4 多了个this

var iQuery=function (){name="iQuery"; //4return new iQuery.prototype.init(); //1};iQuery.prototype={init : function(){this.name="iQueryPrototypeInit"; //5},name : "iQueryPrototype" //6};iQuery().name; //结果为 iQueryPrototypeInit

分析: 执行 iQuery().name;执行流程

1 创建一个对象
2 让 this 引用这个对象
3 为 this 所引用的对象添加属性 name
4 返回 this 所引用的对象
iQuery() instanceof iQuery //false
iQuery() instanceof iQuery.prototype //VM125:1 Uncaught TypeError: Right-hand side of ‘instanceof‘ is not callable(…)
说 iQuery.prototype 是一个对象 instanceof 右边必须是类,即函数名
iQuery() instanceof iQuery.prototype.init; //true
这里调用 iQuery() 是创建了init的一个对象。


//代码5 多了//2

var iQuery=function (){name="iQuery"; //4return new iQuery.prototype.init(); //1};iQuery.prototype={init : function(){this.name="iQueryPrototypeInit"; //5return this; //2},name : "iQueryPrototype" //6};iQuery().name; //结果为 iQueryPrototypeInit

分析: 执行 iQuery().name;执行流程

1 创建一个对象
2 让 this 引用这个对象
3 为 this 所引用的对象添加属性 name
4 返回 this 所引用的对象
iQuery() instanceof iQuery //false
iQuery() instanceof iQuery.prototype //VM125:1 Uncaught TypeError: Right-hand side of ‘instanceof‘ is not callable(…)
说 iQuery.prototype 是一个对象 instanceof 右边必须是类,即函数名
iQuery() instanceof iQuery.prototype.init; //true
这里调用 iQuery() 是创建了init的一个对象。

总结1 如果使用new创建对象加不加 return this 是一样的。


//代码6 去掉//1 处的 new //2处有 return this

var iQuery=function (){name="iQuery"; //4return iQuery.prototype.init(); //1};iQuery.prototype={init : function(){this.name="iQueryPrototypeInit"; //5return this; //2},name : "iQueryPrototype" //6};iQuery().name; // iQueryPrototypeInit

如果去掉 //5

iQuery().name; // iQueryPrototype

分析: 执行 iQuery() 返回了 iQuery.prototype 这个由字面常量创建的对象

如果没有去掉 //5 则给 iQuery.prototype 添加了 name 属性覆盖了原有的name
在这里 iQuery.prototype.init() 是 iQuery.prototype 这个对象调用了 init 函数
所以 init 的 this 指向了 iQuery.prototype
结论2: 函数中的 this 始终指向直接调用它的对象 ,注意是直接,为什么说是直接 请看 //代码6


//代码7

var iQuery=function (){name="iQuery"; //4return iQuery.prototype.init(); //1};iQuery.prototype={init : function(){return this; //2},name : "iQueryPrototype" //6};var temp ={};temp.name="temp";temp.sayName=iQuery().init; // 等价于 temp.sayName=iQuery.prototype.init;temp.name; // 结果 temptemp.sayName.name; // 结果 temp

分析: 执行 temp.sayName=iQuery().init; 为对象 temp 添加了一个 sayName 方法,
sayName 引用了 iQuery().init/temp.sayName=iQuery.prototype.init
这时 init 中的 return this 这个 this 指向 temp 因为是 temp 直接调用 init
总结: JavaScript中的 this 是上下文 这个上下文特指是函数的上下文,就是函数所属的对象
JavaScript中的 bind,call,apply 方法都能切换 函数的上下文,这和代码 //6 的原理相同
都是改变 this 的指向,所以叫做上下文切换


//代码8 (本文最重要的点) 对象和类之间的关系(instanceof)

var iQuery=function (){name="iQuery"; //4return new iQuery.prototype.init(); //1};iQuery.prototype={init : function(){},name : "iQueryPrototype" //6};iQuery.prototype.init.prototype=iQuery.prototype; //3

  

注意 增加了 //3
这是执行:
a: iQuery() instanceof iQuery().init; //true
b: iQuery() instanceof iQuery; //true;
如果去掉 //3
c: iQuery() instanceof iQuery; //false;

分析: 我调用 iQuery() 创建的明明是 构造器 init 的对象啊 a:的结果才是符合逻辑的结果,b: 是什么鬼啊,和他有毛关系啊
请看 //代码9 //代码10


//代码9

var pro={};var A=function(){};A.prototype=pro;var B=function(){};B.prototype=pro;var a=new A();var b=new B();执行:a instanceof A; //truea instanceof B; //trueb instanceof A; //trueb instanceof B; //true

  

//代码10

var pro={};var A=function(){};A.prototype=pro;var B=function(){};B.prototype=pro;var a=new A();var b=new B();var C=function(){};C.prototype=a;var c=new C();c instanceof A; //truec instanceof B; //truec instanceof C; //true

  

 

分析: 看到这里大家一定会明白Jquery的设计者为什么加 iQuery.prototype.init.prototype=iQuery.prototype;
虽然源码中用了 fn 但是 fn 就是 Jquery.prototype
我给出我的结论
结论3: JavaScript 中的对象和类(即 构造器) 之间除了 对象的_proto_ 属性指向了 类(构造器)指定的 prototype之外,
对象和类之间没有更多的关系。类型完全由 prototype 决定。具有相同 prototype 的所有构造器的对象都具有相同的
类型

最后: Jquery中的init中有 return this 对于使用 new 函数名() 这样的方式创建对象有无 return this 是一样的。那Jquery
为什么加啊,因为Jquery中的很多其它方法可以进行 链式调用,这些方法中通过 return this 返回由 init创建的对象,为了
保持一致 所以 init中的 return this 真的可以去掉。
对于使用 new 函数名() 创建 对象 return this 和无返回值一样因为默认就会返回 this。
return 基本类型,则 return 会被忽略依然 return this。
如果 return 引用类型 那么返回结果就是 引用类型的对象。

由Jquery创建对象引发的思考