Open zhaobinglong opened 4 years ago
• 子类去new实例时,无法向父类构造函数传参 • 父类的引用类型的属性被所有实例共享(最大的缺点)
// 父类构造函数
function Parent2() {
this.name = 'parent2';
this.play = [1, 2, 3] // 数组类型的属性会被所有的实例共享
}
Parent2.prototype.age='100' // 给构造函数添加原型属性(原型属性会直接显示在子类的属性中)
// 子类
function Child2() {
this.type = 'child2';
}
// 核心代码,原型继承的本质是把父类的实例赋值给子类的原型对象prototype
Child2.prototype = new Parent2();
var s1 = new Child2(); // 实例化一个Child2出来,并不能向Parent2传递参数
var s2 = new Child2();
s1.play.push(4);
console.log(s1.play, s2.play);
为什么不指向父类的原型,而是父类的一个实例?因为如果子类的原型直接指向父类的原型,那么子类就无法获取父类构造函数定义的属性和函数,同时修改子类的原型也会影响到父类的原型,这是违背继承的原则的。
缺点:
function Animal(name) {
this.name = name;
}
Animal.prototype.eat= function () {
console.log(this.name + '正在吃东西')
};
function Cat(furColor){
Animal.call(this,'小花猫'); // 核心代码, 利用call和apply在子类的构造函数中调用父类的构造函数。,这样子类就可以使用父类的属性
// Animal.apply(this, ['小花猫']);
this.name = ''
this.furColor = furColor ;
};
let tom = new Cat('black');
console.log(tom);
console.log(tom instanceof Animal); // false,实例并不是父类的实例,只是子类的实例,原因也是因为没有继承Animal的原型
console.log(tom instanceof Cat); // true.
缺点:没有缺点,解决了前面两个方法的问题
//父类:人
function Person () {
this.head = '脑袋瓜子';
this.emotion = ['喜', '怒', '哀', '乐']; //人都有喜怒哀乐
}
//将 Person 类中需共享的方法放到 prototype 中,实现复用
Person.prototype.eat = function () {
console.log('吃吃喝喝');
}
//子类:学生,继承了“人”这个类
function Student(studentID) {
this.studentID = studentID;
Person.call(this);
}
//核心代码1: 此时 Student.prototype 中的 constructor 被重写了,会导致 stu1.constructor === Person
Student.prototype = new Person();
//核心代码2: 将 Student 原型对象的 constructor 指针重新指向 Student 本身
Student.prototype.constructor = Student;
var stu1 = new Student(1001);
console.log(stu1.emotion); //['喜', '怒', '哀', '乐']
stu1.emotion.push('愁');
console.log(stu1.emotion); //["喜", "怒", "哀", "乐", "愁"]
var stu2 = new Student(1002);
console.log(stu2.emotion); //["喜", "怒", "哀", "乐"]
stu1.eat(); //吃吃喝喝
stu2.run(); //快跑
console.log(stu1.constructor); //Student
实质是先将父类实例对象的属性和方法,加到this上面(所以必须先调用super方法),然后再用子类的构造函数修改this。 需要注意的是,class关键字只是原型的语法糖,JavaScript继承仍然是基于原型实现的。
缺点:不是所有浏览器都支持(随着时间的推移这个问题就不存在了)
class Animal {
constructor(name) {
this.name = name;
};
eat() {
console.log(this.name + '正在吃东西');
};
}
var animal = new Animal('小猫咪');
animal.eat();// 小猫咪正在吃东西
//.....省略上面Animal类
class Cat extends Animal {
// Tips: 这里有一个小的知识点,就是ES6的继承方法中如果子类没有写构造函数的话就一般默认添加构造。
constructor(name) {
//super作为函数调用时,代表父类的构造函数。
super(name);
}
catchMouse(){
console.log(`${this.name}正在捉老鼠`);
}
}
var cat= new Cat('Tom猫');
cat.catchMouse();// Tom猫正在捉老鼠
关键字extends 允许一个子类继承父类,需要注意的是,子类的constructor 函数中需要执行 super() 函数。 当然,你也可以在子类方法中调用父类的方法,如super.parentMethodName()。
class Phone { constructor(name) { this.name = name console.log("I'm a phone."); } }
class MI extends Phone { constructor() { // 类似于call的继承:在这里super相当于把父类的constructor给执行了,并且让方法中的this是B的实例, // super当中传递的实参都是在给A的constructor传递。 super('kk'); console.log("I'm a phone designed by xiaomi"); } }
let mi8 = new MI();
面向对象的缺点
面向对象继承的缺点:无法决定继承哪些属性,所有属性都得继承。
参考:
https://zhuanlan.zhihu.com/p/47703221 https://www.jianshu.com/p/d5299ca26e4e