文章目录
前言
提示:需要掌握如下知识点
- 原型链
- 箭头函数与普通函数的区别
一、原型链的继承
1. 代码
function Person() {
this.name = "小明"
this.eats = ["苹果"]
// 此处使用普通函数,输出结果看下面的第一张图片
this.getName = function () {
console.log(this.name)
}
// 此处使用箭头函数,输出结果看下面的第二张图片
/*this.getName = () => {
console.log(this.name)
}*/
}
Person.prototype.get = function () {
console.log("Person.prototype 上的方法!")
}
function Student() {
}
Student.prototype = new Person()
let stu1 = new Student()
stu1.name = "小花"
stu1.eats.push("香蕉")
console.log(stu1.name); // 输出:小花
console.log(stu1.eats); // 输出:['苹果','香蕉']
stu1.getName() // 输出:小花
stu1.get() // 输出:Person.prototype 上的方法!
console.log("--------------")
let stu2 = new Student()
console.log(stu2.name); // 输出:小明
console.log(stu2.eats); // 输出:['苹果','香蕉']
stu2.getName() // 输出:小明
stu2.get() // 输出:Person.prototype 上的方法!
2. 输出结果
图1:
图2:
3. 优缺点
优点: 父类方法可以复用
缺点:
- 父类所有的引用类型数据(对象,数组)会被子类共享,更改一个子类的数据,其他数据会受到影响,一直变化
- 子类实例不能给父类构造函数传参
二、构造函数的继承
1. 代码
function Person() {
this.name = "小明"
this.eats = ["苹果"]
// 此处使用普通函数,输出结果看下面的第一张图片
this.getName = function () {
console.log(this.name)
}
// 此处使用箭头函数,输出结果看下面的第二张图片
/*this.getName = () => {
console.log(this.name)
}*/
}
Person.prototype.get = function () {
console.log("Person.prototype 上的方法!")
}
function Student() {
Person.call(this)
}
let stu1 = new Student()
stu1.name = "小花"
stu1.eats.push("香蕉")
console.log(stu1.name); // 输出:小花
console.log(stu1.eats); // 输出:['苹果','香蕉']
stu1.getName() // 输出:小花
// stu1.get() //
console.log("--------------")
let stu2 = new Student()
console.log(stu2.name); // 输出:小明
console.log(stu2.eats); // 输出:['苹果']
stu2.getName() // 输出:小明
// stu2.get() // 输出:Person.prototype 上的方法!
2. 输出结果
3. 优缺点
优点: 父类的引用类型的数据不会被子类共享,不会互相影响
缺点: 子类不能访问父类原型属性上的方法和参数
三、组合继承
1. 代码
function Person() {
this.name = "小明"
this.eats = ["苹果"]
// 此处使用普通函数,输出结果看下面的第一张图片
this.getName = function () {
console.log(this.name)
}
// 此处使用箭头函数,输出结果看下面的第二张图片
/*this.getName = () => {
console.log(this.name)
}*/
}
Person.prototype.get = function () {
console.log("Person.prototype 上的方法!")
}
function Student() {
Person.call(this)
}
Student.prototype = new Person()
let stu1 = new Student()
stu1.name = "小花"
stu1.eats.push("香蕉")
console.log(stu1.name); // 输出:小花
console.log(stu1.eats); // 输出:['苹果','香蕉']
stu1.getName() // 输出:小花
stu1.get() // 输出:Person.prototype 上的方法!
console.log("--------------")
let stu2 = new Student()
console.log(stu2.name); // 输出:小明
console.log(stu2.eats); // 输出:['苹果']
stu2.getName() // 输出:小明
stu2.get() // 输出:Person.prototype 上的方法!
2. 输出结果
3. 优缺点
优点:
- 父类可以复用
- 父类构造函数中的引用属性数据不会被共享
缺点: 会调用两次父类的构造函数,会有两份一样的属性和方法,会影响性能
四、寄生组合继承
1. 代码
function Person() {
this.name = "小明"
this.eats = ["苹果"]
// 此处使用普通函数,输出结果看下面的第一张图片
this.getName = function () {
console.log(this.name)
}
// 此处使用箭头函数,输出结果看下面的第二张图片
/*this.getName = () => {
console.log(this.name)
}*/
}
Person.prototype.get = function () {
console.log("Person.prototype 上的方法!")
}
function Student() {
Person.call(this)
}
const Fn = function(){
}
Fn.prototype = Person.prototype
Student.prototype = new Fn()
let stu1 = new Student()
stu1.name = "小花"
stu1.eats.push("香蕉")
console.log(stu1.name); // 输出:小花
console.log(stu1.eats); // 输出:['苹果','香蕉']
stu1.getName() // 输出:小花
stu1.get() // 输出:Person.prototype 上的方法!
console.log("--------------")
let stu2 = new Student()
console.log(stu2.name); // 输出:小明
console.log(stu2.eats); // 输出:['苹果']
stu2.getName() // 输出:小明
stu2.get() // 输出:Person.prototype 上的方法!
console.log(stu2)
2. 输出结果
3. 优缺点
目前最优的一个继承方案
五、ES6的 class类继承(extends)
1. 代码
class Person {
constructor() {
this.name = "小明"
this.eats = ["苹果"]
this.getName = function () {
console.log(this.name)
}
}
get = function () {
console.log("Person.prototype 上的方法!")
}
}
class Student extends Person{
}
let stu1 = new Student()
stu1.name = "小花"
stu1.eats.push("香蕉")
console.log(stu1.name); // 输出:小花
console.log(stu1.eats); // 输出:['苹果','香蕉']
stu1.getName() // 输出:小花
stu1.get() // 输出:Person.prototype 上的方法!
console.log("--------------")
let stu2 = new Student()
console.log(stu2.name); // 输出:小明
console.log(stu2.eats); // 输出:['苹果']
stu2.getName() // 输出:小明
stu2.get() // 输出:Person.prototype 上的方法!
console.log(stu2)