functionPerson( name , age ){ this.name = name this.age = age this.play = function(){ console.log('i can play!') } }
Person.prototype.say = function(){ console.log('hello i am a person') }
functionMan( name , age ){ this.name = name this.age = age }
Man.prototype = newPerson() Man.prototype.constructor = Man// 修复原型链指向 // Man 自定义的方法或属性 Man.prototype.foo = function(){ console.log('this is foo func in Man') }
var p = newMan('小红', 14) console.log( p.name , p.age ) // 小红 14 p.say() // hello i am a person p.foo() // this is foo func in Man p.play() // Uncaught TypeError: p.play is not a function
如上代码,我们为了实现原型继承,将父类 Person 的实例对象赋值给了 Man.prototype 这时候 Man 便拥有了 Person 原型上的所有属性和方法。 但是要注意,为了不破坏 Man 的原型链,必须将 Man.prototype.constructor 指向 Man。此时,我们没有继承到父类 Person 构造函数内的属性及方法。
// 自身的静态方法 staticbar(){ console.log('this is a static method bar') }
}
let p = newMan('小红', 14, 188)
console.log( p.name , p.age , p.height ) // 小红 14 188 p.play() // i can play Man.bar() // this is a static method bar p.say() // hello i am小红(Preson) Man.foo() // this is a static method foo
子类必须在 constructor 方法中调用 super 方法,否则新建实例时会报错。这是因为子类自己的 this 对象,必须先通过父类的构造函数完成塑造,得到与父类同样的实例属性和方法,然后再对其进行加工,加上子类自己的实例属性和方法。如果不调用 super 方法,子类就得不到 this 对象。
1 2 3 4 5 6 7 8
classPoint { /* ... */ }
classColorPointextendsPoint { constructor() { } }
let cp = newColorPoint(); // ReferenceError
上面代码中,ColorPoint 继承了父类 Point,但是它的构造函数没有调用 super 方法,导致新建实例时报错。
ES5 的继承,实质是先创造子类的实例对象 this,然后再将父类的方法添加到 this上面(Parent.apply(this))。ES6 的继承机制完全不同,实质是先将父类实例对象的属性和方法,加到 this 上面(所以必须先调用 super 方法),然后再用子类的构造函数修改 this。
另一个需要注意的地方是,在子类的构造函数中,只有调用 super 之后,才可以使用 this 关键字,否则会报错。这是因为子类实例的构建,基于父类实例,只有 super 方法才能调用父类实例。
super关键字
super 这个关键字,既可以当作 函数 使用,也可以当作 对象 使用。在这两种情况下,它的用法完全不同。
作为函数时
super 作为函数调用非时,表示父类的构造函数 Parent.prototype.constructor,es6 规定,在使用 extends 实现继承时,必须先在子类的构造函数中优先调用一次 super(),否则直接使用 this 会报错。并且 super 作为函数调用时,只能出现在子类的构造函数中,用在其他地方会报错。
作为对象时
当 super 作为对象调用时,在普通方法中,指向父类的原型对象;在静态方法中,指向父类。
ES6 规定,在子类普通方法中通过 super 调用父类的方法时,方法内部的 this 指向当前的子类实例。
另外,在子类的静态方法中通过 super 调用父类的方法时,方法内部的 this 指向当前的子类,而不是子类的实例。
注意,使用 super 的时候,必须显式指定是作为函数、还是作为对象使用,否则会报错。
Mixin 模式的实现
Mixin 指的是多个对象合成一个新的对象,新对象具有各个组成成员的接口。它的最简单实现如下。
1 2 3 4 5 6 7
const a = { a: 'a' }; const b = { b: 'b' }; const c = {...a, ...b}; // {a: 'a', b: 'b'}