在学习继承之前,我们要知道一个概念,那就是原型和原型对象。
原型对象:原型对象是构造函数(也就是非箭头函数)所特有的一块区域,用来共享实例间的数据。
原型就是[[prototype]]指向的区域,所有的引用类型都具有[[prototype]]属性。
还需要了解一个知识,构造函数的实例对象中的原型,默认指向该构造函数的原型对象,并且js在查找数据时,会顺着原型链向上查找,直到寻找到原型链的终点null返回undefined。
好了,现在我们进入主题,了解js的继承机制。
1. 使用原型链继承
思想: 让派生构造函数的原型对象指向父构造函数的实例。
- 优势:所有派生构造函数的实例都可以使用父构造函数原型对象中的方法
- 不足:所有派生构造函数的实例共用同一个父构造函数实例的属性
colors
function SuperType (){
this.colors = ['red', 'black'];
}
function SubType(){
this.name = '哈哈'
}
SubType.prototype = new SuperType();
let instance1 = new SubType();
let instance2 = new SubType();
instance1.colors.push('white')
console.log(instance2.colors);// ['red', 'black', 'white']
由于原型链的继承方式的不足,我们引入了一种新的继承法方式。
2. 盗用构造函数
思想: 在派生构造函数中调用父构造函数
- 优点:继承了父构造函数中的属性,并且实例间不在共享
- 不足:派生构造函数的实例不可以使用父构造函数原型对象中方法
function SuperType (){
this.colors = ['red', 'black'];
}
SuperType.prototype.getColors = function(){
console.log(this.colors);
}
function SubType(){
SuperType.call(this);
}
let instance1 = new SubType();
let instance2 = new SubType();
instance1.colors.push('blue')
console.log(instance2.colors)// ['red', 'black']
console.log(instance1.colors) // ['red', 'black', 'blue']
这样我们将原型链和盗用构造函数两种继承方式优势相结合,就产生了一种新的继承方式。
3. 组合继承
思想: 结合了原型链和盗用构造函数的思想。
- 优点:实现了继承的基本模式,派生构造函数实例中有了父构造函数的属性,并且实例之间不会共享,也可以使用父构造函数原型对象中的方法。
- 不足:可以看到,父构造函数执行了两次,第一次是将其实例对象赋值给
oldPeople的时候,第二次是创建子实例的时候。
function People( gender ){
this.gender = gender;
}
People.prototype.say = function () {
console.log('我的性别', this.gender, this. age);
}
function oldPeople(name, gender, age){
People.call(this, sex);
this.name = name;
this.age = age;
}
oldPeople.prototype = new People();
let oldWoman = new oldPeople('小红', '女', 80);
let oldMan = new oldPeople('小明', '男', 81);
oldWoman.say(); // 我的性别是女 80
oldMan.say();// 我的性别是女 81
4. 原型式继承
思想: 将子对象的原型指向父对象
- 优点:不需要单独创建构造函数,就可以在对象间共享信息
- 不足:同原型继承一样,子对象共享父对象的属性
该种继承方式规范化其实就是Object.create的静态方法
function object (o) {
function F() {}
F.prototype = o;
return new F();
}
let person = {
name: '小明',
friends: ['小红','小绿']
}
let clone = object(person);
5. 寄生式继承
思想: 该思想同原型式继承一样,只是为对象新增了一个新的方法
function object(o){
function fn (){};
fn.prototype = o;
return new fn();
}
function createAnother( original ){
let clone = object(original)
clone.sayHi = function(){
console.log('Hi');
}
return clone;
}
let person = {
name: '小明',
friends: ['小红', '小蓝']
}
let anotherPerson = createAnother(person);
anotherPerson.sayHi();
6. 寄生式组合继承
思想: 使用寄生式继承来继承父类原型,然后盗用构造函数的思想继承父类属性。
寄生式继承可以算是引用类型继承的最佳模式了
function SuperType (name){
this.name = name;
}
SuperType.prototype.sayName = function(){
console.log(this.name)
}
function SubType(age, name){
SuperType.call(this, name);
this.age = age
}
function inheritPrototype (SubType, SuperType){
let prototype = SuperType.prototype;
prototype.constructor = SubType;
SubType.prototype = prototype;
}
inheritPrototype(SubType, SuperType);
SubType.prototype.sayAge = function (){
console.log(this.age);
}
let person1 = new SubType(12, '小明');
let person2 = new SubType(18, '小红');
person1.sayAge();
person1.sayName();
person2.sayAge();
person2.sayName();
以上就是 js中 实现继承的全部方式,在ES6之后,出现了 class 和 extends,其背后思想其实就是使用构造函数的继承来实现的。

436

被折叠的 条评论
为什么被折叠?



