JS继承的6种写法
{
/**
* 1. 原型链继承
*/
function SuperType() {
this.property = true;
}
SuperType.prototype.getSuperValue = function() {
return this.property;
};
function SubType() {
this.subproperty = false;
}
SubType.prototype = new SuperType();
SubType.prototype.getSubValue = function() {
return this.subproperty;
};
var instance = new SubType();
console.log(instance.getSuperValue());
/**
* 关键问题
* 1.引用类型值的原型属性会被所有实例共享
* 2. 不能向超类型的构造函数中传递参数
*/
}
{
/**
* 2. 借用构造数据
*/
function SuperType(name) {
this.name = name;
}
function SubType() {
// 继承了SuperType, 同时传递了参数
SuperType.call(this, "hooke");
this.age = 29;
}
const instance = new SubType();
/**
* 关键问题:
* 没有函数复用
*/
}
{
/**
* 3. 组合继承
*/
function SuperType(name) {
this.name = name;
this.colors = ["red", "blue", "green"];
}
SubType.prototype.sayName = function() {
console.log(this.name);
};
function SubType(name, age) {
// 继承属性
SuperType.call(this, name);
this.age = age;
}
// 继承方法
SubType.prototype = new SubType();
SubType.prototype.sayAge = function() {
console.log(this.age);
};
// 原来Nicholas写这本书的时候,跟我一样29
const instance = new SubType("Nicholas", 29);
console.log(instance.sayAge());
/**
* 融合了原型链和借用构造函数,
* 避免了二者的缺陷,融合了他们的优势,
* 是JS中最常用的继承模式
* 能够使用instanceof和isPrototypeOf()识别对象
*
* 关键问题:
* 任何情况下,都会调用两次超类型构造函数
* 1. 创建子类型原型的时候
* 2. 子类型构造函数内部
*/
}
{
/**
* 4. 原型式继承
*/
function object(o) {
function F() {}
F.prototype = o;
return new F();
}
// ES5引入了Object.create()来规范化了原型式继承
const person = {
name: "hooke",
friends: ["zhao", "qian", "sun"]
};
const anotherPerson = Object.create(person, {
name: {
value: "huxiaohui"
}
});
/**
* 优点:
* 让一个对象和另一个对象保持相似的简单实现,
* 省去了创建构造函数的麻烦
*
* 关键问题:
* 包含引用类型值的树形始终会钟祥相应的值,就像使用原型模式一样
*/
}
{
/**
* 5. 寄生式继承
*/
function createAnother(original) {
// 调用一个函数克隆一个新对象
const clone = object(original);
clone.sayHi = function() {
console.log("hi");
};
return clone;
}
const person = {
name: "hooke",
friends: ["zhao", "qian", "sun"]
};
// 新对象不仅有person的所有属性和方法,还有自己的sayHi方法
const anotherPerson = createAnother(person);
console.log(anotherPerson.sayHi());
/**
* 关键问题:
* 没有函数复用
*/
}
{
/**
* 6. 寄生组合式继承(实现基于类型继承的最有效方式)
* 通过借用构造函数来继承属性。
* 通过原型链的混成形式来继承方法
*/
function inheritPrototype(subType, superType) {
const prototype = object(superType.prototype); // 创建对象
// 弥补因重写原型而失去的默认的constructor属性
prototype.constructor = subType; // 增强对象
subType.prototype = prototype; // 指定对象
}
function SuperType(name) {
this.name = name;
this.colors = ["red", "blue", "green"];
}
SuperType.prototype.sayName = function() {
console.log(this.name);
};
function SubType(name, age) {
SuperType.call(this, name);
this.age = age;
}
inheritPrototype(SubType, SuperType);
SubType.prototype.sayAge = function() {
console.log(this.age);
};
/**
* 仅调用了一次SuperType构造函数
* 避免了在SubType.prototype上面创建不必要的、多余的树形
* 原型链能够保持不变
* 能够使用instanceOf、isPrototypeOf()
*/
}
{
/**
* TS的继承模式: 寄生组合
*/
/**
* 编译前
*/
{
class SuperType {
constructor(public name) {}
sayName() {
console.log(this.name);
}
}
class SubType extends SuperType {
constructor(public name, public age) {
super(name);
}
sayName() {
console.log("subName", this.name);
}
}
}
/**
* 编译后
*/
{
var __extends =
(this && this.__extends) ||
(function() {
var extendStatics = function(d, b) {
extendStatics =
Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array &&
function(d, b) {
d.__proto__ = b;
}) ||
function(d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
};
return extendStatics(d, b);
};
return function(d, b) {
extendStatics(d, b);
function __() {
this.constructor = d;
}
d.prototype =
b === null
? Object.create(b)
: ((__.prototype = b.prototype), new __());
};
})();
var SuperType = /** @class */ (function() {
function SuperType(name) {
this.name = name;
}
SuperType.prototype.sayName = function() {
console.log(this.name);
};
return SuperType;
})();
var SubType = /** @class */ (function(_super) {
__extends(SubType, _super);
function SubType(name, age) {
var _this = _super.call(this, name) || this;
_this.name = name;
_this.age = age;
return _this;
}
SubType.prototype.sayName = function() {
console.log("subName", this.name);
};
return SubType;
})(SuperType);
}
}