一、原型链继承(8.20)
1. 原理示例:
通过函数的prototype属性给其原型添加属性或方法!
缺点:继承的引用类型的数据,在实例后别其他实例改变,会跟着改变.
看例子:
function SuperType() {
}
SuperType.prototype.colors = ["red", "blue", "green"];
var instance1 = new SuperType();
instance1.colors.push("black");
console.log(instance1.colors); //[ 'red', 'blue', 'green', 'black' ]
var instance2 = new SuperType();
console.log(instance2.colors); //[ 'red', 'blue', 'green', 'black' ]
二、借用构造函数(8.21)
理解:解决原型链继承中对原型中引用数据类型的误删改
特点: 把父类私有的属性和方法,克隆一份一样的给子类私有的属性,Father执行的时候,把Father的中的this换成Son的实例,由于并不是new Father,所以Father.prototype上的属性无关.
function SuperType() {
colors.call(this)
}
function colors() {
this.colors = ["red", "blue", "green"]
}
var instance1 = new SuperType();
instance1.colors.push("black");
console.log(instance1.colors); //[ 'red', 'blue', 'green', 'black' ]
var instance2 = new SuperType();
console.log(instance2.colors); //[ 'red', 'blue', 'green']
但他也有他的缺点: 方法都在构造函数中定义,函数复用无从谈起,另外超类型原型中定义的方法对于子类型而言都是不可见的。
三、组合继承(原型链 + 借用构造函数)(8.22)
特点: 组合继承指的是将原型链和借用构造函数技术组合到一块,从而发挥二者之长的一种继承模式。
理解: 使用原型链实现对原型属性和方法的继承,通过借用构造函数来实现对实例属性的继承,既通过在原型上定义方法来实现了函数复用,又保证了每个实例都有自己的属性。
// 父类型
function Teacher(name, age, sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
//子类型
function Student(name, age, sex, score) {
//借用构造函数
Teacher.call(this, name, age, sex);
this.score = score;
}
Student.prototype = new Teacher(); // 此时 Student.prototype 中的 constructor 被重写了,会导致 s1.constructor === Teacher
Student.prototype.constructor = Student; //将 Student 原型对象的 constructor 指针重新指向 Student 本身
// 学生特有
Student.prototype.Exam = function () {
console.log('大家好,我是学生,我是要考试的');
};
//此时s1就继承JPerson的属性和方法
var s1 = new Student('zs', 18, '男', 100);
console.log('s1',s1);//s1 Student { name: 'zs', age: 18, sex: '男', score: 100 }
var p1 = new Teacher('zs2', 28, '男');
console.log("p1",p1);//p1 Teacher { name: 'zs2', age: 28, sex: '男' }
console.log(s1.constructor === Teacher);//false
缺点: 无论什么情况下,都会调用两次超类型构造函数:一次是在创建
子类型原型的时候,另一次是在子类型构造函数内部。
四、冒充对象继承(8.23)
核心: 使用父类的构造函数来增强子类实例
特点: 把父类私有的和公有的克隆一份一样的给子类
function Son(){
var temp = new Father()
for(var k in temp){
this[k] = temp[k]
}
temp = null
}
var son = new Son()
console.log(son.sleep()) // father正在睡觉
console.log(son.look('TV')) // father正在看TV
五、原型式继承
特点: ECMAScript5 通过新增 Object.create()方法规范了原型式继承。
这个方法接收两个参数:一个用作新对象原型的对象和(可选的)一个为新对象定义额外属性的对象(可以覆盖原型对象上的同名属性),在传入一个参数的情况下,Object.create() 和 object() 方法的行为相同。
原型式继承的基本思路:
借助原型可以基于已有的对象创建新对象,同时还不必因此创建自定义类型。
function object(sourceObj) {
function Man4() {};
Man4.prototype = sourceObj;
return new Man4();
}
var Man4 = Object.create(Person4, {
name: {
value:
enumerabel:
}
})
// 以这种方式指定的任何属性都会覆盖原型对象的同名属性
六、ES6 继承
class Person {
constructor(name) {
console.log(this.name)
this.name = name || 'xixi';
}
names() {
console.log(this.name)
}
}
let p1 = new Person('wys')
p1.names()//wys
//继承Person
class children extends Person {
constructor(name) {
super(name);//父
}
}
let p2 = new children('ii')
p2.names()//'ii'