javascript继承问题
selfcontroller
2013-11-24
最近在研究javascript继承问题,遇到点疑惑,希望大家指点,具体看代码:
function Dog(){ this.tail = true; } dog1 = new Dog(); dog2 = new Dog(); Dog.prototype.say = function(){ return 'woof'; } dog1.say(); >>> 'woof' dog2.say(); >>> 'woof'; 以上代码说明,只要我们在构造器的原型对象上添加了新的方法或者属性,那么不管实例是什么时候创建的,他们都能访问这些新添加的方法或者属性。并且我们访问dog1和dog2的constructor的时候返回的都是Dog(): dog1.constructor; >>> Dog() dog2.constructor: >>> Dog() 通过以上的代码,你会感觉一切正常,但是如果我们访问的是该原型对象的构造器的话,返回的也是Dog(),这就不对了,因为这个时候,它的原型对象应该是一个有Object()创建的一个一般对象才对,并不拥有Dog()所构造的对象所拥有的属性。按理说,每个实例的constructor属性默认调用的是prototype的constructor的属性,这是我迷惑的地方之一,希望各位指教。 另一个疑惑: 继续上面的例子,这次不同的是,我用一个自定义的对象覆盖了原有的原型对象: Dog.prototype = {paws:4,hair:true} typeof(dog1.paws) >>> 'undefined' typeof(dog2.paws) >>> 'undefined' dog1.say(); >>> 'woof' dog3 = new Dog(); dog3.say() >>> TypeError: dog3.say is not a function dog3.paws >>> 4 从上面的代码可以看出,在我用自定义的对象覆盖了之前的原型对象之后,dog1和dog2,不能再访问我新添加的属性(paws,hair)了,这说明,在dog1和dog2看来,自定义的对象所充当的原型对象已经不是他们当初的原型对象了,然而他们依然能访问我改变之前的原型对象,这是我疑惑的地方之二,请问,他们是如何知道原型对象发生改变的?又是如何找到之前的原型对象的? 对于以上疑问,我通过查阅资料得知,每个实例都存在一个指向相关原型的链接,叫__proto__ 也就是说,dog1和dog2是通过这个属性来找到他们的原型对象的,而不是通过dog1.constructor.prototype。并且,即使constructor的prototype已经被改变(我后来用自定义的对象覆盖了它),dog1和dog2的 __proto__ 属性是不会跟着改变的,这也就解释了为什么我改变了constructor的prototype之后,dog1和dog2依然能够访问say方法了。而且,每个实例对象的__proto__属性是由该实例对象被实例化时的constructor的prototype所决定的。当然这只是我的个人理解,不知是否正确,请各位指点。 迷惑3: 继续上面的例子,因为我用自定义的对象覆盖了Dog()的默认prototype,这个时候我访问dog3.constructor: dog3.constructor >>> Object() dog1.constructor >>> Dog() 通过上面的代码你会发现,其实每个实例也有一个constructor属性,并且,这个constructor的属性默认是调用prototype的constructor属性的,所以你看见dog3的constructor跟dog1的constructor已经不一样了。但是这个结论刚好又跟我开始说的第一个疑惑相冲突,行开始的例子你能发现,dog1的constructor是Dog(),而我们的推测却是该dog1的prototype的constructor刚好是个Object(),难道是我的推测错了么?这刚好是我的第三个疑问,请各位多多指教。 |
|
jackyin5918
2013-11-25
下面代码,貌似涉及到 第三个疑惑,
供参考 http://jackyin5918.iteye.com/admin/blogs/1881246 //定义一个基类 function Animal() { this.species = "动物"; } Animal.prototype.show = function() { alert('This is An Animal. name=' + this.name);}; //定义基类一个普通方法 Animal.legCount=4; //定义动物有4条腿,类的静态属性 Animal.TestStaticFunction = function() {alert('TestStaticFunction.');};//基类,静态方法 //定义一个子类 function Cat(name,color) { Animal.call(this);//相当于调用基类的构造函数,将基类的属性继承过来,但仅限于在基类的构造函数中定义的属性 this.name = name; this.color = color; } var EmptyObject = function(){}; // EmptyObject.prototype = Animal.prototype; Cat.prototype = new EmptyObject(); //修改Cat的prototype不会影响到基类的prototype Cat.prototype.constructor = Cat; //因为每个类的prototype对象都有个constructor属性,指向类自己, //这里需要Cat.prototype其实是Animal,而Animal的constructor是指向Animal的, //造成了Cat的constructor指向了Animal,产生混乱,需要修正过来 var anAnimal = new Animal(); var aCat = new Cat('Tom','black'); console.log(aCat); anAnimal.show(); //基类prototype中方法,正常访问,(但基类中this.name未定义) aCat.show(); //正常,通过prototype方式继承了基类prototype中的方法 |
|
selfcontroller
2013-11-25
@jackyin5918,这。。。。。
|
|
jackyin5918
2013-11-26
selfcontroller 写道 @jackyin5918,这。。。。。
这。。。。。 是什么意思? 通过以上的代码,你会感觉一切正常,但是如果我们访问的是该原型对象的构造器的话,返回的也是Dog(),这就不对了,因为这个时候,它的原型对象应该是一个有Object()创建的一个一般对象才对,并不拥有Dog()所构造的对象所拥有的属性。 这个疑问从何而来? prototype 是每个function都有的,在定义function的时候,会给这个function增加一个prototype属性,其中这个prototype又有一个constructor属性,指向这个function本身. 在定义好这个function,使用new创建出来的对象实例会拷贝原来function的prototype为自己的__proto__属性.所以访问对象实例的constructor,就是原来函数(构造器)的constructor. 它的原型对象应该是一个有Object()创建的一个一般对象才对 这个结论 怎么得出来的? 貌似楼主对prototype这个没搞清楚吧. 另, 在new()的时候,js主要干了下面几件事情: 1. js运行环境首先创建一个空对象 2. 把this变量指向这个对象 3. 把__proto__指向这个构造器的prototype属性 4. 通过this把属性和方法加在这个对象上 5. 最后会把this指向的对象return出来(当然你也可以显示的return别的对象,这是情况跟我讨论的有点不一样) 参考: http://jackyin5918.iteye.com/admin/blogs/1881650 |
|
selfcontroller
2013-11-26
@jackyin5918 ,谢谢你,我想我明白了,你的解释很透彻,之前一直以为每个函数的prototype默认都是一个空对象,并且他们的constructor都是Object的,经你这么一说,确实是有道理的,谢谢你。 |
|
lt0604
2013-11-29
Dog.prototype应该是赋值语句,而不是重写。
|