先写一个父级的构造函数
function Parent(name){
this.name = name;
this.money = 10000000;
this.hobby = function(){
console.log("Parent this.hobby");
}
}
Parent.prototype.active = function(){
console.log("Parent.prototype");
}
Parent.prototype.eat = function(){
console.log("Parent.prototype.eat");
}
接着子集的构造方法
function Son(name){
}
子集想要继承父级里面的内容就要在里面加上
function Son(name){
Parent.call(this,name);
}
这样就可以继承父级里面的内容
var newSon = new Son("rrrr");
console.log(newSon.name); // rrrr
console.log(newSon.money); // 10000000
newSon.hobby(); // Parent this.hobby
这样写看似没什么问题,但是当我们在子集里面写上与父级相同的属性或者方法呢?
function Son(name){
Parent.call(this,name); // rrrr
this.money = 10;
this.hobby = function(){
console.log("Son this.hobby");
}
}
var newSon = new Son("rrrr");
console.log(newSon.name); // rrrr
console.log(newSon.money); // 10
newSon.hobby(); // Son this.hobby
上述代码表明,子集继承父级,在自身重写该方法的时候以自身为准
回到上述继承 构造继承
function Parent(name){
//属性
this.name = name;
this.money = 10000000
//实例方法
this.hobby = function(){
console.log("Parent this.hobby");
}
}
//原型方法
Parent.prototype.active = function(){
console.log("Parent.prototype");
}
Parent.prototype.eat = function(){
console.log("Parent.prototype.eat");
}
function Son(name){
Parent.call(this,name);
}
var newSon = new Son("rrrr");
console.log(newSon.name); // rrrr
console.log(newSon.money); // 100000
console.log(newSon instanceof Parent); // false
console.log(newSon instanceof Son); // true
newSon.hobby() // Parent this.hobby
newSon.active(); // 报错
newSon.eat(); // 报错
由上述可知,子集继承父级,只继承父级本身的属性和方法,不会继承父级原型上的方法,因为构造继承的核心就是使用父类的构造函数来增强子类的实例,等于是复制父类的实例属性给子类(没用到原型)
特点:
- 解决子类实例共享父类引用属性的问题
- 创建子类实例时,可以向父类传参数
- 可以实现多继承,(call多个父类对象)
缺点: - 实例并不是父类的实例,只是子类的实例
- 只能继承父类的实例属性和方法,不能继承原型属性和方法
- 无法实现函数复用,每个子类都有父类实力函数的副本,影响性能
这就可以利用到 实例继承
function Son(name){
var ins = new Parent(name);
return ins;
}
var newSon = new Son("ggg");
console.log(newSon.name); // ggg
console.log(newSon.money); // 10000000
console.log(newSon instanceof Parent); // true
console.log(newSon instanceof Son); // false
newSon.hobby() // Parent this.hobby
newSon.active(); // Parent.prototype
newSon.eat(); // Parent.prototype.eat
实例继承的核心。为父类实例添加新特性,作为子类实例返回
特点:
- 不限制调用方式,不管是 new 子类() 还是 子类() ,返回的对象具有相同的效果
缺点: - 实例是父级的实例,不是子类的实例
- 不支持多继承
再有 组合继承
function Son(name){
Parent.call(this,name);
}
Son.prototype.eat = function(){
console.log("Son.prototype.eat");
}
Son.prototype = new Parent();
var newSon = new Son("ggg");
console.log(newSon.name); // ggg
console.log(newSon.money); // 10000000
console.log(newSon instanceof Parent); // true
console.log(newSon instanceof Son); // true
newSon.hobby() // Parent this.hobby
newSon.active(); // Parent.prototype
newSon.eat(); // Parent.prototype.eat
组合继承的核心是通过父类构造,继承父类的属性并保留传参的优点,然后通过降幅及实例子类原型,实现函数复用
特点:
- 可以继承实例属性、方法,也可以继承原型属性、方法
- 即是子类的实例,也是父类的实例
- 不存在引用属性共享问题
- 可传参
- 函数可复用
缺点: - 调用了两次父类构造函数,生成两份实例(父类实例将子类原型上的那份屏蔽了),
最后寄生组合继承,通过创建一个空的构造函数。
function Son(name){
Parent.call(this,name);
}
Son.prototype.eat = function(){
console.log("Son.prototype.eat");
}
//创建一个空的构造函数
function Link(){}
//将Person4 里面的构造函数的原型 传址赋值 到 Link构造函数的原型里面
Link.prototype = Parent.prototype;
//实例化Student的构造方法的原型。此时 实例化的时候会重新创建一个新的地址存储,所以改变
//Student里面的方法的时候 不会影响Link 当然 也不会影响Person4
Son.prototype = new Link();
var newSon = new Son("tt")
console.log(newSon.name); // tt
console.log(newSon.money); // 10000000
console.log(newSon instanceof Parent); // true
console.log(newSon instanceof Son); // true
newSon.hobby() // Parent this.hobby
newSon.active(); // Parent.prototype
newSon.eat(); // Parent.prototype.eat