class語法爲咱們提供了構造函數的語法糖,響應的,也給咱們提供了ES5經過原型鏈實現繼承提供了extends關鍵字實現繼承。繼承這個概念對面後臺應該也是很是常見。bash
經過extends繼承,語法:數據結構
class User{}函數
class Son extends User{}ui
繼承以後Son可使用User類的全部屬性和方法:this
class User{
constructor(a){
this.a = a;
this.b = 10;
}
eat(){
console.log('user eat');
}
}
class Son extends User{
constructor(b, c){
super(b);
this.c = c;
}
sum(){
console.log(this.a, this.b, this.c);
}
}
var son = new Son(1, 2);
son.eat();//user eat
son.sum();//1 10 2
複製代碼
子類必須在constructor方法中調用super方法,不然新建實例時會報錯。這是由於子類本身的this對象,必須先經過父類的構造函數完成塑造,獲得與父類一樣的實例屬性和方法,而後再對其進行加工,加上子類本身的實例屬性和方法。若是不調用super方法,子類就得不到this對象。spa
若是子類沒有定義constructor方法,這個方法會被默認添加,須要注意的地方是,在子類的構造函數中,只有調用super以後,纔可使用this關鍵字,不然會報錯。這是由於子類實例的構建,基於父類實例,只有super方法才能調用父類實例。靜態方法也會繼承。prototype
經過Object.getPrototypeOf獲取父類:code
class User{}
class Son extends User{}
console.log(Object.getPrototypeOf(Son));//class User{}
複製代碼
Super關鍵字有兩個用法,一個是函數,一個是對象。當作函數的時候只能在子類的構造函數中使用,子類必須調用,也就是constructor裏面,其餘地方會報錯:cdn
class User{}
class Son extends User{
eat(){
super();
}
}
//Uncaught SyntaxError: 'super' keyword unexpected here
複製代碼
做爲對象的時候,普通方法super指向父類的原型對象,在靜態方法中指向父類;對象
class User{
constructor(){
this.a = 1;
this.b = 1;
}
eat(){
console.log(this.b);//10
return 2
}
}
class Son extends User{
constructor(){
super();
this.b = 10;
this.c = 20;
console.log(super.c);//undefined
console.log(this.c);//20
}
talk(){
console.log(super.a);//undefined
console.log(super.eat());//2
}
}
var son = new Son();
son.talk();
複製代碼
普通方法中,super指向父類原型對象(constructor裏面是實例的屬性),因此調用eat方法能夠,a就獲取不到。若是屬性定義在父類的原型對象上,能夠獲取。子類調用super的時候,this指向當前子類的實例。對super賦值至關於爲this賦值。
靜態方法中,super指向父類,也就是User類:
class User{
constructor(){
this.a = 10;
}
static eat(val) {
console.log('static', val);
}
eat(val) {
console.log('instance', val);
}
static talk(){
console.log(this.a);
}
}
class Son extends User{
constructor(){
super();
this.a = 20;
}
static eat(val) {
super.eat(val);
}
eat(val) {
super.eat(val);
}
static talk(){
super.talk();
}
}
Son.a = 30;
Son.talk();//30
Son.eat(1); // static 1
var son = new Son();
son.eat(2); // instance 2
複製代碼
子類Static eat方法super指向父類,因此調用父類static eat方法,子類普通方法eat指向父類原型對象,因此調用父類普通方法eat。子類靜態方法super內部this指向當前子類,而不是實例或者原型對象,因此子類Son調用talk方法,輸出的是30。
使用super必須指定是函數仍是對象,不然報錯。
類也是有prototype和__proto__屬性的,相應的構成原型鏈:
子類的__proto__屬性是構造函數的繼承,指向父類
子類的prototype屬性的__proto__屬性,表示方法的繼承,指向父類的prototype。
class User{}
class Son extends User{}
console.log(Son.__proto__ === User); // true
console.log(Son.prototype.__proto__ === User.prototype); // true
複製代碼
由於類的繼承是經過setPrototypeOf。
子類實例的__proto__屬性的__proto__屬性,指向父類實例的__proto__屬性。也就是說,子類的原型的原型,是父類的原型:
class User{}
class Son extends User{}
console.log(Son.__proto__ === User.__proto__); // false
console.log(Son.__proto__.__proto__ === User.__proto__); // true
複製代碼
原生的構造函數Boolean()、Number()、String()、Array()、Date()、Function()、RegExp()、Error()、Object()在ES5以前是沒法繼承的,ES6能夠自定義原生數據結構:
class MyArray extends Array {
constructor(...args) {
super(...args);
}
}
var arr = new MyArray();
複製代碼
Misin模式就是把多個對象合成一個新的對象,新對象有各個組成的接口:
var a = {}
var b = {}
var c = {...a, ...b}
複製代碼
阮大神提供了class的Mixin:
function mix(...mixins) {
class Mix {
constructor() {
for (let mixin of mixins) {
copyProperties(this, new mixin()); // 拷貝實例屬性
}
}
}
for (let mixin of mixins) {
copyProperties(Mix, mixin); // 拷貝靜態屬性
copyProperties(Mix.prototype, mixin.prototype); // 拷貝原型屬性
}
return Mix;
}
function copyProperties(target, source) {
for (let key of Reflect.ownKeys(source)) {
if ( key !== 'constructor'
&& key !== 'prototype'
&& key !== 'name'
) {
let desc = Object.getOwnPropertyDescriptor(source, key);
Object.defineProperty(target, key, desc);
}
}
}
複製代碼
使用:
class DistributedEdit extends mix(Loggable, Serializable) {// ...}
複製代碼
建議可使用了看看打印的數據。