js实现继承的多种方式

1. 原型链继承

function Parent() {
this.name = 'xwk'
}
Parent.prototype.getName = function() {
console.log(this.name)
}
function Child() {}
Child.prototype = new Parent()
var child = new Child()
console.log(child.getName()) // xwk

缺点:

  1. 引用类型的属性被所有实例共享,举个例子:
function Parent () {
this.names = ['kevin', 'daisy'];
}
function Child () {}
Child.prototype = new Parent();
var child1 = new Child();
child1.names.push('yayu');
console.log(child1.names); // ["kevin", "daisy", "yayu"]
var child2 = new Child();
console.log(child2.names); // ["kevin", "daisy", "yayu"]
  1. 在创建Child的实例时,不能向Parent传参数
  2. 实例丢失了自己的construct属性

2. 经典继承(借用构造函数(使用call))

function Parent() {
this.names = ["kevin", "daisy"]
}
Parent.prototype.getName = function() {
console.log(this.names)
}
function Child() {
Parent.call(this)
}
var child1 = new Child()
child1.names.push('yayu');
console.log(child1.names); // ["kevin", "daisy", "yayu"]
var child2 = new Child();
console.log(child2.names); // ["kevin", "daisy"]

缺点:Parent原型上的属性和方法不能被继承

优点:

  1. 在继承的时候可以向Parent传参
  2. 可以避免引用类型的属性被不同实例所共享

3. 组合继承

原型链继承 + 经典继承

function Parent(name) {
this.name = name
this.colors = ['red','blue']
}
Parent.prototype.getName = function() {
console.log(this.name)
}
function Child(name, age) {
Parent.call(this, name)
this.age = age
}
Child.prototype = new Parent()
Child.prototype.constructor = Child var child1 = new Child('kevin', '18'); child1.colors.push('black'); console.log(child1.name); // kevin
console.log(child1.age); // 18
console.log(child1.colors); // ["red", "blue", "green", "black"] var child2 = new Child('daisy', '20'); console.log(child2.name); // daisy
console.log(child2.age); // 20
console.log(child2.colors); // ["red", "blue", "green"]

分析下上述代码:

  1. Parent.call(this, name) ,解决了传参问题,并且将Parent构造函数内的属性复制到Child里,可以避免引用类型被共享;
  2. Child.prototype = new Parent() 同时使用原型链继承,可以保证Parent原型上的属性和方法能被Child继承到。

4. 原型式继承 (Object.create)

function createObj(obj) {
function F() {}
F.prototype = obj
return new F()
}

上述代码,其实就是ES5 Object.create 方法的实现,将传入的对象作为一个新对象的原型返回。

缺点:和原型链继承的缺点一样,引用类型的属性会被子实例所共享

var person = {
name: 'kevin',
friends: ['daisy', 'kelly']
} var person1 = createObj(person);
var person2 = createObj(person); person1.name = 'person1';
console.log(person2.name); // kevin person1.friends.push('taylor');
console.log(person2.friends); // ["daisy", "kelly", "taylor"]

5. 寄生式继承

创建一个仅用于封装继承过程的函数,该函数在内部以某种形式来增强对象,最后返回对象。

function createObj (o) {
var clone = Object.create(o);
clone.sayName = function () {
console.log('hi');
}
return clone;
}

缺点:和经典模式一样,方法都在构造函数中定义,每次创建实例都会创建一遍方法。

6. 寄生组合继承

其实就是对组合继承的优化,

我们可以看组合继承的代码,发现一共掉了两次Parent构造函数,

一次是Child.prototype = new Parent(),

一次是Child构造函数中,Parent.call(this,name),

这样导致的结果就是Child和Child.prototype中都有colors属性。

那么怎么优化呢,避免这一次重复调用呢?

如果我们不使用 Child.prototype = new Parent() ,而是间接的让 Child.prototype 访问到 Parent.prototype 呢?

function Parent(name) {
this.name = name
this.colors = ['red','blue']
}
Parent.prototype.getName = function() {
console.log(this.name)
}
function Child(name, age) {
Parent.call(this, name)
this.age = age
}
Child.prototype = Object.create(Parent.prototype)
Child.prototype.constructor = Child var child1 = new Child('kevin', '18'); child1.colors.push('black'); console.log(child1.name); // kevin
console.log(child1.age); // 18
console.log(child1.colors); // ["red", "blue", "green", "black"] var child2 = new Child('daisy', '20'); console.log(child2.name); // daisy
console.log(child2.age); // 20
console.log(child2.colors); // ["red", "blue", "green"]

注意️:

使用 Child.prototype = Object.create(Parent.prototype) 替换

Child.prototype = new Parent()

虽然目的都是一样,让Child.prototype 的原型对象 指向 Parent.prototype,

但是使用后者会把Parent构造函数内部的多余属性也继承过来,前者不会。

最新文章

  1. java 引入自定义字体font后出现的硬盘吃光的问题
  2. 看完《Thinking in Java》后,我觉得自己就是一个不懂编程的小孩子,如何快速摆脱这种自卑感
  3. Spring 开启Annotation <context:annotation-config> 和 <context:component-scan>诠释及区别
  4. puppet安装
  5. Android 内存优化 (防Memory Leak)
  6. [SAP ABAP开发技术总结]几个小技巧
  7. TADOTable 用过滤事件 后 记录数据和 记录的内容
  8. Linux使用笔记: 定制core dump文件的文件名
  9. centos打开3306端口
  10. org.springframework.dao.EmptyResultDataAccessException
  11. 自己定义GSON类型适配器
  12. python的流程控制学习
  13. win7下IIS的安装和配置
  14. 【NOIP2015】运输计划
  15. Objc中触摸处理阻塞时消息派送的问题
  16. Redis和mysql数据怎么保持数据一致的?
  17. EXCEL中把两列表格里的数字合成一列并且中间用逗号隔开
  18. 当visual studio的数据库项目遇到SQL71501
  19. HttpComponents-Client学习
  20. HTML5之2D物理引擎 Box2D for javascript Games 系列 翻外篇--如何结合createJS应用box2d.js

热门文章

  1. ARC126F
  2. AI趋势量化系统(Binance升级版)
  3. csv.reader(f)和f.readlines()、追加数据
  4. 10分钟快速部署camunda BPM开源版
  5. 使用 DartPad 制作代码实践教程
  6. LVGL库入门教程03-布局方式
  7. ShardingSphere-proxy-5.0.0分布式雪花ID生成(三)
  8. 《阿里云天池大赛赛题解析》——O2O优惠卷预测
  9. SAP -熟练使用T-Code SHD0
  10. python小题目练习(九)