深入浅出js实现继承的7种方式
给大家介绍7中js继承的方法
有些人认为JavaScript并不是真正的面向对象语言,在经典的面向对象语言中,您可能倾向于定义类对象,然后您可以简单地定义哪些类继承哪些类(参考C++ inheritance里的一些简单的例子),JavaScript使用了另一套实现方式,继承的对象函数并不是通过复制而来,而是通过原型链继承
一、原型链继承
// 原型链实现继承 function Person(name,age) { this.name=name; this.age=age; } Person.prototype.show=function() { console.log(`我是${this.name},我今年${this.age}`) } function Worker(name, age, job) { Person.call(this, name, age); this.job=job; } // 如果此处有Woker的原型对象上的方法,由于原型重定向,下面的代码会覆盖此方法 Worker.prototype = new Person(); // 应该写在此处 Worker.prototype.showJob=function() { console.log(`我的工作是${this.job}`) }; var mine = new Worker('佳', 18, '写代码'); console.log(mine); mine.show(); mine.showJob();
二、借用构造函数继承
function Person(name, age){ this.name=name; this.age=age; } function Worker(name, age, job){ Person.call(this, name, age); this.job=job; } var mine=new Worker('佳', 18, '写代码的');
console.log(mine);
优点:1. 相对于原型链而言,借用构造函数有一个很大的优势,即可以在子类型构造函数中向父类型构造函数传递参数。
缺点:1、只能继承父类构造函数的属性。
2、无法实现构造函数的复用。(每次用每次都要重新调用)
3、每个新实例都有父类构造函数的副本,臃肿。
三、组合继承(组合原型链继承和借用构造函数继承)(常用)
// 组合继承 function Person(name,age) { this.name=name; this.age=age; } Person.prototype.show=function() { console.log(`我是${this.name},我今年${this.age}`) } function Worker(name, age, job) { Person.call(this, name, age); this.job=job; } Worker.prototype = new Person(); Worker.prototype.constructor = Worker; Worker.prototype.showJob=function (){ console.log(`我的工作是${this.job}`) }; var mine = new Worker('佳', 18, '打杂的'); console.log(mine); mine.show(); mine.showJob();
重点:结合了两种模式的优点,传参和复用
优点:1、可以继承父类原型上的属性,可以传参,可复用。
2、每个新实例引入的构造函数属性是私有的。
缺点:调用了两次父类构造函数(耗内存),子类的构造函数会代替原型上的那个父类构造函数。
四、原型式继承
// 原型式继承 function Woker(o){ function Empty(){}; Empty.prototype = o; return new Empty(); } var mine = { name: 'jia', age: 18, job: '打杂的' }; var anotherMine =Woker(mine);
重点:用一个函数包装一个对象,然后返回这个函数的调用,这个函数就变成了个可以随意增添属性的实例或对象。object.create()就是这个原理。
特点:类似于复制一个对象,用函数来包装。
缺点:1、所有实例都会继承原型上的属性。
2、无法实现复用。(新实例属性都是后面添加的)
var woker={ name: 'jia', age: 18, job: '打杂的' } var mine = Object.create(woker);
原理和上面相同,ECMAScript 5 通过新增 Object.create()方法规范化了原型式继承。
// 寄生式继承 function createAnother(o) { var person = Woker(o); person.show=function() { console.log(`我是jia`) } return person; } var mine = { name: 'jia', age: 18, job: '打杂的' }; var anotherMine = createAnother(mine);
重点:就是给原型式继承外面套了个壳子。
优点:没有创建自定义类型,因为只是套了个壳子返回对象(这个),这个函数顺理成章就成了创建的新对象。
缺点:没用到原型,无法复用。
也可用 Object.create()方法实现
六、寄生组合式继承
//寄生组合式继承 function inheritProto(parents,child){ var o=Object.create(parents.prototype); o.constructor=child; child.prototype=o; } //父类构造函数 function Parents(surname){ this.surname=surname; } Parents.prototype.getSurname=function(){ console.log(this.surname); } //子类构造函数 function Child(surname,age){ Parents.call(this,surname); this.age=age; } inheritProto(Parents,Child); Child.prototype.getAge=function(){ console.log(this.age); }
寄生组合式继承,集寄生式继承和组合继承的优点与一身,是实现基于类型继承的最有效方式。YUI 的 YAHOO.lang.extend()方法采用了寄生组合继承,从而让这种模式首次 出现在了一个应用非常广泛的 JavaScript 库中。要了解有关 YUI 的更多信息,请访问 http://developer. yahoo.com/yui/。
七、ES6的Class实现继承
class Person{ constructor(name, age){ this.name=name; this.age=age; } show(){ alert(this.name); alert(this.age); } } class Worker extends Person{ constructor(name, age, job){ super(name, age); this.job=job; } showJob(){ alert(this.job); } } let me=new Worker('jia', 18, '前端攻城狮'); me.show(); me.showJob();
好啦,常见的7种JS继承的方法介绍完了。~~