(1) 原型继承 - 将父类的实例作为子类的原型// 父类function Super(name) { this.name = name}Super.prototype.getAddress = function() { return 'chongqing'}// 子类function Sub(age) { this.age = age}Sub.prototype = new Super('woow-wu') -------- 将父类的实例作为子类实例的原型,子类的实例即可以访问父类实例和父类原型上的属性和方法Sub.prototype.getSex = function() { return 'man'}const sub = new Sub(20)console.log(sub.name) ------------------- 先在sub实例上找name,未找到再在super实例上查找,未找到再在super原型上查找 // 'woow-wu'console.log(sub.getAddress()) // 'chongqing'console.log(sub.age) // 20console.log(sub.getSex()) // man
(由于没有new Super,即根本没有new父类,不存在原型链继承)
function Super1 (name) { this.name = {name: name}}function Super2 (sex) { this.sex = sex}Super.prototype.getAddress = function() { return 'chongqing'}function Sub(name, sex) { Super.call(this, name) -------------- 直接调用Super类(函数),将Super中的this绑定在sub实例上,并传参给父类 Super2.call(this, sex)}const sub1 = new Sub('woow-wu', 'man') ------------------------------ 可以向父类传参console.log(sub1) // {name: {…}, sex: "man"}const sub2 = new Sub('wang', 'woman')console.log(sub2) // {name: {…}, sex: "woman"} ----------------------- 可以实现多继承,且实例之间的属性互不影响
原型链继承和借用构造函数继承的组合
优点
可以传参,多继承,不存在属性共享
缺点
function Super(name) { this.name = name this.score = 100}Super.prototype.getName= function() { return 'super' + this.name}function Sub(name, dress) { Super.call(this, name) this.address = address}Sub.prototype = new Super() // 注意,这里没有传参,在原型链继承这条线上,父类原型上的nane属性是undefinedSub.ptototype.getSex = function() { return 'man'}cosnt sub = new Sub('woo-wu', 'chongqing')console.log(sub)组合继承最大的缺点:1. 父类执行了两次属性 - 1. 在new Sub('woo-wu', 'chongqing')是会执行Super.call(this, name)------- 生成一次name,score - 2. 在Sub.prototype = new Super() 执行了一次,又会生成一次name,score
const obj = { name: 'wang', frends: ['li', 'go']}obj.__proto__ .age = 20function createObj(obj) { function F(){} F.prototype = obj return new F()}const a = createObj(obj)const b = createObj(obj)a.name = 'xxxxx' // ----------------- 这样实际上是直接在a对象上增加了name属性,而不是修改a原型上的属性, 原型上的属性值不能直接通过实例来修改// ----------------- 假如要修改,需要通过 a.__proto__.name = 30这样来修改 console.log(a.name) // xxxxx console.log(b.name) // 'wang' console.log(a.age) // 20
寄生组合式继承如图4组合式继承存在的问题:1. 父类构造函数执行了两次 - 在借用构造函数式的时候执行了1次 - 在原型继承的时候执行了1次 - 所以子类实例上有父类中的属性和方法,子类的原型对象(即父类的实例)上也有父类的属性和方法function Father (name) { this.name = name}Father.prototype.addressFather = 'china'function Child(name, sex) { Father.call(this, name) //----------------------------------------- 借用构造函数继承 this.sex = sex}// Child.prototype = new Father() //------------------------------ 原型继承function F(){}F.prototype = Father.prototypeChild.protype = new F() --------------- 这样就没有执行父类(构造函数),而是间接只继承了父类的原型Child.prototype.addressChild = 'shanghai'const child = new Child('wang', 'man')console.log(child)console.log(child.name) // wangconsole.log(child.__proto__.name)
组合继承: 下图 图5function Father (name) { this.name = name}Father.prototype.addressFather = 'china'function Child(name, sex) { Father.call(this, name) //----------------------------------------- 借用构造函数继承 this.sex = sex}Child.prototype = new Father() //------------------------------ 原型继承Child.prototype.addressChild = 'shanghai'const child = new Child('wang', 'man')console.log(child)console.log(child.name) // wangconsole.log(child.__proto__.name) ----------------------------- undefined,由于new Father()时没有传参
https://www.songma.com/p/a8844b28ff79
https://juejin.im/post/591523588d6d8100585ba595
__proto__
和prototype
,由于函数是函数也是对象__proto__
总是指向父类 (表示构造函数的继承)__proto__
总是指向父类的prototype(表示方法的继承)1. 作为对象,------------------------------ A.__proto__ = B2. 作为构造函数,-------------------------- A.prototype.__proto__ = B.prototype
class Father { constructor() { console.log(new.target.name) } } class Child extends Father { constructor() { super() ------------------- super作为函数,只能用于构造函数,表示父类的构造函数 ------------------- 但是super内部的this指代的是子类的实例 } } const fahter = new Father() // Father const child = new Child() // Child ------ 由于super尽管是借用了父类的构造函数,但是this绑定在子类的实例上,(相似借用构造函数继承) new.target用在函数内部,假如该函数通过new命令调用,new.target指正在执行的函数
(函数 或者者 对象)
父类的构造函数
(super作为函数时,只能用在构造函数中) class A { constructor() { this.name = 'woow-wu' } go() { console.log('home') } } class B extends A { constructor() { super() -------------------- super作为函数,只能用于构造函数,表示父类的构造函数,但this指向子类实例 super.go() ------------------ super作为对象,在普通函数中指 父类的原型 ---- 所以无法继承父类实例上的属性和方法 } getName() { return super.name } } cosnt b = new B() b.getName ----------------------------- undefined,父类实例上的name并没有被继承,super指的是父类的原型
super作为对象,表示父类的原型,内部的this指的是子类的实例super作为函数,表示父类的构造函数,内部的this指的是子类的实例,(作为函数,只能用于构造函数中)class A { constructor() { this.name = 'wang' } getAName() { return this.name } } class B extends A { constructor() { super() this.name = 'li' } getBName() { return super.getAName() } } const b = new B() const res = b.getBName() console.log(res) // li
super作为对象,在静态方法中,指向父类super作为对象,在普通方法中,指向父类的原型class Father { constructor() {} setAge(age) { console.log(age * 100) } static setAge(age) { console.log(age) } } class Child extends Father { constructor() { super() } getAge(age) { super.setAge(age) // 通过实例调用,super在普通方法中,表示父类的原型 } static getAge(age) { super.setAge(age) // 静态方法中的super对象,指的是父类,父类直接调用的是静态方法setAge } } const child = new Child() Child.getAge(10) // 10 静态方法直接通过类直接调用 child.getAge(10) // 1000 通过实例调用的是类原型上的方法