JavaScript的继承整理
閱讀時間:全文 1031 字,預估用時 6 分鐘
創作日期:2020-05-08
上篇文章:React-Hooks源码阅读
BEGIN
准备
定义父类
- 定义Father类和Mother类
- Father会下象棋
- Mother会做饭
- Father和Mother都会吃东西
function Father (name) {
this.name = name || 'Father';
this.gender = 'men';
this.chess = function () {
console.log(this.name, 'can chess!')
}
}
Father.prototype.eat = function (food) {
console.log(this.name, 'eating', food);
}
function Mother (name) {
this.name = name || 'Mother';
this.gender = 'women';
this.cook = function () {
console.log(this.name, 'can cook!')
}
}
Mother.prototype.eat = function (food) {
console.log(this.name, 'eating', food);
}
Object.create实现
Object.create
是ES5新增的方法, 在此之前可通过自己定义函数实现, 参考《JavaScript语言精粹》的实现:
function create (o) {
var F = function() {};
F.prototype = o;
return new F();
}
拷贝继承
function Child (name) {
var father = new Father();
for (var key in father) {
Child.prototype[key] = father[key];
}
var mother = new Mother();
for (var key in mother) {
Child.prototype[key] = mother[key];
}
Child.prototype.name = name || 'child';
}
- 通过对父类的实例化对象的属性和方法拷贝达到继承父类方法和属性
- 无法获取父类不可枚举方法和属性
var child = new Child();
console.log(child.name); // child
console.log(child.gender); // women
console.log(child.chess()); // child can chess!
console.log(child.cook()); // child can cook!
console.log(child.eat('fish')); // child eat fish
console.log(child instanceof Child); // true
console.log(child instanceof Father); // false
console.log(child instanceof Mother); // false
原型链继承
function Child () {};
Child.prototype = new Father();
Child.prototype.name = 'child';
- 也叫伪类继承
- 只能继承单一父类
- 原型对象的所有属性被所有实例共享.
- 通过修改prototype指向的方式实现继承, 指向实例化后的对象或者对象字面量, 即:
Child.prototype = new Father();
Child.prototype = { name: 'Father', ... };
var child = new Child();
console.log(child.name); // child
console.log(child.gender); // men
console.log(child.chess()); // child can chess!
console.log(child.eat('fish')); // child eating fish
console.log(child instanceof Child); // true
console.log(child instanceof Father); // true
构造继承
function Child (name) {
Father.call(this);
Mother.call(this);
this.name = name || 'child';
}
- 通过call调用达到父类实例方法和实例属性与当前this绑定
- 只继承父类的实例方法和属性(捆绑于this), 原型方法和属性无法继承
- 可以多继承
- 能继承弗雷的实例方法和属性, 却与父类无任何关系
var child = new Child();
console.log(child.name); // child
console.log(child.gender); // women
console.log(child.chess()); // child can chess!
console.log(child.cook()); // child can cook!
console.log(child.eat('fish')); // TypeError: child.eat is not a function
console.log(child instanceof Child); // true
console.log(child instanceof Father); // false
console.log(child instanceof Mother); // false
寄生式继承
// 实例方式实现, 生成伪类的实例化对象, 给对象增加属性并返回
function Child () {
var instance = new Father();
instance.name = 'child';
return instance;
}
// 对象字面量方式实现, obj = { name: 'Father', ... }
function Child (obj) {
var instance = object(obj);
instance.name = 'child';
return instance;
}
- 也叫寄生式继承
- 返回的实例与中间函数不存在继承关系
- 寄生概念的理解: 创建一个仅用于封装继承过程的函数, 函数返回封装后的存在继承关系的主体
var child = Child();
// 或 var child = new Child();
console.log(child.name); // child
console.log(child.gender); // men
console.log(child.chess()); // child can chess!
console.log(child.eat('fish')); // child eating fish
console.log(child instanceof Child); // false
console.log(child instanceof Father); // true
组合继承
function Child (name) {
Father.call(this);
Mother.call(this);
this.name = name || 'child';
}
Child.prototype = new Father();
Child.prototype.constructor = Child;
- 组合继承其实就是将原型链继承和构造继承相结合
- 通过原型链继承方式解决构造继承方式无法继承原型方法和属性的问题
- 原型链继承只能继承一个父类
- 父类会执行2次
- 此继承继承了: this下属性和方法 + prototype下属性和方法 + this下属性和方法
var child = new Child();
console.log(child.name); // child
console.log(child.gender); // women
console.log(child.chess()); // child can chess!
console.log(child.cook()); // child can cook!
console.log(child.eat('fish')); // child eat fish
console.log(child instanceof Child); // true
console.log(child instanceof Father); // true
console.log(child instanceof Mother); // false
寄生组合式继承
function Child (name) {
Father.call(this);
Mother.call(this);
this.name = name || 'child';
}
Child.prototype = create(Father.prototype);
Child.prototype.constructor = Child;
- 也叫组合寄生继承
- 和组合继承的差别在于避免重复实例化或执行父类, 和组合式继承相比不用继承实例化对象的属性和方法, 因为也没必要
- 此继承继承了: this下属性和方法 + prototype下属性和方法
var child = new Child();
console.log(child.name); // child
console.log(child.gender); // women
console.log(child.chess()); // child can chess!
console.log(child.cook()); // child can cook!
console.log(child.eat('fish')); // child eat fish
console.log(child instanceof Child); // true
console.log(child instanceof Father); // true
console.log(child instanceof Mother); // false
参考
FINISH
上篇文章:React-Hooks源码阅读