原型
我个创立的每一个函数都有一个prototype(原型)属性, 这个属性是一个指针,指向一个对象。而这个对象的作用是蕴含由特定类型的所有实例共享的属性和办法。应用原型的益处是能够让所有实例共享它所蕴含所有属性和办法。换句话说,不用在构造函数中定义对象的实例的信息,而是能够将这些信息增加到原型对象中。(红宝书)
继承的6种办法
继承分ES6和ES5的办法,ES6的办法很简略,就是extends
,然而只晓得这个办法是不合格的。上面说说ES5的办法,共有:
原型链继承、借用构造函数继承、组合式继承、寄生式继承、继生组合式继承
- 原型链继承
让子类的原型等行父类的实例,当子类实例找不到对应的属性和办法时,就会向父类实例上找。
function Parent() { this.name = 'parent'}Parent.prototype.sayName = function() { console.log(this.name)}function Child() { this.name = 'child'}Child.prototype = new Parent()// 最初能够将constructor改回来Child.prototype.constructor = Child
原型链继承的毛病:
- 所有子类的实例的原型都是援用同一个Parent的实例,当其中一个子类实例将原型中的援用类型数据更改时,其余实例对应的数据也会扭转
- 在创立子类实例时不能向Parent传参
借用构造函数
在子类的构造函数中调用父类构造函数(用call / apply将调用的this指向子类实例),这样既防止了实例之间共享同一个原型,又能够向父类构造函数传参。解决了原型链继承的两个问题。
function Parent(name, age) { this.style = [1, 2, 3] this.name = name this.age = age}Parent.prototype.sayStyle = function() { console.log(this.style)}function Child(name, age) { Parent.call(this, name, age)}let child = new Child('child', 11)child.style // [1, 2, 3]child.name // 'child'child.sayStyle() // 报错 is not a function, 因为子实类无奈继承到Parent原型上的办法
借用构造函数的毛病
- 继承不到父类原型上的属性和办法
- 办法都在构造函数中定义, 每次创立都会生成一遍办法
组合继承
将原型链继承和借用构造函数继承(经典继承)组合起来。
function Parent(name) { this.style = [1, 2, 3] this.name = name}Parent.prototype.sayStyle = function() { console.log(this.style)}function Child(name) { Parent.call(this, name)}Child.prototype = new Parent()Child.prototype.constructor = Childlet child = new Child('child')
寄生式继承
创立一个实现继承的函数,以某种形式加强对象,而后返回这个对像.
function createAnother(obj) { const clone = Object(obj) clone.sayHi = function() { console.log('hi') } return clone}
寄生组合式继承
解决组合继承会调用两次父类构造函数的问题(效率问题), 找一个直达的空函数来执行
function Parent(name) { this.name = name this.style = [1, 2, 3]}Parent.prototype.say = function() { console.log(this.style)}function Child(name, age) { Parent.call(this, name) this.age = age}// 直达的空函数function F() {}F.prototype = Parent.prototypeChild.prototype = new F()Child.prototype.constructor = Child