原型
原型是Javascript中的继承的根底,Javascript中的继承就是原型的继承。
构造函数
其实就是咱们平时写的函数,能够用new关键字来创立实例的,咱们称之为构造函数。
当申明一个函数时,浏览器会主动生成一个原型对象,贮存在内存之中。
function add() { let a = 1}const f = new add()// add()就是一个构造函数// f 就是构造函数add()的实例
原型链
通过_proto_链接起来的链式关系就是原型链
原型链决定了Javascript的继承关系
当咱们查找一个属性时,查找机制如下:
- 拜访对象属性,有则返回,没有就通过_proto_去它的原型对象外面找
- 一层一层找直到找到Object.prototype,如果找到就返回,没有找到就返回undefind,因为再往下找_proto_外面就是null
继承
原型链继承
原型链继承通过批改子类的原型为父类的实例,从而达到子类能过拜访父类的原型上的属性和办法
function Parent() { this.name = 'nana'}Parent.prototype.getName = function () { return this.name;}function Child() { constructor()}Child.prototype = new Parent()const child = new Child()const child2 = new Child();child.name = 'heaven'child.getName(); // 'heaven'child2.getName(); // 'heaven'// 'nana'
长处:实现简略不便。
毛病:父类构造函数中的援用类型(数组/对象),会被所有子类实例共享,其中一个子类实例进行批改时,会导致其余所有子类实例这个值都会被扭转。
构造函数继承
通过批改父类构造函数this实现的继承。就是在子类构造函数中执行父类的构造函数,批改父类this为子类this.
function Parent() { this.info = ['name','age','sex']}function Child() { Parent.call(this)}const child = new Child()child.info.push('school')const child2 = new Child()console.log(child,'child'); // ['name', 'age', 'sex', 'school']console.log(child2,'child2'); // ['name', 'age', 'sex']
长处:完满解决了下面原型链继承的毛病,其中一个子类实例属性值被批改不会影响其余子类。
毛病:办法都定义在构造函数中,每次都须要从新创立,比拟浪费资源。
组合继承
联合原型链继承和构造函数继承。
function Parent() { this.info = ['name','age','sex']}Parent.prototype.getName = function () { return this.info;}function Child() { Parent.call(this) this.topic = 'fe';}Child.prototype = new Parent()Child.prototype.constructor = Childconst child = new Child()child.info.splice(0,1)const child2 = new Child()console.log(child,'child');console.log(child2,'child');
长处:同时解决了构造函数援用类型的问题和防止了办法被创立屡次。
毛病:父类构造函数被调用了两次,同时子类实例以及子类原型对象上都会存在info属性。
寄生组合继承
在组合继承的根底上,解决了父类结构函数调用两次的问题。
function Parent() { this.info = ['name','age','sex']}Parent.prototype.getName = function () { return this.info;}function Child() { Parent.call(this) this.topic = 'fe';}inherit(Child,Parent)function inherit(child,parent) { let prototype = Object(parent.prototype) prototype.constructor = child child.prototype = prototype}function object(o) { function f() {} f.prototype = o; return new f()}const child = new Child()child.info.push('school')const child2 = new Child()console.log(child,'ll'); //['name', 'age', 'sex', 'school']console.log(child2,'22'); //['name', 'age', 'sex']
长处:是目前为止最正当的实现继承的形式。
毛病:比较复杂。
ES6继承
ES6提供了class语法糖,同时提供了extends用于实现类的继承。这也是我的项目开发中举荐应用的形式。
class Ground{ constructor(age){ this.age = age; } lunch(){ console.log('吃午饭'); }}class Person extends Ground{ constructor(name,age){ super(age); this.name = name; } drink(){ console.log('喝水'); }}class Student extends Person{ constructor(name,score,age){ super(name,age); this.score = score; }; info(){ console.log(`我是${this.name},年龄${this.age},分数${this.score}`); }}const student = new Student('张三',19,99)student.info() // 我是张三,年龄99,分数19
参考
https://juejin.cn/post/684490...
https://zhuanlan.zhihu.com/p/...