一个有关原型的问题牵扯出的问题

最近推荐一个朋友学习js,今天他问了我一个问题,问题如下:

 1 function Box (){}
 2 Box.prototype = {
 3     name : 'Lee',
 4     age : 28,
 5     run : function (){
 6         return this.name+this.age+'运行中...';
 7     }
 8 };
 9 var box = new Box();
10 Box.prototype = {
11     age : 200
12 };
13 alert(box.age);

这里alert出来的结果是多少呢?结果是28,他问我为什么是28,我运行代码之后发现是28,但是我也没有想明白为什么是。虽然一直使用js,但是每次遇到原型这个地方的问题的时候我还是会蒙,一直对这个理解的不是很透彻。刚好借着这个问题,我详细的看了下书和资料,算是弄明白了为什么。

这里先引用一段JavaScript高级程序设计(第三版)中的一段话。

无论什么时候,只要创建了一个新函数,就会根据一组特定的规则为该函数创建一个prototype属性。这个属性指向函数的原型对象。在默认情况下,所有原型对象都会自动获得一个constructor(构造函数)属性,这个属性包含一个指向prototype属性所在函数的指针。

这里有点抽象,我借用书中一个图说明下:

这里可以看出Box.prototype.constructor == Box;

上面的问题在哪里呢?当Box.prototype = {};一个新的对象的时候,这段代码:

1 function Box (){}
2 Box.prototype = {
3     name : 'Lee',
4     age : 28,
5     run : function (){
6         return this.name+this.age+'运行中...';
7     }
8 };

这段之后,这个Box.prototype.constructor == Box;就不成立了,

其实上面说的这段没啥用,只是为了凑字数显得字多,而接下来的new这个操作才是真正的起了作用。这里要理解new这个操作到底做了什么,在理解之前,先插入一段书上的原话:

创建了自定义的构造函数之后,其原型对象默认只会去的constructor属性,至于其他方法,则都是从Object继承而来的。当调用构造函数创建一个新实例后,该实例内部将包含一个指针(内部属性),指向构造函数的原型对象。ECMA-262第五版中管这个指针叫[[Prototype]]。虽然在脚本中没有标准的方式访问[[Prototype]]。但Firefox, Safari和Chrome在每个对象上都支持一个属性__proto__;而在其他实现中,这个属性对脚本则是完全不可见的。不过,要明确的真正重要的一点就是,这个连接存在于实例与构造函数的原型对象之间,而不是存在于实例与构造函数之间。

几把越看越晕了,看代码就好了:

1 var box = new Box();
2 // function new () {
3 //     var box = {};
4 //     box.__proto__ = Box.prototype;
5 //     Box.apply(box, arguments);
6 //       return box;
7 // }
8 注释部分只是方便理解

如果这样的话,上面的问题就一下子晴朗了,因为在new的时候指定了box内部__proto__的指向,这个指向就是Box.prototype的指向,

为了方便理解我把代码修改成如下:

 1 function Box (){}
 2 
 3 console.log(Box.prototype.constructor == Box);    //true
 4 
 5 var obj1 = {
 6     name : 'Lee',
 7     age : 28,
 8     run : function (){
 9         return this.name+this.age+'运行中...';
10     }
11 };
12 
13 Box.prototype = obj1;
14 
15 var box = new Box();
16 // function new () {
17 //     var box = {};
18 //     box.__proto__ = Box.prototype;
19 //     Box.apply(box, arguments);
20 //       return box;
21 // }
22 
23 console.log(box.age);
24 
25 
26 var obj2 = {
27     age : 200
28 };
29 
30 Box.prototype = obj2;
31 
32 console.log(Box.prototype.isPrototypeOf(box));               //false
33 console.log(Object.getPrototypeOf(box) == Box.prototype);    //false
34 console.log(Object.getPrototypeOf(box) == obj1);             //true
35 console.log(Object.getPrototypeOf(box) == obj2);             //false
36 
37 console.log(box.age);

因为已经new过了,而new过之后修改Box.prototype又是直接给了一个新的对象obj2, 所以原来的box内部的__proto__还是指向obj1, 跟Box没关系,只是Box.prototype是指向obj2而已。

 

一个小小的问题让我看了半天,看来对js的理解还是不够透彻。

posted @ 2015-09-09 19:49  Dn9x  阅读(283)  评论(0编辑  收藏  举报