有几种实现继承的方式,以下给予总结.
function Person(name,age){
this.name=name;
}
Person.prototype.sayName=function(){
console.log(this.name);
}
function Programmer(job){
this.job=job;
}
Programmer.prototype=new Person('Tom',23); //打通原型链
Programmer.prototype.constructor=Programmer; //修改constructor指向
Programmer.prototype.sayJob=function(){
console.log(this.job);
}
let coder=new Programmer('programmer');
console.log(coder.constructor);
console.log(coder.name); //Tom
coder.sayName(); //Tom
以上方法有几个致命的问题
1.)如果子类想拥有自己的name, 我们将会弄不了.
2.)属性共享 因为父类的属性以及方法都挂在了原型链上导致当我们修改自己的属性的时候会污染,尤其是Object,Array等情况.
function Person(name,age){
this.name=name;
}
Person.prototype.sayName=function(){
console.log(this.name);
}
function Programmer(name,job){
Person.call(this,name);
this.job=job;
}
Programmer.prototype.sayJob=function(){
console.log(this.job);
}
let coder=new Programmer('Tom',23);
// 拿不到,因为方法不在原型链上
coder.sayName();
我们通过把父类链的环境指向子类的环境来获取父类的属性(相当于es6中的super())。
致命的缺陷,因为父类的方法是在原型链上的,我们使用call来获取了父类本身的环境,但没有获取到父类的原型.
于是,我们想到通过组合以上两种方法来达到我们的目的.
function Person(name,age){
this.name=name;
}
Person.prototype.sayName=function(){
console.log(this.name);
}
function Programmer(name,job){
Person.call(this,name);
this.job=job;
}
Programmer.prototype=new Person();
Programmer.prototype.constructor=Programmer;
Programmer.prototype.sayJob=function(){
console.log(this.job);
}
let coder=new Programmer('Tom',23);
console.log(coder);
console.log(coder.name); //Tom
coder.sayName(); //Tom
可以看到我们实现了我们想要的继承方式,但也有几个缺点.
1.两处用了构造函数,造成浪费
2.我们只是想要原型链上的方法,但属性也被拿了过来.
function Person(name,age){
this.name=name;
}
Person.prototype.sayName=function(){
console.log(this.name);
}
function Programmer(name,job){
Person.call(this,name);
this.job=job;
}
Programmer.prototype=Object.create(Person.prototype,{
constructor:{
value:Programmer
}
})
Programmer.prototype.sayJob=function(){
console.log(this.job);
}
let coder=new Programmer('Tom',23);
console.log(coder);
我们为了少用一个构造函数,使用了Object.create方法,并且把子类的原型上的constructor指向了父类.