原型链继承
套路
- 定义父类型的构造函数
- 给父类型的原型添加方法
- 定义子类型的构造函数
- 创建父类型的实例对象赋值给子类型的原型
- 让子类型的原型对象上的 constructor 指向子类型构造函数
- 给子类型的原型添加方法
- 创建子类型的实例对象,可以调用父类型的方法
关键:子类型的原型 = 父类型的实例对象
// 父类型
function Supper(params) {
this.supper = 'supper';
}
Supper.prototype.showSupper = function(params) {
console.log(this.supper);
};
// 子类型
function Sub(params) {
this.sub = 'sub';
}
// 子类型的原型为父类型的一个实例对象,继承父类型方法
Sub.prototype = new Supper();
// 子类型的原型对象的constructor 指向子类型构造函数
Sub.prototype.constructor = Sub;
Sub.prototype.showSub = function(params) {
console.log(this.sub);
};
var sub = new Sub();
sub.showSub(); // sub
sub.showSupper(); // supper
图解:
组合继承(原型链继承+借用构造函数继承)
- 利用原型链继承实现继承父类型对象的方法
- 利用call() 借用父类型构造函数初始化相同属性
- 组合继承在 Student.prototype = new Person();这一步时,会执行 new Person()方法,这里没有必要,引出寄生组合继承 ```javascript // 父类型 function Person(name, age) { this.name = name; this.age = age; } Person.prototype.setName = function(name) { this.name = name; }; // 子类型 function Student(name, age, id) { Person.call(this, name, age); // 借用Person 得到name和age属性,call改变this指向 this.id = id; } // 子类型的原型为父类型的一个实例对象,继承父类型方法 Student.prototype = new Person(); // 子类型的原型对象的constructor 指向子类型构造函数 Student.prototype.constructor = Student; Student.prototype.setId = function(id) { this.id = id; };
var s = new Student(‘xq’, 22, 111); s.setName(‘tzq’); s.setId(14); console.log(s.name, s.age, s.id); // tzq 22 14
<a name="B3gBg"></a>
# 寄生组合继承(最理想的方式)
使用 Object.create(Sup.prototype) 方法返回一个以Person.prototype 为原型的对象,而不用执行 new Person() 方法。
`Student.prototype = Object.create(Person.prototype);`<br />**Object.create也就是说,可以把`Student.prototype`的`__proto__`(隐式原型)指向`Person.prototype`**。
这种方式的高效率体现它只调用了一次Parent构造函数,并且因此避免了在 Parent.prototype 上面创建不必要的、多余的属性。与此同时,原型链还能保持不变;因此,还能够正常使用 instanceof 和 isPrototypeOf。开发人员普遍认为寄生组合式继承是引用类型最理想的继承范式。——引用《JavaScript高级程序设计》
```javascript
// 父类型
function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype.setName = function(name) {
this.name = name;
};
// 子类型
function Student(name, age, id) {
Person.call(this, name, age); // 借用Person 得到name和age属性,call改变this指向
this.id = id;
}
// 子类型的原型指向返回一个以Person.prototype为原型的对象
Student.prototype = Object.create(Person.prototype);
// 子类型的原型对象的constructor 指向子类型构造函数
Student.prototype.constructor = Student;
Student.prototype.setId = function(id) {
this.id = id;
};
var s = new Student('xq', 22, 111);
s.setName('tzq');
s.setId(14);
console.log(s.name, s.age, s.id);
// tzq 22 14
红宝书寄生组合继承
function inherit(child, parent) {
const prototype = Object.create(parent.prototype) // 创建对象
prototype.constructor = child // 增强对象
child.prototype = prototype // 赋值对象
}
寄生组合继承:ES6的extends继承
// ES6
class Parent{
constructor(name){
this.name = name;
}
static sayHello(){
console.log('hello');
}
sayName(){
console.log('my name is ' + this.name);
return this.name;
}
}
class Child extends Parent{
constructor(name, age){
super(name);
this.age = age;
}
sayAge(){
console.log('my age is ' + this.age);
return this.age;
}
}
let parent = new Parent('Parent');
let child = new Child('Child', 18);
console.log('parent: ', parent); // parent: Parent {name: "Parent"}
Parent.sayHello(); // hello
parent.sayName(); // my name is Parent
console.log('child: ', child); // child: Child {name: "Child", age: 18}
Child.sayHello(); // hello
child.sayName(); // my name is Child
child.sayAge(); // my age is 18
两条:原型链
// 1、构造器原型链
Child.__proto__ === Parent; // true
Parent.__proto__ === Function.prototype; // true
Function.prototype.__proto__ === Object.prototype; // true
Object.prototype.__proto__ === null; // true
// 2、实例原型链
child.__proto__ === Child.prototype; // true
Child.prototype.__proto__ === Parent.prototype; // true
Parent.prototype.__proto__ === Object.prototype; // true
Object.prototype.__proto__ === null; // true
如图:
结合代码和图片:ES6 extends继承,过程:
- 把子类构造函数(
Child
)的隐式原型(__proto__
)指向了父类构造函数(Parent
) - 把子类实例对象(
child
)的原型对象(Child.prototype
)的隐式原型(__proto__
)指向父类实例对象(parent
)的原型对象(Parent.prototype
) - 子类构造函数(
Child
)继承了父类构造函数(Parent
)里的方法,使用super
调用(ES5
则用call
或者apply
调用传参)
总结
寄生组合式继承是开发者使用比较多的。 回顾寄生组合式继承。主要就是三点:
- 子类构造函数的
__proto__
指向父类构造器,继承父类的静态方法。 - 子类构造函数的原型对象
prototype
的隐式原型__proto__
指向父类构造器的原型对象prototype
,继承父类的方法。 - 子类构造器里调用父类构造器,继承父类的属性。