原型链继承
```javascript
function Pet(){
this.master = "zxz"
}
Pet.prototype.about = function(){
console.log(`这只宠物的主人是${this.master}`)
}
function Cat(color){
this.color = color
}
Cat.prototype = new Pet()
Cat.prototype.constructor = Cat
var coco = new Cat()
coco.about() //这只宠物的主人是zxz
```
构造函数继承
子类内部调用父类构造函数
构造函数继承
```javascript
function Pet(name,age){
this.name = name
this.age = age
}
function Cat(name,age,color){
this.color = color
Pet.call(this,name,age)
}
var coco = new Cat("coco",3,"白")
console.log(coco) //Cat { color: '白', name: 'coco', age: 3 }
```
组合继承
组合继承
1. 通过call或者apply,继承父类构造函数中的属性
- 如果不写的话,还是可以通过原型链获得属性;但是对于需要向构造函数传入参数的属性,因为没法传参,值只能undefined
2. 替换原型,子类的原型对象设置为父类的一个实例
3. 保持构造函数的一致性
- 第一步是基于构造函数的继承,第二步是基于原型链的继承,两者组合使用
- 规避**只使用原型链继承时 引用类型 原型属性被所有实例共享的问题**
- 规避**只使用构造函数继承时 实例的方法没有复用 的问题**
```javascript
function Pet(name,age){
this.name = name
this.age = age
}
Pet.prototype.about = function(){
console.log(`这只宠物叫${this.name},今年${this.age}岁了`)
}
function Cat(name,age,color){
this.color = color
Pet.call(this,name,age) //通过call或者apply定义Pet中以及定义的属性
}
Cat.prototype = new Pet() //继承原型,coco.__proto__ => Cat.prototype ; coco.__proto__.__proto__ => new Pet().__proto__ => Pet.prototype
Cat.prototype.constructor = Cat // 保持构造函数的一致性,不然构造函数指向Pet的
Cat.prototype.about = function(){ //重写对象方法
console.log(`这只${this.color}色猫猫叫${this.name},今年${this.age}岁了`)
}
var wowo = new Pet("wowo",4)
wowo.about()//这只宠物叫wowo,今年4岁了
var coco = new Cat("coco",3,"白")
coco.about()//这只白色猫猫叫coco,今年3岁了
console.log(coco.__proto__.constructor) //[Function: Cat]
console.log(coco instanceof Cat) //true
console.log(coco instanceof Pet) //true
```
缺点:原型上有一些多余的属性
```javascript
console.log(coco)
```
![image](https://user-images.githubusercontent.com/44082279/61166551-12111c00-a562-11e9-844c-c489485b3e77.png)
原型式继承
创造一个新的空的类
新的类的原型指向要继承的类
返回一个新的类的实例
原型式继承
```javascript
function object(o){
function F(){}
F.prototype = o
return new F();
}
```
ES5使用object.create()规范了原型式继承
`(method) ObjectConstructor.create(o: object): any (+1 overload)`
有重载,第二个参数格式类似`Object.definedProperties()`方法
寄生式继承
寄生式继承
```javascript
function createAnother(original){
var clone = object(original); // object是上面的原型式继承
clone.sayHi = function(){
console.log('hi')
}
return clone
}
```
寄生组合式继承
寄生组合式继承
1.通过call或者apply,继承父类构造函数中的属性
2.使用Object.create(Pet.prototype)替换原型,子类的原型对象设置为父类的一个原型式继承
3.保持构造函数的一致性
好像就是把组合继承中的`Cat.prototype = new Pet()`换成了`Cat.prototype = Object.create(Pet.prototype)`
避免了二次调用new SuperType()
```javascript
function Pet(name, age) {
this.name = name
this.age = age
}
Pet.prototype.about = function () {
console.log(`这只宠物叫${this.name},今年${this.age}岁了`)
}
function Cat(name, age, color) {
this.color = color
Pet.call(this, name, age) //通过call或者apply定义Pet中以及定义的属性
}
/***** 继承步骤上组合继承不同的地方 ***********************/
Cat.prototype = Object.create(Pet.prototype)
/***** **************************************************/
Cat.prototype.constructor = Cat // 保持构造函数的一致性,不然构造函数指向Pet的
Cat.prototype.about = function () { //重写对象方法
console.log(`这只${this.color}色猫猫叫${this.name},今年${this.age}岁了`)
}
var coco = new Cat("coco", 3, "白")
/***** 这部分得到的结果都和组合继承相同 *******************/
var wowo = new Pet("wowo", 4)
wowo.about() //这只宠物叫wowo,今年4岁了
var coco = new Cat("coco", 3, "白")
coco.about() //这只白色猫猫叫coco,今年3岁了
console.log(coco.__proto__.constructor) //[Function: Cat]
console.log(coco instanceof Cat) //true
console.log(coco instanceof Pet) //true
/***** **************************************************/
```
```javascript
console.log(coco)
```
![image](https://user-images.githubusercontent.com/44082279/61166546-f60d7a80-a561-11e9-803a-874a72a48f51.png)
相比于组合继承,在Pet原型上少了很多多余的属性
ES6中的继承
ES6中的继承
`class` 实现继承的核心在于使用 `extends` 表明继承自哪个父类,并且在子类构造函数中必须调用 `super`,因为这段代码可以看成 `Pet.call(this, name, age) `。
```javascript
class Pet {
constructor(name, age) {
this.name = name
this.age = age
}
about() {
console.log(`这只宠物叫${this.name},今年${this.age}岁了`)
}
}
class Cat extends Pet {
constructor(name, age, color) {
super(name, age)
this.color = color
}
about() { //重写对象方法
console.log(`这只${this.color}色猫猫叫${this.name},今年${this.age}岁了`)
}
}
/***** 这部分得到的结果都和组合继承相同 *******************/
var wowo = new Pet("wowo", 4)
wowo.about() //这只宠物叫wowo,今年4岁了
var coco = new Cat("coco", 3, "白")
coco.about() //这只白色猫猫叫coco,今年3岁了
console.log(coco.__proto__.constructor === Cat) //[Function: Cat]
console.log(coco instanceof Cat) //true
console.log(coco instanceof Pet) //true
/***** **************************************************/
```
```javascript
console.log(coco)
```
![image](https://user-images.githubusercontent.com/44082279/61199826-e92f8900-a711-11e9-897c-def87f5f45c3.png)
另外,类的内部所有定义的方法,都是不可枚举的(non-enumerable)。
```javascript
Object.keys(Pet.prototype) //[]
```
原型链继承
原型链继承
```javascript function Pet(){ this.master = "zxz" } Pet.prototype.about = function(){ console.log(`这只宠物的主人是${this.master}`) } function Cat(color){ this.color = color } Cat.prototype = new Pet() Cat.prototype.constructor = Cat var coco = new Cat() coco.about() //这只宠物的主人是zxz ```构造函数继承
构造函数继承
```javascript function Pet(name,age){ this.name = name this.age = age } function Cat(name,age,color){ this.color = color Pet.call(this,name,age) } var coco = new Cat("coco",3,"白") console.log(coco) //Cat { color: '白', name: 'coco', age: 3 } ```组合继承
组合继承
1. 通过call或者apply,继承父类构造函数中的属性 - 如果不写的话,还是可以通过原型链获得属性;但是对于需要向构造函数传入参数的属性,因为没法传参,值只能undefined 2. 替换原型,子类的原型对象设置为父类的一个实例 3. 保持构造函数的一致性 - 第一步是基于构造函数的继承,第二步是基于原型链的继承,两者组合使用 - 规避**只使用原型链继承时 引用类型 原型属性被所有实例共享的问题** - 规避**只使用构造函数继承时 实例的方法没有复用 的问题** ```javascript function Pet(name,age){ this.name = name this.age = age } Pet.prototype.about = function(){ console.log(`这只宠物叫${this.name},今年${this.age}岁了`) } function Cat(name,age,color){ this.color = color Pet.call(this,name,age) //通过call或者apply定义Pet中以及定义的属性 } Cat.prototype = new Pet() //继承原型,coco.__proto__ => Cat.prototype ; coco.__proto__.__proto__ => new Pet().__proto__ => Pet.prototype Cat.prototype.constructor = Cat // 保持构造函数的一致性,不然构造函数指向Pet的 Cat.prototype.about = function(){ //重写对象方法 console.log(`这只${this.color}色猫猫叫${this.name},今年${this.age}岁了`) } var wowo = new Pet("wowo",4) wowo.about()//这只宠物叫wowo,今年4岁了 var coco = new Cat("coco",3,"白") coco.about()//这只白色猫猫叫coco,今年3岁了 console.log(coco.__proto__.constructor) //[Function: Cat] console.log(coco instanceof Cat) //true console.log(coco instanceof Pet) //true ``` 缺点:原型上有一些多余的属性 ```javascript console.log(coco) ``` ![image](https://user-images.githubusercontent.com/44082279/61166551-12111c00-a562-11e9-844c-c489485b3e77.png)原型式继承
原型式继承
```javascript function object(o){ function F(){} F.prototype = o return new F(); } ``` ES5使用object.create()规范了原型式继承 `(method) ObjectConstructor.create(o: object): any (+1 overload)` 有重载,第二个参数格式类似`Object.definedProperties()`方法寄生式继承
寄生式继承
```javascript function createAnother(original){ var clone = object(original); // object是上面的原型式继承 clone.sayHi = function(){ console.log('hi') } return clone } ```寄生组合式继承
寄生组合式继承
1.通过call或者apply,继承父类构造函数中的属性 2.使用Object.create(Pet.prototype)替换原型,子类的原型对象设置为父类的一个原型式继承 3.保持构造函数的一致性 好像就是把组合继承中的`Cat.prototype = new Pet()`换成了`Cat.prototype = Object.create(Pet.prototype)` 避免了二次调用new SuperType() ```javascript function Pet(name, age) { this.name = name this.age = age } Pet.prototype.about = function () { console.log(`这只宠物叫${this.name},今年${this.age}岁了`) } function Cat(name, age, color) { this.color = color Pet.call(this, name, age) //通过call或者apply定义Pet中以及定义的属性 } /***** 继承步骤上组合继承不同的地方 ***********************/ Cat.prototype = Object.create(Pet.prototype) /***** **************************************************/ Cat.prototype.constructor = Cat // 保持构造函数的一致性,不然构造函数指向Pet的 Cat.prototype.about = function () { //重写对象方法 console.log(`这只${this.color}色猫猫叫${this.name},今年${this.age}岁了`) } var coco = new Cat("coco", 3, "白") /***** 这部分得到的结果都和组合继承相同 *******************/ var wowo = new Pet("wowo", 4) wowo.about() //这只宠物叫wowo,今年4岁了 var coco = new Cat("coco", 3, "白") coco.about() //这只白色猫猫叫coco,今年3岁了 console.log(coco.__proto__.constructor) //[Function: Cat] console.log(coco instanceof Cat) //true console.log(coco instanceof Pet) //true /***** **************************************************/ ``` ```javascript console.log(coco) ``` ![image](https://user-images.githubusercontent.com/44082279/61166546-f60d7a80-a561-11e9-803a-874a72a48f51.png) 相比于组合继承,在Pet原型上少了很多多余的属性ES6中的继承
ES6中的继承
`class` 实现继承的核心在于使用 `extends` 表明继承自哪个父类,并且在子类构造函数中必须调用 `super`,因为这段代码可以看成 `Pet.call(this, name, age) `。 ```javascript class Pet { constructor(name, age) { this.name = name this.age = age } about() { console.log(`这只宠物叫${this.name},今年${this.age}岁了`) } } class Cat extends Pet { constructor(name, age, color) { super(name, age) this.color = color } about() { //重写对象方法 console.log(`这只${this.color}色猫猫叫${this.name},今年${this.age}岁了`) } } /***** 这部分得到的结果都和组合继承相同 *******************/ var wowo = new Pet("wowo", 4) wowo.about() //这只宠物叫wowo,今年4岁了 var coco = new Cat("coco", 3, "白") coco.about() //这只白色猫猫叫coco,今年3岁了 console.log(coco.__proto__.constructor === Cat) //[Function: Cat] console.log(coco instanceof Cat) //true console.log(coco instanceof Pet) //true /***** **************************************************/ ``` ```javascript console.log(coco) ``` ![image](https://user-images.githubusercontent.com/44082279/61199826-e92f8900-a711-11e9-897c-def87f5f45c3.png) 另外,类的内部所有定义的方法,都是不可枚举的(non-enumerable)。 ```javascript Object.keys(Pet.prototype) //[] ```