继承方式
js中继承的方式有六种:
原型链,盗用构造函数,组合继承,原型式继承,寄生式继承,寄生式组合继承
1.原型链
原型链的思想:实例化父类赋值给子类构造函数的原型,从而达到共享父类的方法和属性的目的。
原型链有两个问题(原型链不会单独使用):
- 在父类使用引用值会导致继承该父类的子类共享该引用值的指针
- 子类不可以向父类传参数
/*原型链实现继承的实现方式*/
function Paren(){
this.name="小明";
}
Paren.prototype.sayName=function(){
console.log(this.name)
}
function Child(){
this.age = 12;
}
Child.prototype = new Parent()
Child.prototype.sayAge=function(){
console.log(this.age);
}
const instance = new Child();
在父类使用引用值会导致继承该父类的子类共享该引用值的指针
function Paren(){
this.friends = ["friend1","friend2","friend3"];
}
function Child(){}
Child.prototype = new Paren();//因为在这一步的时候Child.prototype.friend存的是引用值
let instance1 = new Child();
let instance2 = new Child();
instance1.friends.push("friendN");
console.log(instance2.friends);//["friend1","friend2","friend3","friendN"]
console.log(instance1.friends === instance2.friends);//true (引用值相等)
2.盗用构造函数
盗用构造函数的思想:在子类构造函数中调用父类构造方法,this的指向指向子类
解决的问题:传参问题
存在的问题(盗用构造函数不会单独使用):
- 子类不能访问父类原型的方法
- 必须在构造函数里面定义方法,导致方法没有办法复用(因为每次都执行一次父类构造方法)
/*盗用构造函数实现继承的实现方式*/
function Paren(name){
this.name = name;
}
function Child(name,age){
Paren.call(this,name)
this.age = age;
}
3.组合继承
组合继承的思想:结合原型链和盗用构造函数的优点,使用原型链共享方法,使用盗用构造函数共享属性;
解决的问题:子类可以向父类传递参数,父类的方法可以复用
function Parent( name ){
this.name = name;
}
Parent.prototype.sayName = function(){
console.log(this.name)
}
function Child( name ,age){
Parent.call(this,name)
this.age = age;
}
Child.prototype = new Parent();
Child.prototype.sayName = function(){
console.log(this.age)
}
4.原型式继承
出发点:即使不自定义类型也可以通过原型实现对象之间的信息共享
/*核心*/
function object( o ) {
let F = function(){};
F.prototype = o;
return new F()
}
/*等同于*/
Object.create();
5.寄生式继承
寄生式继承同样适合主要关注对象,而不在乎类型和构造函数的场景。和原型式继承很像
function Child (org) {
const clone = object(org);//新建一个对象
clone.sayName = function(){ //增强对象属性
console.log("hello")
}
return clone; //返回对象
}
6.寄生式组合式继承
组合继承:
function Parent( name ){
this.name = name;
}
Parent.prototype.sayName = function(){
console.log(this.name)
}
function Child( name ,age){
// 第一次执行父类构造函数,获取父类属性
Parent.call(this,name);
this.age = age;
}
// 第二次执行父类的构造函数,导致原型上会有父类的属性和方法
// 这次我们只需要获取方法,是不需要获取属性的
// 所以可以只拷贝原型上的方法即可
Child.prototype = new Parent();
Child.prototype.sayName = function(){
console.log(this.age)
}
从组合继承可以看出,执行的时候调用了两次父类的构造函数,存在效率问题
function copyPrototype( parent, child ) {
const childPrototype = {
constructor:child,// 2.所以在这里以添加构造函数的方式给增强
...parent.prototype,
}
child.prototype = childPrototype ;//1.直接赋值会导致child的constructor丢失
}
function Parent( name ){
this.name = name;
}
Parent.prototype.sayName = function(){
console.log(this.name)
}
function Child( name ,age){
Parent.call(this,name);//第一次执行父类构造函数
this.age = age;
}
// Child.prototype = new Parent();//第二次执行父类的构造函数
copyPrototype(Parent,Child);//通过拷贝prototype和增强构造函数;不用调用构造方法
Child.prototype.sayName = function(){
console.log(this.age)
}
总结
。。。待更新