原型链继承
原型链作为实现继承的主要方法,其基本思路是利用原型让一个引用类型继承另一个引用类型的属性和方法, 构造函数,原型和实例之间的关系通过一张图来解释一下,需要详细了解的可以看一下我的另外一篇文章
原型链继承的基本模式如下:
function Parent() {
this.name = "heyushuo";
}
Parent.prototype.sayParentName = function() {
console.log(this.name);
};
function Child() {
this.name = "kebi";
}
//1.此时把Child的原型重写了,换成了Parent的实例
//2.换句话说,原来存在Parent的实例中的属性和方法,现在也存在Child.prototype中了
Child.prototype = new Parent();
//3.在继承了Parent实例中的属性和方法后基础上,又添加了属于自己的一个新方法(这里两个名字一样会覆盖)
Child.prototype.sayChildName = function() {
console.log(this.name);
};
var Person = new Child();
console.log(Person);
//所以现在Person指向Child的原型,Child的原型指向Parent的原型(因为Child的原型对象等于了Parent的实例,这个实例指向Parent的原型)
通过如下图打印的 Person 看一下他们的关系: 这里特别需要注意的是 Person.constructor 现在指向的是 Parent,因为 Child.prototype 中的 constructor 被重写了 可以通过如下代码改变 constructor 的指向
//改变 constructor 的指向
Child.prototype.constructor = Child;
二.如何确定原型和原型的关系呢
1. instanceof (实例对象是否是构造函数函数的实例)
console.log(Person instanceof Child); //true
console.log(Person instanceof Parent); //true
console.log(Person instanceof Object); //true
//由于原型链的关系,可以说Person是他们三个中任何一个类型的实例
2.isPrototypeOf(Person) 只要原型链中出现过的原型,都可以说是该原型链派生的实例的原型(可以理解为是否是实例的原型) Object.prototype.isPrototypeOf(Person) //true Parent.prototype.isPrototypeOf(Person) //true Child.prototype.isPrototypeOf(Person) //true
三.需要注意的问题
再给 Child 添加新的方法的时候,一定要在原型继承父元素后添加,这样可以防止自己定义的方法,会和继承来的方法名字相同,导致 Child 自己定的方法被覆盖
四.原型链继承的问题
1.实例共享引用类型
虽然原型链继承很强大, 但是存在一个问题, 最主要的问题是包含引用类型值的原型, 因为包含引用类型值的原型属性会被所有的实例共享, 而在通过原型来实现继承的时候, 原型实际变成了另外一个函数的实例(这里边就有可能存在引用类型)
通过一个例子看一下
function Parent() {
this.newArr = ["heyushuo", "kebi"];
}
function Child() {
this.name = "kebi";
}
Child.prototype = new Parent();
var Person1 = new Child();
Person1.newArr.push("kuli");
console.log(Person1.newArr); // ["heyushuo","kebi","kuli"]
var Person2 = new Child();
console.log(Person2.newArr); // ["heyushuo","kebi","kuli"]
2.在创建 Child 的子类的时候,无法像继承元素传递参数