借用构造函数继承
借用继承 / call 继承
通过改变 父类 构造函数的 this 指向来达到继承效果
核心代码 在字类构造函数体内, 父类.call(字类的实例)
构造函数的执行
1. 是一个普通函数, 可以当作函数直接调用
2. 当作普通函数执行的时候, this 指向谁, 就向谁身上添加内容
3. call 方法可以改变函数的 this 指向
借用继承的优缺点
优点:
1. 继承来的属性是在自己身上
2. 我们一个实例化过程在一个位置传递参数
缺点:
1. 只能继承父类构造函数体内的内容
2. 父类原型上的内容不能继承
function Student(gender, name, age) {
this.gender = gender
// Person('Jack', 18)
// 使用 call 方法改变一下 Person 函数内部的 this 指向
// 改变成指向谁, Person 就会向谁的身上添加一个 name 一个 age
// Person.call('Jack', 18)
// 这个位置的 this 指向 Student 的实例, 因为 new Student
// Person 函数内部的 this 指向 Student 的实例 this === s
Person.call(this, name, age)
// 这个函数执行完毕以后, 会像 Student 的实例身上添加一个 name 一个 age
}
Student.prototype.study = function () {
console.log('study')
}
const s = new Student('男', 'Jack', 18)
console.log(s)
复制代码
组合继承
把 原型继承 和 借用构造函数继承 合并在一起使用
组合继承的优缺点
优点:
1. 父类构造函数体内和原型上的内容都能继承
2. 继承下来的属性放在自己身上
3. 在一个位置传递所有参数
缺点:
1. 当你给字类添加方法的时候, 实际上是添加在了父类的实例身上
function Student(gender, name, age) {
this.gender = gender
// 借用继承, 目的: 把属性继承在自己身上
Person.call(this, name, age)
}
// 原型继承, 目的: 继承父类原型上的方法
Student.prototype = new Person()
// 书写属于 Student 自己的方法
Student.prototype.study = function () { console.log('study') }
// 使用 Student 创建实例
const s = new Student('男', 'Jack', 18)
console.log(s)
复制代码
拷贝继承
拷贝继承(for in 继承)
利用 for in 循环的特点, 来继承所有的内容
先实例化一个父类的实例
使用 for in 循环来遍历这个实例对象
因为 for in 循环不光遍历对象自己, 还会遍历 __proto__
直接把父类实例身上的所有内容直接复制到字类的 prototype
核心代码
const p = new Person('Jack', 18)
for (var key in p) {
console.log(key)
}
拷贝继承的优缺点
优点:
1. 父类的构造函数体内的和原型上的都可以继承
2. constructor 能正常配套
3. 添加自己的方法的时候, 确实是在自己的原型身上
缺点:
1. for in 循环: for in 循环需要一直遍历到 Object.prototype
2. 不能继承 不可枚举 的属性
3. 继承来的属性不再自己身上
function Student(gender, name, age) {
this.gender = gender
// for in 继承
const p = new Person(name, age)
for (let key in p) {
Student.prototype[key] = p[key]
}
}
Student.prototype.study = function () { console.log('study') }
const s = new Student('男', 'Jason', 18)
console.log(s)
复制代码
寄生继承
是一种伪继承
1. 构造函数不要写 return
return 基本数据类型, 写了白写
return 复杂数据类型, 构造函数没有意义
核心代码
const instance = new Person(name, age)
return instance
function Student(name, age) {
this.gender= '男'
// 寄生继承
const instance = new Person(name, age)
return instance
}
// s 确实是 new Student 来的
// s 就是 Student 的实例, 但是真实的内容是 Person 的实例
const s = new Student('Jason', 18)
Student.prototype.study = function () {}
console.log(s)
复制代码
寄生继承 2
出现了第二种寄生继承
不直接寄生实例, 寄生原型
寄生继承的优缺点
优点: (号称完美继承)
1. 原型和构造函数体内的都能继承下来
2. 寄生原型的话, 自己的属性和方法依旧可以添加和使用
缺点:
1. 寄生实例的时候, 没有自己的任何内容
2. 寄生原型的时候, 一旦修改原型上, 父类的实例也会有这些方法
// 寄生继承2
function Student(gender) {
this.gender = gender
}
// 寄生原型
Student.prototype = Person.prototype
// 该自己的
Student.prototype.stduy = function () {}
const s = new Student('男')
console.log(s)
复制代码
寄生式组合继承(完美继承)
合并了 寄生继承 + 原型继承 + 独立第三方构造函数 + 借用继承
核心代码
(function () {
function Abc(name, age) {}
// 让 第三方构造函数 来寄生 父类 的原型
Abc.prototype = Person.prototype
Student.prototype = new Abc()
})();
复制代码
function Person(name, age) {
this.name = name
this.age = age
}
Person.prototype.sayHi = function () { console.log('hello world') }
function Student(gender, name, age) {
this.gender = gender
// 借用继承: 继承来了父类的属性
Person.call(this, name, age)
}
(function () {
function Abc(name, age) {}
// 让 第三方构造函数 来寄生 父类 的原型
Abc.prototype = Person.prototype
const a = new Abc()
Student.prototype = a
})()
// 当你去修改 Student 的 prototype 的时候
// 相当于在修改 Abc 的实例, 和 Person 父类没有任何关系
Student.prototype.study = function () { console.log('study') }
const s = new Student('男', 'Jason', 18)
console.log(s)
//从现在开始就是如下展示
// a = {
// name: 'Jack',
// age: 18,
// __proto__: Person.prototype {
// sayHi: function () {},
// __proto__: Object.prototype
// }
// }
复制代码
另外 s 的属性
此时: Student.prototype = {
name: 'Jason',
age: 18,
__proto__: Person.prototype {
sayHi: function () {},
__proto__: Object.prototype
}
}
将来实例化 s 的时候
s = {
gender: '男',
__proto__: { // 第三方构造函数的实例
name: 'Jason',
age: 18,
__proto__: Person.prototype {
sayHi: function () {},
__proto__: Object.prototype
}
}
}
复制代码
ES6 类的继承
ES6 把继承这个使用变成了 关键字
1. extends
class 字类类名 extends 父类 {}
2. super()
constructor 里面书写一个 super()
super(name, age) 等价于 Person.call(this, name, age)
注意:
1. super 需要写在 constructor 里面
2. 如果你要写自己的属性, 必须写在 super 后面
3. ES6 的继承可以继承 ES5 的构造函数也可以继承 ES6 的类
function Person(name, age) {
this.name = name
this.age = age
}
Person.prototype.sayHi = function () { console.log('hello world') }
class Student extends Person {
constructor (gender, name, age) {
super(name, age)
this.gender = gender
}
study () {
console.log('study')
}
}
const s = new Student('男', 'Jack', 18)
console.log(s)
class Abc extends Student {
constructor () {
super('女', 'Rose', 20)
}
}
const a = new Abc()
console.log(a)
复制代码
继承到这里就写完了 ,后面我们开始 jQuery.晚安
评论