100字范文,内容丰富有趣,生活中的好帮手!
100字范文 > 聊一聊各种继承方式的前世今生

聊一聊各种继承方式的前世今生

时间:2019-09-21 07:41:54

相关推荐

聊一聊各种继承方式的前世今生

目录

类式继承优点缺点备注构造函数继承优点缺点备注组合继承优点缺点备注原型继承特点备注寄生继承特点备注寄生组合继承特点备注总结

阅读目标

掌握JS6大继承方式及其优缺点了解各种继承方式的演变

类式继承

// 父类function Parent(name, houses) {this.name = name;this.houses = houses;}Parent.prototype.getName = function() {console.log(this.name);}Parent.prototype.getHouses = function() {console.log(this.houses);}// 子类function Son() {}/*==== 核心代码 ====*/Son.prototype = new Parent('Mark', ['北京']);const son1 = new Son();son1.houses.push('上海');son1.name = '斯特里';son1.getName() // 斯特里son1.getHouses(); // ['北京','上海']const son2 = new Son();son2.getName() // Markson2.getHouses(); // ['北京','上海']

优点

可复用父类属性

缺点

父类引用属性会被共享子类构建实例时不可向父类传递参数子类的constructor属性被修改(不影响,可忽略)

备注

该方式的本质就是修改子类的原型对象,没什么可聊的

构造函数继承

// 父类function Parent(name, houses) {this.name = name;this.houses = houses;}Parent.prototype.getName = function() {console.log(this.name);}Parent.prototype.getHouses = function() {console.log(this.houses);}// 子类function Son(name, houses) {/*==== 核心代码 ====*/Parent.call(this, name, houses);}const son1 = new Son('斯特里', ['北京']);son1.houses.push('上海');console.log(son1.name); // 斯特里console.log(son1.houses); // [ '北京', '上海' ]son1.getHouses || console.error('getHouses不存在'); // getHouses不存在const son2 = new Son('Mark', ['北京']);console.log(son2.name); // Markconsole.log(son2.houses); // ['北京']son2.getHouses || console.error('getHouses不存在'); // getHouses不存在

优点

父类引用属性不会被共享子类构建时可向父类传递参数

缺点

无法继承父类原型链上的属性

备注

该方式简单粗暴的理解如下:每次创建子类对象的同时会创建一个父类对象,并将父类对象上的属性绑定到子类对象的上下文(this)上。再认真观察之前两种继承方式的优缺点,发现彼此的优点正好可以弥补对方的缺点,由此衍生出第三种继承方式,组合继承。

组合继承

function Parent(name, houses) {this.name = name;this.houses = houses;}Parent.prototype.getName = function() {console.log(this.name);}Parent.prototype.getHouses = function() {console.log(this.houses);}function Son(name, houses) {/*==== 构造函数继承核心代码 ====*/Parent.call(this, name, houses);}/*==== 类式继承核心代码 ====*/Son.prototype = new Parent();const son1 = new Son('斯特里', ['北京']);son1.houses.push('上海');son1.getName(); // 斯特里son1.getHouses(); // [ '北京', '上海' ]const son2 = new Son('富贵', ['北京']);son2.getName(); // 富贵son2.getHouses(); // [ '北京' ]

优点

可复用父类属性父类引用属性不会被共享子类构建实例时可以向父类传递参数

缺点

会调用两次父类的构造函数

备注

怎么还有缺点,不着急后续还有解决方案

原型继承

function Book() {this.name = 'Js book';this.alikeBook = ['css book'];}Book.prototype.getName = function() {console.log(‘getName执行了’);}/*==== 核心函数 ====*/function inheritObject(SubClass) {function F() {} // 子类;F.prototype = SubClass.prototype;return new F();}let newBook = inheritObject(Book);newBook.getName(); // getName执行了console.log(newBook.name); // undefined

特点

见名知意,该方式可以仅仅继承父类上的原型属性,不继承父类本身的属性

备注

该继承其实就是类式继承的一次改造乍一看,特别容易得出一种结论:这不就是封装了一下原型模式么。但当认真分析函数后会发现,这种继承方式其实是在原型继承基础上有选择的继承了父类原型上的内容

寄生继承

/*==== 原型继承核心 ===*/function inheritObject(o) {function F() {};F.prototype = o;return new F();}/*==== 寄生继承核心 ====*/function createBook(obj) {const o = inheritObject(obj);o.getName = function() {console.log(this.name);}return o;}let book = {name: 'Js book',alikeBook: ['css book'],}let newBook = createBook(book);newBook.name = 'Ajax book';newBook.alikeBook.push('xml book');newBook.getName(); // Ajax bookconsole.log(newBook.alikeBook); // [ 'css book', 'xml book' ]let otherBook = createBook(book);otherBook.name = 'flash book';otherBook.getName(); // flash bookconsole.log(otherBook.alikeBook); // [ 'css book', 'xml book' ]

特点

对原型继承产生的对象进行扩展

备注

该继承其实就是原型继承的一次改造, 寄生继承是的寄生对象是原型继承的产物在此我们观察inheritObject函数,每次使用寄生继承都会创建一个空函数F,这样有些浪费内存,此时可以将该函数做成一个单例函数F以避免频繁创建,当完成这一步,我们便实现了ES6中Object.crate()方法

寄生组合继承

/*==== 原型继承核心 ====*/function inheritObject(o) {function F() {}F.prototype = o;return new F();}/*==== 寄生继承核心 ====*/function inheritPrototype(subClass, superClass) {let p = inheritObject(superClass.prototype);p.constructor = subClass; // 纠正子类constructor的指向subClass.prototype = p;}function SuperClass(name) {this.name = name;this.colors = ['red', 'blue', 'green'];}SuperClass.prototype.getName = function() {console.log(this.name);}function SubClass(name, time) {/*==== 构造函数继承核心 ====*/SuperClass.call(this, name);this.time = time;}inheritPrototype(SubClass, SuperClass);let instance1 = new SubClass('Js book', );let instance2 = new SubClass('css book', );console.log(instance1.colors);console.log(instance2.colors);instance2.getName();

特点

解决了组合继承中父类构造函数会调用两次的问题

备注

ES6中的class继承就是该继承方式的一种语法糖该继承是寄生寄生和组合继承的的融合,通过寄生继承中只操作原型的方式实现原型继承,而不是类式继承中创建对象的方式,从而避免了父类构造函数调用两次的问题

总结

其实分析前五种继承方式的过程就是寄生组合继承的推导过程,推导过程如下:

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。