继承性
- js中继承目的: 把子类型中共同的属性和方法提取到父类型中
- 较少代码的冗余度, 提升代码的复用性
实现继承的方法
1.借用原型链实现继承
直接将子类的原型对象修改为父类对象, 这样就能使用原型链上的属性和方法
function Person() {
this.name = null;
this.age = 0;
this.say = function () {
console.log(this.name, this.age);
}
}
let per = new Person();
per.name = "lnj";
per.age = 34;
per.say();
// 在企业开发中如果构造函数和构造函数之间的关系是is a关系, 那么就可以使用继承来优化代码, 来减少代码的冗余度
// 学生 is a 人 , 学生是一个人
function Student() {
// this.name = null;
// this.age = 0;
// this.say = function () {
// console.log(this.name, this.age);
// }
this.score = 0;
this.study = function () {
console.log("day day up");
}
}
Student.prototype = new Person();
Student.prototype.constructor = Student;
let stu = new Student();
stu.name = "zs";
stu.age = 18;
stu.score = 99;
stu.say();
stu.study();
弊端:无法在创建的时候指定相关的属性,因为创建的时候并没有从父类上面继承过来的额属性和方法,只有当执行到Student.prototype = new Person();才存在这些数据
function Person(myName, myAge) {
this.name = myName;
this.age = myAge;
this.say = function () {
console.log(this.name, this.age);
}
}
function Student(myName, myAge, myScore) {
//this.name,this.age在此时创建的时候并没有从父类继承,所以 myName, myAge 无法创建给其使用
this.score = myScore;
this.study = function () {
console.log("day day up");
}
}
2.借用构造函数实现继承
在子类中调用父类构造函数, 并且将
父类构造函数的this
修改为子类对象
function Person(myName, myAge) {
// let per = new Object();
// let this = per;
// this = stu;
this.name = myName; // stu.name = myName;
this.age = myAge; // stu.age = myAge;
this.say = function () { // stu.say = function () {}
console.log(this.name, this.age);
}
// return this;
}
function Student(myName, myAge, myScore) {
// let stu = new Object();
// let this = stu;
Person.call(this, myName, myAge); // Person.call(stu);
this.score = myScore;
this.study = function () {
console.log("day day up");
}
// return this;
}
let stu = new Student("ww", 19, 99);
// stu.name = "zs";
// stu.age = 18;
// stu.score = 99;
console.log(stu.score);
stu.say();
stu.study();
3.借用构造函数+借用原型链组合继承
- 通过借用构造函数实现属性继承
- 通过借用原型链实现方法继承
function Person(myName, myAge) {
// let per = new Object();
// let this = per;
// this = stu;
this.name = myName; // stu.name = myName;
this.age = myAge; // stu.age = myAge;
// this.say = function () { // stu.say = function () {}
// console.log(this.name, this.age);
// }
// return this;
}
Person.prototype.say = function () {
console.log(this.name, this.age);
}
function Student(myName, myAge, myScore) {
Person.call(this, myName, myAge);
this.score = myScore;
this.study = function () {
console.log("day day up");
}
}
let stu = new Student("ww", 19, 99);
console.log(stu.score);
stu.say(); // 报错: stu.say is not a function
stu.study();
构造函数创建对象,本质上是使用new Object()创建一个对象,通过改变this指向Student,Person内的属性和方法就可以被Student访问,但是Person.prototype也是一个对象,指向的是Person
要想使用Person原型对象中的属性和方法, 那么就必须将Student的原型对象改为Person的原型对象才可以
function Person(myName, myAge) {
// let per = new Object();
// let this = per;
// this = stu;
this.name = myName; // stu.name = myName;
this.age = myAge; // stu.age = myAge;
// this.say = function () { // stu.say = function () {}
// console.log(this.name, this.age);
// }
// return this;
}
Person.prototype.say = function () {
console.log(this.name, this.age);
}
function Student(myName, myAge, myScore) {
Person.call(this, myName, myAge);
this.score = myScore;
this.study = function () {
console.log("day day up");
}
}
// 注意点: 要想使用Person原型对象中的属性和方法, 那么就必须将Student的原型对象改为Person的原型对象才可以
Student.prototype = Person.prototype;
Student.prototype.constructor = Student;
let stu = new Student("ww", 19, 99);
console.log(stu.score);
stu.say();
stu.study();
弊端:
- 1.由于修改了Person原型对象的constructor属性, 所以破坏了Person的三角恋关系
Student.prototype = Person.prototype ;原型对象改为Person的原型对象,改变了constructor的指向,为了不破坏Student原有的关系, 在给prototype赋值的时候, 需要在自定义的对象中手动的添加constructor属性, 手动的指定需要指向谁(但是Student.prototype = Person.prototype为浅复制,修改了constructor,Person的constructor也会改变)
- 2.由于Person和Student的原型对象是同一个, 所以给Student的元素添加方法, Person也会新增方法
4. 终极方案
- 1在子类的构造函数中通过
call
借助父类的构造函数 - 2将
子类的原型对象
修改为父类的实例对象
Student.prototype = new Person();
Student.prototype.constructor = Student;
function Person(myName, myAge) {
// let per = new Object();
// let this = per;
// this = stu;
this.name = myName; // stu.name = myName;
this.age = myAge; // stu.age = myAge;
// this.say = function () { // stu.say = function () {}
// console.log(this.name, this.age);
// }
// return this;
}
Person.prototype.say = function () {
console.log(this.name, this.age);
}
function Student(myName, myAge, myScore) {
Person.call(this, myName, myAge);
this.score = myScore;
this.study = function () {
console.log("day day up");
}
}
Student.prototype = new Person();
Student.prototype.constructor = Student;
Student.prototype.run = function(){
console.log("run");
}
let per = new Person();
per.run(); // 报错
学习笔记❥(^_-)