JS 总结之原型继承的几种方式
栏目: JavaScript · 发布时间: 5年前
内容简介:在之前的总结中,我们详细分析了原型以一个父类为前提条件,列举 js 继承的继承方式:缺点:
在之前的总结中,我们详细分析了原型 《JS 总结之原型》 ,原型很大作用用于模拟继承,这一次,我们来聊原型继承的几种方式。
前提
以一个父类为前提条件,列举 js 继承的继承方式:
function Person (age) { this.age = age || 18 } Person.prototype.sleep = function () { console.log('sleeping') } 复制代码
:meat_on_bone: 方式 1:原型链继承(不推荐)
function Programmer() {} Programmer.prototype = new Person () Programmer.prototype.code = function () { console.log('coding') } let jon = new Programmer() jon.code() // coding jon.sleep() // sleeping jon instanceof Person // true jon instanceof Programmer // true Object.getPrototypeOf(jon) // Person {age: 18, code: ƒ} jon.__proto__ // Person {age: 18, code: ƒ} 复制代码
缺点:
- 无法向父类构造函数传参
- 父类的所有属性被共享,只要一个实例修改了属性,其他所有的子类实例都会被影响
方式 2:借用构造函数(经典继承)(不推荐)
复制父类构造函数内的属性
function Programmer(name) { Person.call(this) this.name = name } let jon = new Programmer('jon') jon.name // jon jon.age // 18 jon.sleep() // Uncaught TypeError: jon.sleep is not a function jon instanceof Person // false jon instanceof Programmer // true 复制代码
优点:
- 可以为父类传参
- 避免了共享属性
缺点:
- 只是子类的实例,不是父类的实例
- 方法都在构造函数中定义,每次创建实例都会创建一遍方法
:fried_shrimp: 方式 3:组合继承(推荐)
组合 原型链继承 和 借用构造函数继承 。
function Programmer(age, name) { Person.call(this, age) this.name = name } Programmer.prototype = new Person() Programmer.prototype.constructor = Programmer // 修复构造函数指向 let jon = new Programmer(18, 'jon') jon.age // 18 jon.name // jon let flash = new Programmer(22, 'flash') flash.age // 22 flash.name // flash jon.age // 18 jon instanceof Person // true jon instanceof Programmer // true flash instanceof Person // true flash instanceof Programmer // true 复制代码
优点:融合原型链继承和构造函数的优点,是 JavaScript 中最常用的继承模式
缺点:调用了两次父类构造函数
方式 4:原型式继承(不推荐)
function create(o) { function F() {} F.prototype = o return new F() } let obj = { gift: ['a', 'b'] } let jon = create(obj) let xiaoming = create(obj) jon.gift.push('c') xiaoming.gift // ['a', 'b', 'c'] 复制代码
缺点:共享了属性和方法
:egg: 方式 5:寄生式继承(不推荐)
创建一个仅用于封装继承过程的函数,该函数在内部以某种形式来做增强对象,最后返回对象
function createObj (o) { var clone = Object.create(o) clone.sayName = function () { console.log('hi') } return clone } 复制代码
缺点:跟借用构造函数模式一样,每次创建对象都会创建一遍方法
:shaved_ice: 方式 6:寄生组合继承(最佳)
子类构造函数复制父类的自身属性和方法,子类原型只接受父类的原型属性和方法:
function create(prototype) { function Super() {} Super.prototype = prototype return new Super() } function Programmer(age, name) { Person.call(this, age) this.name = name } Programmer.prototype = create(Person.prototype) Programmer.prototype.constructor = Programmer // 修复构造函数指向 let jon = new Programmer(18, 'jon') jon.name // jon 复制代码
进阶封装:
function create(prototype) { function Super() {} Super.prototype = prototype return new Super() } function prototype(child, parent) { let prototype = create(parent.prototype) prototype.constructor = child // 修复构造函数指向 child.prototype = prototype } function Person (age) { this.age = age || 18 } Person.prototype.sleep = function () { console.log('sleeping') } function Programmer(age, name) { Person.call(this, age) this.name = name } prototype(Programmer, Person) let jon = new Programmer(18, 'jon') jon.name // jon 复制代码
引用《JavaScript 高级程序设计》中对寄生组合式继承的夸赞就是:
这种方式的高效率体现它只调用了一次 Parent 构造函数,并且因此避免了在 Parent.prototype 上面创建不必要的、多余的属性。与此同时,原型链还能保持不变;因此,还能够正常使用 instanceof 和 isPrototypeOf。开发人员普遍认为寄生组合式继承是引用类型最理想的继承范式。
:ramen: 方式 7:ES6 extends(最佳)
// 父类 class Person { constructor(age) { this.age = age } sleep () { console.log('sleeping') } } // 子类 class Programmer extends Person { constructor(age, name) { super(age) this.name = name } code () { console.log('coding') } } let jon = new Programmer(18, 'jon') jon.name // jon jon.age // 18 let flash = new Programmer(22, 'flash') flash.age // 22 flash.name // flash jon instanceof Person // true jon instanceof Programmer // true flash instanceof Person // true flash instanceof Programmer // true 复制代码
优点:不用手动设置原型。
缺点:新语法,只要部分浏览器支持,需要转为 ES5 代码。
:rocket: 参考
- 《JavaScript 高级程序设计(第 3 版)》6.3 继承
- 《JavaScript 深入之继承的多种方式和优缺点》 by 冴羽
- 《ECMAScript 6 入门》Class 的继承 by 阮一峰
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- 构造函数、原型、原型链、继承
- 前端基本功(七):javascript中的继承(原型、原型链、继承的实现方式)
- JavaScript原型链继承
- JavaScript 继承和原型链
- 彻底弄懂JS原型与继承
- 前端进击的巨人(七):走进面向对象,原型与原型链,继承方式
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。