1.为什么需要继承
// Student
function Student(name,age,sno) {
this.name = name;
this.age = age;
this.sno = sno;
}
Student.prototype.running = function () {
console.log(this.name + "running");
}
Student.prototype.eating = function () {
console.log(this.name + "eating~");
}
Student.prototype.studing = function () {
console.log(this.name + "studing~");
}
// Teacher
function Teacher(name,age,title) {
this.name = name;
this.age = age;
this.title = title;
}
Teacher.prototype.running = function() {
console.log(this.name + " running~")
}
Teacher.prototype.eating = function() {
console.log(this.name + " eating~")
}
Teacher.prototype.teaching = function() {
console.log(this.name + " teaching")
}
在这里我们定义2个构造函数 来生产一些类,我们发现了大量的重复代码,因此我们可以封装一个功能从而节约代码的体积,所以我们引出了继承
2.原型链实现继承
// 父类 公共属性和方法
function Person () {
this.name = "why";
this.friends = [];
}
Person.prototype.eating = function () {
console.log(this.name + "eating~");
}
// 子类: 特有属性和方法
function Student() {
this.son = 11;
}
let p = new Person()
Student.prototype = p
Student.prototype.studying = function() {
console.log(this.name + " studying~")
}
// 原型链实现继承的弊端: 无法枚举的,因此无法查到
// 1.第一个弊端: 打印stu对象, 继承的属性是看不到的
// console.log(stu.name)
// 2.第二个弊端: 创建出来两个stu的对象
let stu1 = new Student()
let stu2 = new Student()
// 直接修改对象上的属性, 是给本对象添加了一个新属性
stu1.name = "kobe"
console.log(stu2.name)
// 获取引用, 修改引用中的值, 会相互影响
stu1.friends.push("kobe")
console.log(stu1.friends) // kobe
console.log(stu2.friends) // kobe
// 3.第三个弊端: 在前面实现类的过程中都没有传递参数
let stu3 = new Student("lilei", 112);
3.借用构造函数实现
// 父类: 公共属性和方法
function Person(name, age, friends) {
// this = stu
this.name = name
this.age = age
this.friends = friends
}
Person.prototype.eating = function() {
console.log(this.name + " eating~")
}
// 子类: 特有属性和方法
function Student(name, age, friends, sno) {
Person.call(this, name, age, friends) // -这句代码借用构造函数实现继承
// this.name = name
// this.age = age
// this.friends = friends
this.sno = 111
}
var p = new Person()
Student.prototype = p
Student.prototype.studying = function() {
console.log(this.name + " studying~")
}
// name/sno
var stu = new Student("why", 18, ["kobe"], 111)
// console.log(stu.name)
// stu.eating()
// stu.studying()
// 原型链实现继承已经解决的弊端
// 1.第一个弊端: 打印stu对象, 继承的属性是看不到的
console.log(stu)
// 2.第二个弊端: 创建出来两个stu的对象
var stu1 = new Student("why", 18, ["lilei"], 111)
var stu2 = new Student("kobe", 30, ["james"], 112)
// // 直接修改对象上的属性, 是给本对象添加了一个新属性
// stu1.name = "kobe"
// console.log(stu2.name)
// // 获取引用, 修改引用中的值, 会相互影响
stu1.friends.push("lucy")
console.log(stu1.friends)
console.log(stu2.friends)
// // 3.第三个弊端: 在前面实现类的过程中都没有传递参数
// var stu3 = new Student("lilei", 112)
// 强调: 借用构造函数也是有弊端:
// 1.第一个弊端: Person函数至少被调用了两次
// 2.第二个弊端: stu的原型对象上会多出一些属性, 但是这些属性是没有存在的必要
4.寄生组合式继承
function Person(name, age, friends) {
this.name = name
this.age = age
this.friends = friends
}
Person.prototype.eating = function () {
console.log("eating")
}
Person.prototype.running = function () {
console.log("running");
}
function Student(name, age, friends, son, score) {
Person.call(this, name, age, friends)
this.son = son
this.score = score
}
function inhertPrototype(son, father) {
son.prototype = Object.create(father.prototype);
Object.defineProperty(son.prototype, "constructor", {
enumerable: false,
configurable: true,
writable: true,
value: son
})
}
inhertPrototype(Student, Person);
Student.prototype.studying = function () {
console.log("studying");
}
let sty1 = new Student("why", 22, ["kobel"], 12, 98);
console.log(sty1);
sty1.studying();
sty1.eating();
sty1.running();
5.es6中的继承
class Person {
constructor(name, age) {
this.name = name
this.age = age
}
running() {
console.log(this.name + " running~")
}
eating() {
console.log(this.name + " eating~")
}
personMethod() {
console.log("处理逻辑1")
console.log("处理逻辑2")
console.log("处理逻辑3")
}
static staticMethod() {
console.log("PersonStaticMethod")
}
}
// Student称之为子类(派生类)
class Student extends Person {
// JS引擎在解析子类的时候就有要求, 如果我们有实现继承
// 那么子类的构造方法中, 在使用this之前
constructor(name, age, sno) {
super(name, age)
this.sno = sno
}
studying() {
console.log(this.name + " studying~")
}
// 类对父类的方法的重写
running() {
console.log("student " + this.name + " running")
}
// 重写personMethod方法
personMethod() {
// 复用父类中的处理逻辑
super.personMethod()
console.log("处理逻辑4")
console.log("处理逻辑5")
console.log("处理逻辑6")
}
// 重写静态方法
static staticMethod() {
super.staticMethod()
console.log("StudentStaticMethod")
}
}
var stu = new Student("why", 18, 111)
console.log(stu)
// console.log(Object.getOwnPropertyDescriptors(stu.__proto__))
// console.log(Object.getOwnPropertyDescriptors(stu.__proto__.__proto__))
stu.eating()
stu.running()
stu.personMethod()
Student.staticMethod()
console.log(Object.getOwnPropertyDescriptors(Person))