你想知道的多种js原生继承方式以及他们的优缺点

一次面试被面试官问到:你简历上写你对js深入的理解,请你说一下js继承有几种方式?我心里暗喜:我当然知道啦,我5年的前端开发经验又不是虚的,然后就列了以下3种模式:

1.通过call/apply将父构造函数this指向子构造函数

2.通过给子构造函数的prototype属性赋值父构造函数实例

3.直接给子构造函数的prototype属性赋值父构造函数prototype属性

然后面试官:嗯,那你知道它们之间的差异和优缺点吗?

我:没有深入了解.....

毫无悬念面试挂了,吸取笔者的教训,以后简历就不要轻易写“深入理解”’,除非你真的对其有很深入的研究,不然就是给自己挖坑!还有千万不要写“精通”某某语言,相信那些技术大牛也不敢说自己“精通”哪门语言。扯远了,回归正题js原生继承有几种方式它们的优缺点分别是什么?

一、构造函数绑定

就是上面说的通过call/apply将父构造函数this指向子构造函数看下面的例子

// 人类的构造函数 
function Person(species){
   this.species = species;
}
Person.prototype.sex='man'
//中国人的构造函数
function Chinese(species,name,skin){
    Person.apply(this, arguments);
     this.name=name;
   this.skin = skin ;
}

 var chinese = new Chinese("会说话","小明","黄色");
 console.log(chinese.species); // 会说话
  console.log(chinese.sex); //undefined

优点:
1.简单快捷
2.创建子类实例时,可以向父类传递参数
3.可以实现多继承(apply多个父类对象)

缺点:
1.实例只是子类的实例不属于父类实例
2.只能继续父类属性/方法不能继承其原型属性/方法

二、原型链继承

function Person(){
   this.species = "会说话";
}

//中国人的构造函数
function Chinese(name,skin){
     this.name=name;
   this.skin = skin ;
}

 Chinese.prototype=new Person();
  Chinese.prototype.constructor = Chinese

var chinese = new Chinese("小明","黄色");
console.log(chinese.species); // 会说话

有同学可能会对这句Chinese.prototype.constructor = Chinese感到疑惑,为什么要重新赋值Chinese.prototype的constructor呢,因为Chinese.prototype=new Person()会把Chinese.prototype的constructor指向了Person,如果不手动改过来就会导致会导致继承链的紊乱。

优点:

1.非常纯粹的继承关系,实例是子类的实例,也是父类的实例
2.父类新增原型方法/原型属性,子类都能访问到
3.简单,易于实现

缺点:

1.性能低,建立Person的实例,浪费内存

2.来自原型对象的所有属性被所有实例共享,改变实例的属性会同时改变原型属性

三、prototype继承

function Person(){
   
}
Person.prototype.species="会说话"
function Chinese(name,skin){
     this.name=name;
   this.skin = skin ;
}

 Chinese.prototype=Person.prototype;
  Chinese.prototype.constructor = Chinese

var chinese = new Chinese("小明","黄色");
console.log(chinese.species); // 会说话
Chinese.prototype.species="好客" 
console.log(Person.prototype.species)// 好客

优点:效率比较高(不用执行和建立Person的实例了),比较省内存

缺点: Person.prototype和Chinese.prototype现在指向了同一个对象,Chinese.prototype的修改,会修改到Person.prototype。

四、拷贝继承

function Person(){
   
}
Person.prototype.species="会说话"
function Chinese(name){
  var person= Person.prototype;
  for(var p in person){
    Chinese.prototype[p] = person[p];
  }
  Chinese.prototype.name = name || 'Tom';
}

var chinese= new Chinese();
console.log(chinese.species); //会说话
console.log(chinese instanceof Person); // false
console.log(chinese instanceof Chinese); // true

特点:支持多继承

缺点:

1.效率较低,内存占用高(因为要拷贝父类的属性)

2.无法获取父类不可枚举的方法(不可枚举方法,不能使用for in 访问到)

五、Object.create

function Person(){
   
}
Person.prototype.species="会说话"
function Chinese(name,skin){
     this.name=name;
   this.skin = skin ;
}

 Chinese.prototype=Object.create(Person.prototype);
  Chinese.prototype.constructor = Chinese

var chinese = new Chinese("小明","黄色");
console.log(chinese.species); // 会说话
Chinese.prototype.species="好客" 
console.log(Person.prototype.species)// 会说话

这种方式是目前常用的一种继承方式,效率高,又解决了Chinese.prototype和Person.prototype共享指针内存问题

原文参考

http://www.ruanyifeng.com/blog/2010/05/object-oriented_javascript_inheritance.html 

https://www.cnblogs.com/humin/p/4556820.html

你可能感兴趣的:(js)