继承家产是什么意思
- 是什么: 在js中,让一个子类可以访问父类的属性和方法。就是继承父亲的家产。
如何继承
问问类叔和构造函叔
他们会告诉我哪些是能继承的,哪些我不能拿到的。
js
//构造函数
function Car(name) {
this.name = name
}
Car.prototype.run = function(){} //可以继承
Car.sell = function(){ //拿不到的
console.log('sell');
}
let car = new Car('BMW')
car.sell()//拿不到的
//类
class Car{
constructor(name){ //构造器显示继承,
this.name = name;
}
run(){ //放在原型,能被car访问
console.log(`${this.name} is running`);
}
//静态方法相对于Car.sell
// static sell(){
// console.log('sell');
// }
}
// Car.prototype.sell = function(){console.log('sell');}//挂在原型上,能被car访问
Car.sell = function(){console.log('sell');}
let car = new Car('BMW');
car.run()
// car.sell()
console.log(car);
-
你能继承的
constructor
构造器是父亲的银行卡,里面定义的是东西可以看到的钱。- 定义在constructor外面的就是父亲的一些非现金,比如房子,地。是肉眼看不到的钱
-
你不该继承的:
- 使用
static
定义的就和Car.sell
一样是父亲的私人所有,比如母亲。
- 使用
继承家产的方式
类叔和构造函叔告诉我总共有7种方法可以拿到父亲让我继承的财产, 父亲还真是玩的花,退休了都不失玩心。
1. 原型链继承
只能飞鸽传书,一次只能告诉一件事给父亲,这样迟早破产。
-
缺点 :
- 无法给父类灵活传参。
- 多个实例对象共用同一个原型对象会存在属性相互影响,比如:push会修改
js
function Car(color, speed) {
this.color = color
this.speed = speed
this.seat = [1, 2]
}
Truck.prototype = new Car('red', 200) //无法灵活传参
function Truck() {
this.container = true
}
let truck = new Truck()
let truck2 = new Truck()
//修改truck的seat
truck.seat.push(3)
console.log(truck2.seat); //[1,2,3]
这种方式有分配问题,兄弟间的财产没有分干净会互相影响,父亲压力山大。
2. 构造函数继承:
只允许继承父亲的银行存款和现金,地皮那些拿不到。
-
缺点 :
- 只能继承到父类身上的属性,无法继承到父类原型上的属性
js
Parent.prototype.say = 'hello'
function Parent() {
this.name = 'parent'
}
function Child() {
Parent.call(this) // this.name = 'parent'
this.type = 'child'
}
let c = new Child()
console.log(c.say); //拿不到
console.log(c.name);//拿得到
3. 组合继承(经典继承):
好处是兄弟分配均匀,不会互相影响。
但是想要用地皮开发还得一直和父亲汇报情况,父亲不得清净。
-
缺点:
- 存在多次父类构造函数的调用,多造成了性能的开销
js
Parent.prototype.say = 'hello'
function Parent() {
this.name = 'parent'
this.car = [1, 2]
}
Child.prototype = new Parent()
function Child() {
Parent.call(this)
this.type = 'child'
//this.car = [1, 2]
}
let c = new Child()
let c2 = new Child()
c.car.push(3)
console.log(c2.car);
4. 原型式继承:
还是兄弟间会相互影响,分配不均匀。
-
缺点 :
- 因为是浅拷贝,父类中的引用类型在子类之间共用,所以会相互影响
2.继承过程中子类无法添加默认属性
- 因为是浅拷贝,父类中的引用类型在子类之间共用,所以会相互影响
js
let parent = {
name: 'Tom',
firends: ['foo', 'bar', 'baz'],
age() {
return 18
}
}
let child = Object.create(parent)
let child2= Object.create(parent)
child.firends.push('xyz')
console.log(child2.firends);
5. 寄生式继承:
这个方法真是不常见,我单手扣6。
-
缺点 :
- 因为是浅拷贝,父类中的引用类型在子类之间共用,所以会相互影响
js
let parent = {
name: 'Tom',
firends: ['foo', 'bar', 'baz'],
age() {
return 18
}
}
function clone(origin) {
let obj = Object.create(origin)
obj.like = function() {
return ['coding']
}
return obj
}
let child = clone(parent)
6. 寄生组合式继承:
容易忘本,迷惑人心。不过是功能最强大的继承方式,优化了多次调用构造函数的缺点。
js
Parent.prototype.say = 'hello'
function Parent(like) {
this.name = 'parent'
this.like = like
}
//这里了优化了多次调用构造函数的缺点
Child.prototype = Object.create(Parent.prototype) // {__proto__: Parent.prototype}
Child.prototype.constructor = Child
function Child(like) {
Parent.call(this, like)
this.type = 'child'
}
let c1 = new Child('coding')
console.log(c1.say);
注意
Child.prototype = Object.create(Parent.prototype)
给了我其他的好处,迷惑我这都是我应得的,还让我认贼作父。
Child.prototype.constructor = Child
他告诉我这些都是继承父亲的资产,不能忘本啊。
7. class继承:
这个也很完美,是ES6的新的继承方式
js
class Parent {
constructor(name) {
this.name = name;
}
getName() {
return this.name;
}
}
class Child extends Parent {
constructor(type, name) {
super(name)//深度继承
this.type = type;
}
}
let c = new Child('child', 'Tom')
console.log(c.name);
super是固定语法,实现对父类构造函数的调用。
决定
最终我决定使用class继承,寄生式组合继承容易迷失自我