对象的继承
面向对象编程最重要的一个方面,就是对象的继承。A对象通过继承B对象,就能直接拥有B对象的所有的属性和方法。这对代码的复用是非常有用的。
1.通过原型链继承
原理:子类的原型是父类的一个实例对象
function Person(name){
this.name = name
this.sayHi = function(){
console.log('你好')
}
}
function Father(name){
this.name = name
this.sayHi = function(){
console.log('你好')
}
}
Father.prototype.age = 19;
//子类
function Child(sex){
this.sex = sex
}
//实现继承
Child.prototype = new Father('张三')
//实例化子类的对象
var c = new Child('男')
console.log(c.name)
c.sayHi()
console.log(c.age)
优点:
父类中的私有属性和方法以及公有属性和方法,子类都能访问到。
缺点:
无法实现多继承,只能继承一个父类。
创建子类实例时,无法向父类构造函数传参。
要想为子类新增属性和方法,必须要在 Student.prototype = new Person() 之后执行。
2.借用构造函数继承
function Father(name) {
this.name = name
this.sayHi = function () {
console.log('你好')
}
}
Father.prototype.age = 19;
Father.prototype.eat = function(){
console.log('吃饭')
}
//父类2
function Person(height){
this.height = height
}
//子类
function Child(name,height,sex) {
//通过借用父类构造函数,可以修改父类中的属性的值
Father.call(this,name)
Person.call(this,height)
this.sex = sex
}
//借用构造函数(父类)继承
var c = new Child('张三','180cm','男')
var c1 = new Child('李四','170cm','女')
console.log(c.name,c.height,c.sex)
console.log(c1.name,c1.height,c1.sex)
c.sayHi()
console.log(c.age) // undefined
c.eat() // c.eat is not a function
优点:
创建子类实例时,可以向父类传递参数,修改父类属性的值。
可以实现多继承(call多个父类对象)。
缺点:
只能继承父类的私有属性和方法,不能继承父类的公有属性和方法。
3.组合继承
这种方式关键在于:通过调用父类构造,继承父类的属性并保留传参的优点,然后通过将父类实例作为子类原型,实现函数复用。
//父类
function Father(name) {
this.name = name
this.sayHi = function () {
console.log('你好')
}
}
Father.prototype.age = 19;
Father.prototype.eat = function(){
console.log('吃饭')
}
//父类2
function Person(height){
this.height = height
}
//子类
function Child(name,height,sex) {
//1.通过借用父类构造函数,可以修改父类中的属性的值
Father.call(this,name)
Person.call(this,height)
this.sex = sex
}
// 2. 将子类的原型指向父类的一个实例对象
Child.prototype = new Father()
//实例化子类的实例对象
var c = new Child('张三','180cm','男')
var c1 = new Child('李四','170cm','女')
console.log(c.name,c.height,c.sex)
console.log(c1.name,c1.height,c1.sex)
console.log(c.age)
c1.eat()
```````
优点: 1.可以给父类传递阐述
2.可以实现多继承
3.可以继承父类的私有属性也可以继承父类的公有属性
缺点:1.调用了两次父类的构造函数
3.1组合继承优化
//父类
function Father(name) {
this.name = name
this.sayHi = function () {
console.log('你好')
}
}
Father.prototype.age = 19;
Father.prototype.eat = function(){
console.log('吃饭')
}
//子类
function Child(name,sex) {
//1.通过借用父类构造函数,可以修改父类中的属性的值
Father.call(this,name)
this.sex = sex
}
// 2. 将子类的原型指向父类的一个实例对象
//Child.prototype = new Father() // 作用:是为了让子类的实例对象能够继承父类的私有属性和公有属性
/* 原理: 子类的实例对象中的 __proto__ 指向的是子类的原型对象,子类的原型对象指向的是父类的一个实例对象,而父类中的实例对象继承了父类中的私有属性 ; 而父类的实例对象中的 __proto__ 指向的是父类的原型对象,所以能够继承父类的公有属性 */
Child.prototype = Father.prototype
//实例化子类的实例对象
var c = new Child('张三','男')
var c1 = new Child('李四','女')
console.log(c.name,c.sex)
console.log(c1.name,c1.sex)
console.log(c.age)
c1.eat()
// instanceof 判断一个对象是否是一个构造函数的实例对象
console.log( c instanceof Child) // true
console.log( c instanceof Father) // true
/*
缺点:
无法分辨当前的实例对象到底是子类的还是父类的,无法区别
*/
3.2组合继承的优化2
```````
Child.prototype = Object.create(Father.prototype)
```````
继承核心代码 借助原型可以基于已有的对象来创建对象:var B = Object.create(A) 以A对象为原型,生成了B对象。B继承了A的所有属性和方法
`````
Child.prototype.constructor = Child
```````
在Child的原型下的构造器指向Child本身