js中原型链和继承的问题
1、当构造函数中包含和原型对象重名的方法和属性时(构造函数中的会覆盖原型对象中的方法和属性)
1 function Person() { 2 this.name="martin"; 3 this.gun=function () { 4 alert("i am a person") 5 } 6 } 7 Person.prototype.gun=function () { 8 alert("biubiu"); 9 } 10 var xiaoGang=new Person(); 11 xiaoGang.gun();//输出i am a person 12
2、当正常的继承用法
function Person() { this.name="martin"; } } Person.prototype.gun=function () { alert("biubiu"); } function Student(){ this.name="dick"; } Student.prototype=new Person;//Student原型对象作为Person实例拥有Person构造函数所有属性方法,并包含指向Person原型对象的指针 } var xiaoMing=new Student(); xiaoMing.gun();//输出biubiu
原型搜索机制:拿上面的程序举例,要搜索xiaoMing实例中的gun方法;1、先搜寻xiaoMing实例本身 2、再搜索Student.prototype是否有gun方法 3、最后搜索Person.prototype,发现有所以调用了Person.prototype中的gun方法
针对于整个程序而言gun方法搜索过程:1.xiaoMing实例本身 2、Student构造函数 3、Student.prototype 4、Person构造函数 5、Person.prototype
总结:搜索属性和方法时从从近到远搜索,先搜索自身实例,然后搜索离自己最近的子对象,然后父对象(类似于冒泡搜索),同时构造函数中的方法属性会比其原型对象优先搜索,因为构造函数中的方法属性会屏蔽(注意和下面覆盖的区别)原型对象中的方法属性。
思考:正常的继承会同时继承父辈构造函数及其原型对象的方法和属性,那如果我只要继承父辈原型对象的方法和属性怎么办?
以上面的程序为例:想法:将程序中的Student.prototype=new Person替换成Student.prototype=Person.prototype能否实现
利用程序试验后得知:改方法可以实现只继承父辈原型对象的方法属性,但是因为Person把原型对象地址直接给了Student的原型对象,导致Student和Person原型对象的方法属性会互相覆盖,因为他们都指向Person原型对象的地址。
一般编程用到继承都用组合继承,方法继承用原型链继承,属性继承用借用构造函数方法继承,避免了原型链继承和借用构造函数的缺点(回忆两种方法各自的缺点),并结合了两者的优点。
function Person(name){ this.name=name; this.color=["red","green","white"]; } Person.prototype.sayname=function () { alert(this.name); } function Student(name,age) { Person.call(this,name); this.age=age; } Student.prototype=new Person; Student.prototype.sayAge=function () { alert(this.age); } var xiaoMing=new Student("xiaoMing",23); xiaoMing.color.push("black"); alert(xiaoMing.color); xiaoMing.sayname(); xiaoMing.sayAge();
1、原型链方法继承的缺点
以上面例子为例,
Student.prototype=new Person;//重点在这一句
这一句就相当于把Student的原型对象变成了Person的一个实例,也相当于创建了Student.prototype.color=["red","green","white"],所以当Student被实例化时,即var xiaoMing=new Student("xiaoMing",23);
Person构造函数中的属性color会被xiaoMing实例共享,最后导致一改改所有,所以我们属性继承不用原型链,方法继承用原型链。(详见Javascript高级编程P167)
2、借用构造函数缺点
因为利用构造函数创建对象,该对象实例化后属性和方法虽然同名但都是不相等的,因为他们都分属于不同的实例,调用相同的方法没必要在不同实例上都创建一遍,所以方法继承我们一般不用次方法,属性继承用借用构造函数方法。
总结:在使用继承时,对象方法放在原型对象上,属性放在构造函数里面。