1.原型、原型链、继承的概念
(1)每个构造函数都有一个原型对象,原型对象都包含指向构造函数的指针,而实例都包含一个指向原型对象的内部指针(
__proto__
);
(2)一个对象会指向一个原型,原型对象会有自己的原型,以此类推,构成原型链。
(3)实例使用方法和属性时,会先从构造函数内部找,找不到再去原型对象上找,还找不到就去原型对象的原型上找,直到(原型对象的原型为null)
Object.prototype.__proto__===null
,停止查找.
(4)继承是指能够访问另外一个对象中的方法和属性。
2.实现继承的几种方式:(主要是原型链继承)
(1)原型链继承
//原型链继承
function Person(name,age){
this.name=name;
this.age=age;
this.desc=function(){
console.log("this is a person");
}
}
Person.prototype.common=function(){
console.log("恭喜您出生了");
}
function Teacher(name,age,skill){
this.name=name;
this.age=age;
this.skill=function(){
console.oog("传授知识");
}
}
//实现继承的关键
Teacher.prototype=new Person();
总结:子类继承的实现:将父类的实例赋值给子类的原型。
缺点是:(1)子类原型的构造函数指向的是父类构造函数,Person.prototype.constructor === Teacher.prototype.constructor.
(2)无法给父类构造函数传参数
(3)所有子类的实例共享父类构造函数的属性方法。
(2)构造函数继承
function Person(name,age){
this.name=name;
this.age=age;
this.desc=function(){
console.log("this is a person");
}
}
Person.prototype.common=function(){
console.log("恭喜您出生了");
}
function Teacher(name,age,skill){
Person.call(this,name,age);
}
总结:该类继承方式,是在子类的定义中改变父类的this指向(即父类的执行环境),缺点是无法访问父类原型对象上的方法。
(3)组合式继承
function Person(name,age){
this.name=name;
this.age=age;
this.desc=function(){
console.log("this is a person");
}
}
Person.prototype.common=function(){
console.log("恭喜您出生了");
}
function Teacher(name,age,skill){
Person.call(this);// 第一次调用父类
}
Teacher.prototype=new Person();//第二次调用父类
总结:该继承方式结合了原型链和构造函数的继承方式;
缺点:
(1)会调用两遍父类构造函数
(2)会出现 Teacher.prototype.constructor === Person.prototype.constructor
(4)寄生式继承
let obj={
name:1,
age:2
};
function createObj(obj){
function F(){
};
F.prototype=obj;
return new F();
}
function createPerson(obj){
let clone=createObj(obj);
return clone;
}
let p1=createPerson(obj);
总结:模式与工厂模式类似,创建一个仅用于封装继承过程的函数。
(5)寄生组合式继承
function initPrototype(fatherType,childType){
let prototypeF=createOb(fatherType.protoType);//创建对象
prototypeF.constructor=childType;//增强对象
childType.prototype=prototypeF;//指定对象
};
function createObj(obj){
function F(){
};
F.prototype=obj;
return new F();
}
function Father(name){
this.name=name;
};
Father.prototype.skill=function(){
console.log("father's skill");
};
function Child(){
Father.call(this, ...arguments);
};
initPrototype(Father,Child);
Child.prototype.change=function(){
console.log("Child changing");
}
总结:通过借用构造函数来继承属性,通过原型链的混成形式来继承的方法。对于父类的原型继承,相当于是将父类的原型对象的副本赋值给子类的原型,这样避免了在子类原型上面添加其他多余的属性,子类的原型和原型指向的构造函数也不再混乱了。
(6)ES6中的class相关的继承
class Animal{
constructor(name,type){
this.name="everything";
this.type=type;
this.skill1=function(){
console.log("animal");
}
}
change(){
console.log("changeing")
}
};
class Bird extends Animal{
constructor(name,type){
super(name,type);
this.skill=function(){
console.log("flying");
}
}
};
let b1=new Bird();
b1.change();
(7)通过Object.create实现继承
作用: 以一个现有对象作为原型,创建一个新对象
function Father () {
}
Father.prototype.run = function () {
console.log('is running')
}
function Child () {
Father.call(this) // 调用父类构造函数。
}
Child.prototype = Object.create(Father.prototype, {
constructor: {
value: Child,
enumerable: false,
writable: true,
configurable: true,
}
})
备注:参考自JAVASCRIPT高级程序设计