跳到主要内容

认识

2024年03月07日
柏拉文
越努力,越幸运

一、原型链继承


1.1 弊端

  • 一、原型中包含的引用值会在所有实例间共享
  • 二、子类型在实例化时不能给父类型的构造函数传参
  • 三、子类新增属性或者方法必须放在 子类.prototype = new 父类(); 之后

1.2 实现

function Parent(type){
this.parentType = type;
this.parentData = [];
}
Parent.prototype.getParentType = function(){
return this.parentType;
}

function Child(type){
this.childType = type;
this.childData = [];
}
Child.prototype = new Parent();
Child.prototype.getChildType = function(){
return this.childType;
}

const child1 = new Child('一号孩子');
console.log(child1); // Child {childType: '一号孩子', childData: Array(0)}
console.log(child1.getChildType()); // 一号孩子
console.log(child1.getParentType()); // undefined
child1.parentData.push('一号孩子');

const child2 = new Child('二号孩子');
console.log(child2); // Child {childType: '二号孩子', childData: Array(0)}
console.log(child2.getChildType()); // 二号孩子
console.log(child2.getParentType()); // undefined
console.log(child2.parentData); // ['一号孩子']

二、构造函数继承


2.1 弊端

  • 一、必须在构造函数中定义方法,因此函数不能重用
  • 二、子类也不能访问父类原型上定义的方法,因此所有类型只能使用构造函数模式

2.2 实现

function Parent(type){
this.parentType = type;
this.parentData = [];
}
Parent.prototype.getParentType = function(){
return this.parentType;
}

function Child(parentType,childType){
Parent.call(this,parentType);
this.childType = childType;
this.childData = [];
}
Child.prototype.getChildType = function(){
return this.childType;
}

const child1 = new Child('一号孩子父类','一号孩子');
console.log(child1); // Child {parentType: '一号孩子父类', parentData: Array(0), childType: '一号孩子', childData: Array(0)}
console.log(child1.getChildType()); // 一号孩子
// console.log(child1.getParentType()); // 报错
child1.parentData.push('一号孩子');

const child2 = new Child('二号孩子父类','二号孩子');
console.log(child2); // Child {parentType: '二号孩子父类', parentData: Array(0), childType: '二号孩子', childData: Array(0)}
console.log(child2.getChildType()); // 二号孩子
// console.log(child2.getParentType()); // 报错
console.log(child2.parentData); // []

三、组合式继承


3.1 弊端

  • 一、父类构造函数始终会被调用两次 一次在是创建子类原型时调用,另一次是在子类构造函数中调用

3.2 实现

function Parent(type){
this.parentType = type;
this.parentData = [];
}
Parent.prototype.getParentType = function(){
return this.parentType;
}

function Child(parentType,childType){
Parent.call(this,parentType);
this.childType = childType;
this.childData = [];
}
Child.prototype = new Parent();
Child.prototype.constructor = Child;
Child.prototype.getChildType = function(){
return this.childType;
}

const child1 = new Child('一号孩子父类','一号孩子');
console.log(child1); // Child {parentType: '一号孩子父类', parentData: Array(0), childType: '一号孩子', childData: Array(0)}
console.log(child1.getChildType()); // 一号孩子
console.log(child1.getParentType()); // 一号孩子父类
child1.parentData.push('一号孩子');

const child2 = new Child('二号孩子父类','二号孩子');
console.log(child2); // Child {parentType: '二号孩子父类', parentData: Array(0), childType: '二号孩子', childData: Array(0)}
console.log(child2.getChildType()); // 二号孩子
console.log(child2.getParentType()); // 二号孩子父类
console.log(child2.parentData); // []

四、原型式继承


4.1 弊端

  • 一、原型属性中包含的引用值始终会在相关对象间共享

4.2 实现

写法一
function createObject(originalObj){
const F = new Function();
F.prototype = originalObj;
return new F();
}
const obj = {
type:'一个对象',
data:[]
}

const anotherObj1 = createObject(obj);
console.log(anotherObj1);
anotherObj1.data.push('另一个对象一号');
// {}
// [[Prototype]]: Object
// data: []
// type: "一个对象"
// [[Prototype]]: Object
const anotherObj2 = createObject(obj);
console.log(anotherObj2);
// {}
// [[Prototype]]: Object
// data: []
// type: "一个对象"
// [[Prototype]]: Object
console.log(anotherObj2.data); // ['另一个对象一号']
写法二
const obj = {
type:'一个对象',
data:[]
}

const anotherObj1 = Object.create(obj,{
type:{
value:'另一个对象一号 type',
writable:true,
enumerable:true,
configurable:true
},
data:{
value:[],
writable:true,
enumerable:true,
configurable:true
}
});
console.log(anotherObj1);
anotherObj1.data.push('另一个对象一号');
// {type: '另一个对象一号 type', data: Array(0)}
// [[Prototype]]: Object
// data: []
// type: "一个对象"
// [[Prototype]]: Object
const anotherObj2 = Object.create(obj,{
type:{
value:'另一个对象二号 type',
writable:true,
enumerable:true,
configurable:true
},
data:{
value:[],
writable:true,
enumerable:true,
configurable:true
}
});
console.log(anotherObj2);
// {type: '另一个对象二号 type', data: Array(0)}
// [[Prototype]]: Object
// data: []
// type: "一个对象"
// [[Prototype]]: Object
console.log(anotherObj2.data); // []

五、寄生式继承


5.1 弊端

  • 承给对象添加函数会导致函数难以重用

5.2 实现

const obj = {
type:'一个对象',
data:[]
}

function createObject(originalObj){
const anotherObj = Object.create(originalObj,{
type:{
value:'另一个对象',
writable:true,
enumerable:true,
configurable:true
}
});
anotherObj.getType = function(){
return this.type;
}
return anotherObj;
}

const anotherObj1 = createObject(obj);
anotherObj1.type = '另一个对象一号'
console.log(anotherObj1); // {type: '另一个对象一号', getType: ƒ}
anotherObj1.data.push('另一个对象一号');

const anotherObj2 = createObject(obj);
anotherObj2.type = '另一个对象二号'
console.log(anotherObj2); // {type: '另一个对象二号', getType: ƒ}
console.log(anotherObj2.data); ['另一个对象一号']

六、寄生组合式继承


寄生组合式继承是目前这是最成熟的方法,也是现在库实现的方法

6.1 实现

基础
function Parent(type){
this.parentType = type;
this.parentData = [];
}
Parent.prototype.getParentType = function(){
return this.parentType;
}

function Child(parentType,childType){
Parent.call(this,parentType);
this.childType = childType;
this.childData = [];
}
Child.prototype = Object.create(Parent.prototype);
Child.prototype.constructor = Child;
Child.prototype.getChildType = function(){
return this.childType;
}

const child1 = new Child('一号孩子父类','一号孩子');
console.log(child1); // Child {parentType: '一号孩子父类', parentData: Array(0), childType: '一号孩子', childData: Array(0)}
console.log(child1.getChildType()); // 一号孩子
console.log(child1.getParentType()); // 一号孩子父类
child1.parentData.push('一号孩子');

const child2 = new Child('二号孩子父类','二号孩子');
console.log(child2); // Child {parentType: '二号孩子父类', parentData: Array(0), childType: '二号孩子', childData: Array(0)}
console.log(child2.getChildType()); // 二号孩子
console.log(child2.getParentType()); // 二号孩子父类
console.log(child2.parentData); // []
封装
function inheritPrototype(Child,Parent){
const prototype = Object.create(Parent.prototype);
prototype.constructor = Child;
Child.prototype = prototype;
}
function Parent(type){
this.parentType = type;
this.parentData = [];
}
Parent.prototype.getParentType = function(){
return this.parentType;
}

function Child(parentType,childType){
Parent.call(this,parentType);
this.childType = childType;
this.childData = [];
}
inheritPrototype(Child,Parent);
Child.prototype.getChildType = function(){
return this.childType;
}

const child1 = new Child('一号孩子父类','一号孩子');
console.log(child1); // Child {parentType: '一号孩子父类', parentData: Array(0), childType: '一号孩子', childData: Array(0)}
console.log(child1.getChildType()); // 一号孩子
console.log(child1.getParentType()); // 一号孩子父类
child1.parentData.push('一号孩子');

const child2 = new Child('二号孩子父类','二号孩子');
console.log(child2); // Child {parentType: '二号孩子父类', parentData: Array(0), childType: '二号孩子', childData: Array(0)}
console.log(child2.getChildType()); // 二号孩子
console.log(child2.getParentType()); // 二号孩子父类
console.log(child2.parentData); // []

七、类继承


7.1 实现

class Person{
constructor(name,age){
this.name = name;
this.age = age;
}
say(){
console.log(this.name+'说话');
}
}
class Student extends Person{
constructor(name,age,stage){
super(name,age,stage);
}
study(){
console.log(this.name+'学习');
}
}

const student = new Student('柏拉图',23,'大学');
console.log(student);
student.say();
student.study();

参考资料


参考资料