- function Person(name) {
- this.name = name
- }
- Person.prototype.sayName = () => {
- console.log('name')
- }
-
- function Stu(age) {
- this.age = age
- }
-
- const s = new Stu(18)
-
- console.log(s) // {age: 18}
说明:
- 想让s这个对象内部有一个name属性, 并且可以使用 sayName 这个方法
- 可以通过继承的方式让Stu这个类, 继承上Person这个类内部的属性与原型上的方法
- 核心: 就子类的原型指向父类的实例化对象
- 优点: 实现了继承
- 缺点: 继承了属性, 但是不在自己身上,失去了自己的原型
- // 1. Person父类
- function Person(name) {
- this.name = name
- }
- Person.prototype.sayName = () => {
- console.log('name')
- }
-
- // 2. Person子类
- function Stu(age) {
- this.age = age
- }
- Stu.prototype.abc = () => {
- console.log(123)
- }
- // 原型的继承
- Stu.prototype = new Person('QF001')
- Stu.prototype.abc2 = () => {
- console.log(456)
- }
-
- const s = new Stu(18)
-
- // 需求:使用Person内部的name和sayName 方法
- console.log(s)

- 先在对象内部查找name属性, 然后发现对象内部没有这个属性
- 再去对象内部的 __proto__ 上查找, 对象的__proto__ 指向了自己构造函数的原型,也就是指向了 Stu.prototype
- 因为我们手动修改了 Stu.prototype, 给他赋值为了 Person 构造函数的实例化对象
- 也就是说我们 Stu.prototype就指向了 Person的实例化对象
- Person的实例化对象内部有一个属性叫做name, 此时找到并返回
- function Person(name) {
- this.name = name
- }
- Person.prototype.sayName = () => {
- console.log('name')
- }
-
- // 2. Person子类
- function Stu(age) {
- this.age = age
- }
- Stu.prototype.abc = () => {
- console.log(123)
- }
- // 原型的继承
- Stu.prototype = new Person('QF001')
- Stu.prototype.abc2 = () => {
- console.log(456)
- }
- const s = new Stu(18)
-
- console.log(s)
- console.log(s.age)
- console.log(s.name)
- s.sayName()

- 核心: 借用 call 方法修改 父类构造函数内部的 this 指向
- 优点: 将属性继承在自己身上,保留了自己的原型
- 缺点: 只能继承父类的属性, 不能继承父类原型上的方法
- // 父类
- function Person(name) {
- this.abc = name;
- this.name = name;
- }
- Person.prototype.sayName = () => {
- console.log('name');
- }
-
- // Person的自类
- function Stu(age) {
- this.age = age;
- // .call 改变Stu的this指向父类
- Person.call(this, 'QF002');
- }
-
- const s = new Stu(18);
- console.log(s)

1. 通过new关键字调用Stu这个构造函数
2. new 关键会在这个函数内部创建一个空对象, 并且会把这个函数内部的this指定刚才创建的空对象
3. 我们现在开始正常执行函数代码
给这个对象添加一个age属性, 并且给他赋值为参数age 参数 age === 18
调用Perosn 这个函数, 并通过call方法改变这个函数内部的 this 指向, this指向了刚才 new 关键字创建的对象
4. Person 函数开始执行
给这个对象 添加一个abc的属性, 并赋值为参数name 参数 name === 'QF002'
给这个对象 添加一个name的属性, 并赋值为参数name 参数 name === 'QF002'
5. 现在函数执行完毕, 然后new关键字,会将刚才创建的对象return
6. 将这个对象保存在了变量s中
7. 通过上述流程, 我们认为 这个对象中应该是 {age:18, abc: 'QF002', name: 'QF002'}
- function Person(name) {
- this.abc = name;
- this.name = name;
- }
- Person.prototype.sayName = () => {
- console.log('name');
- }
-
- function Stu(age) {
- this.age = age;
- Person.call(this, 'QF002');
- }
- const s = new Stu(18);
-
- // 需求:使用Person内部的name和sayName 方法
- console.log(s);
- console.log(s.age);
- console.log(s.abc);
- console.log(s.name);
- s.sayName() //报错:只能继承父类的属性, 不能继承父类原型上的方法

组合继承:
1. 利用原型继承,继承到父类的原型上的方法
2. 利用借用继承,继承到父类的构造函数内部的属性
好处:
1. 能继承到属性, 并且是在自己对象内部(自己身上)
2. 能够继承到父类原型上的方法
缺点: 在原型上,有一套多余的属性
- function Person(name) {
- this.abc = name;
- this.name = name;
- }
- Person.prototype.sayName = () => {
- console.log('hello');
- }
- function Stu(age) {
- this.age = age;
-
- // 2. 利用借用继承, 继承到父类的构造函数内部的属性
- Person.call(this, 'QF001');
- }
-
- // 1. 利用原型继承, 继承到父类的原型上的方法
- Stu.prototype = new Person();
- const s = new Stu(18);
-
- console.log(s);
- console.log(s.name);
- s.sayName();

核心:
- 通过for in遍历父类实例化对象上的所有属性, 拷贝到子类上,
- 它能够遍历对象内部的属性, 以及原型上
- function Person(name) {
- this.name = name;
- }
- Person.prototype.sayName = () => {
- console.log('name');
- }
-
- function Stu(age) {
- this.age = age;
- const p = new Person('QF001');
-
- for (let key in p) {
- Stu.prototype[key] = p[key];
- }
- }
- Stu.prototype.abc = () => {
- console.log(123);
- }
-
- const s = new Stu(18);
- console.log(s);

运用
- function Person(name) {
- this.name = name;
- }
- Person.prototype.sayName = () => {
- console.log('name');
- }
-
- function Stu(age) {
- this.age = age;
- const p = new Person('QF001');
-
- for (let key in p) {
- Stu.prototype[key] = p[key];
- }
- }
- Stu.prototype.abc = () => {
- console.log(123);
- }
- const s = new Stu(18);
-
- // // 需求:使Person内部的name何sayName方法
- console.log(s);
- console.log(s.age);
- console.log(s.name);
- s.abc();
- s.sayName();

ES6 类的继承
1. 语法: class 子类类名 extends 父类类名
2. 在书写子类,constructor需要在内部书写super()
注意:
1. 两个写法必须同时存在, 才能完成继承
2. super() 必须在constructor 在开始位置
类的继承, 除了能够继承 class 类, 还能够继承 ES5 的构造函数
- function Person (name) {
- this.name = name;
- }
- Person.prototype.sayName = function () {
- console.log('name');
- }
-
- class Stu extends Person {
- constructor(age) {
- super('QF001');
- this.age = age;
- }
- }
-
- const s = new Stu(18);
- console.log(s);
- console.log(s.age);
- console.log(s.name);
- s.sayName();
