<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>组合继承</title>
</head>
<body>
</body>
</html>
<script>
/**
* 组合继承:
* 原型继承 + 构造函数继承
* 避免了原型 && 构造函数 继承的缺点,融合他们的优点
* 优点:
* 可以使用原型上的方法和属性;
* 实现给父级构造函数传参
* 缺点:
* 创建实例的原型上会存在两份属性
* 父类构造函数调用一次,子类原型实现时候又会调用父类构造函数一次。因此会调用两次
*/
function Person(name) {
this.name = name || 'not name';
this.books = ['html', 'css'];
Person.prototype.getName = function () {
console.log(`父级类的方法得到的name:${this.name}`);
}
}
function Adult(name, time) {
this.time = time
// 构造函数继承父类 && 传参name属性
Person.call(this, name);
Adult.prototype.getTime = function () {
console.log(this.time);
}
}
Adult.prototype = new Person();
// 是否设置下面这一行,具体请看65行
Adult.prototype.constructor = Adult;
// 子类属性修改后不会影响其他实例
// 子类的参数可以传递给父类
let ming = new Adult('小明', 0000);
let hong = new Adult('小红', 2020);
ming.books.push('vue') // books: (3) ["html", "css", "vue"]
hong.books.push('react'); // books: (3) ["html", "css", "react"]
// 两个构造函数上面都会增加 books 和name属性 可以在增加属性测试
console.log(ming);
console.log(hong);
ming.getTime() // 0
hong.getTime() // 2020
ming.getName() // 父级类的方法得到的name:小明
hong.getName() // 父级类的方法得到的name:小红
// 讨论是否设置 constructor 问题 https://www.zhihu.com/question/19951896/answer/13457869
// 下面假设如果没有设置 Adult.prototype.constructor = Adult
console.log(Adult.prototype.constructor); // ƒ Person(name) {}
console.log(Person.prototype.constructor); // ƒ Person(name) {}
// 设置上之后 Adult.prototype.constructor = Adult
console.log(Adult.prototype.constructor); // ƒ Adult(name, time) {}
console.log(Person.prototype.constructor); // ƒ Person(name) {}
</script>