JavaScript实现继承的五种方式
1.##经典继承
实现原理: 在子类的构造函数内部调用超类型构造函数。
通过使用apply()和call()方法在新创建的对象上执行构造函数
缺点: 方法都在构造函数中定义,没有用到函数的复用。
在超类型的原型中定义的方法,对子类是不可见的,所以导致所有的类型都只能使用构造函数
function SuperType(){
this.number =[1,2,6,8,9];
}
function SubType(){
//继承 SuperType
SuperType.call(this);
}
var obj = new SubType();
obj.number.push(7);
console.log(obj.number);// 1,2,6,8,9,7
var obj2 = new SubType();
console.log(obj2.number) // 1,2,6,8,9
2.组合继承(伪经典继承)
实现原理: 使用原型链实现对原型属性和方法的继承,通过借用构造函数来实习实例属性的继承
不但通过原型定义方法实习了函数的复用,又保证每个实例 都有自己的数组
它避免了原型链和借用构造函数的缺点,融合了他们的优点,成为JavaScript常用的继承模式
<script>
/**
*
* 组合继承
* call 继承属性
* prototype 继承方法
*
* */
/* Person 构造函数 */
function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype.sayHi = function () {
console.log('我是' + this.name);
};
Person.prototype.sayAge = function () {
console.log('我今年' + this.age);
};
// 学生对象和人对象其实有很多重复
// 所以我们考虑 <学生对象> 从 <人对象> 上<继承>过来一些基本的属性
function Student(name, age, classNo) {
/*
* call (打电话)借用一下 Person 构造函数
* 第一个参数:调用该函数的那个对象
* 后面的参数:作为实参传过去
**/
Person.call(this, name, age); // 借用构造函数只能借用属性
this.classNo = classNo;
}
/* 改变1 →: 尽管是空对象,但是空对象也有原型,间接继承了原型的方法 */
// new Person() 实例化一个空对象,其实我们不是用空对象的属性,而是用了对象的原型
Student.prototype = new Person();
/* 改变2 →: 这行代码写不写都不影响继承,写了显得更专业,更规范 */
// 由于上一行代码把原型改变了,constructor 没了,所以我们人为再添加一个 constructor
Student.prototype.constructor = Student;
// console.log(Student.prototype);
var p1 = new Person('大树', 48);
var stu1 = new Student('小成', 18, 313);
// 后面给 Person 添加的方法,看看后面能不能调用
Person.prototype.say666 = function(){
console.log(666);
};
console.log(p1);
console.log(stu1);
stu1.sayAge();
/*
* Student 的原型方法继承自 Person
* p1 能调用 say666,sayHi,sayAge
* stu1 也能调用 say666,sayHi,sayAge
* */
p1.say666();
stu1.say666();
console.log(stu1 instanceof Student); // true
console.log(stu1 instanceof Person); // true
console.log(stu1 instanceof Object); // true
</script>
3.原型继承
思路: 借助原型可以基于已有的对象创建对象,同时还不必因此创建自定义类型
在object()函数内部,创建一个临时的构造函数,然后将传入的对象作为这个构造函数的原型,最好返回临时的新实例
Function obj(){
Function F(){
F.prototype = o;
Return new F();
}
- 寄生继承
思路: 创建一个仅仅用于封装继承过程的函数,该函数在内部一某种方式来增强对象,最后再像真的是它做了所有的工作一样返回对象
缺点: 使用寄生式继承来为对象添加函数,会由于不能做到函数的复用二降低效率,这点和构造函数模式相似
Function createAonter (original){
var clone = object(original); // 通过构造函数创建一个新对象
Clone.sayHi = function(){// 用某种方式来增强这个函数
Alert('hi');
}
Return clone;// 返回这个对象
}
5.寄生组合式继承 类的继承用的就是这个
思路: 通过借用构造函数来继承属性,通过原型链的混成形式来继承方法
本质上就是 使用寄生式继承来继承超类型的原型,然后再将结果指定给子类型的原型
目前来说 算是最理想的继承方式了 extend() 就是用了这种方式