ES6中的Class
prototype
class語法中 prototype
依然存在, 類的所有方法都定義在了類的 prototype
屬性上。
class Demo {
constructor() {
//
}
toString() {}
toValue() {}
}
// 等同於
Demo.prototype = {
constructor: Demo,
toString() {},
toValue() {}
}
註意在類的方法之間不要加 ,
號, 否則報語法錯誤,在類的實例上調用方法還是調用原型上的方法。
在類內部定義的方法都是不可枚舉的, 這點應該引起註意;
class Demo {
constructor() {
//
}
toString() {}
toValue() {}
}
Object.keys(Demo.prototype) // []
Object.getOwnPropertyNames(Demo.prototype) // ['constructor', 'toString', 'toValue']
類名的屬性可以采用動態屬性:
class Demo {
constructor() {}
[someProp]() {}
}
註意上面的例子中的 []
不可替換成 ()
, 否則報語法錯誤;
constructor方法
constructor
方法是類的默認方法,通過 new
命令生成對象實例時自動調用該方法。一個類必須要有 constructor
方法, 未顯示定義, js會默認添加一個 constructor
, 該方法默認返回實例對象(this
),這點與 es5
的構造器表現一樣, 也可以指定返回別的對象, 但是指定返回 基本類型 的值會阻止不了返回 this
;
實例對象
生成實例的方法與 es5
的寫法一致, 要使用 new
, 如果沒有 new
調用 class
會報錯
類的所有實例共享一個原型對象
let demo1 = new Demo();
let demo2 = new Demo();
demo1.__proto__ === demo2.__proto__ // true
name屬性
本質上 class
只是 es5
的構造函數的一層包裝, 很多函數具備的特性它也有, name
屬性也不例外;
class表達式
const Demo = class some {
getClassName() {
return some.name;
}
}
let demo = new Demo();
demo.getClassName() // some
some.name // 報錯
跟在表達式後面的名字(如some),只能在類的作用域能引用, 其他位置引用不到, 盡管在全局環境下定義也拿不到, 這樣做的一個應用場景是替代 arguments.callee
, 因為在嚴格模式下
arguments.callee
是不能被使用的, es6
已經把整個語言升級到了嚴格模式,我們可以用表達式右邊的 name
來取代 arguments.callee
; 這個地方和 es5
完全一致;
不存在變量提升
new Demo(); // 報引用錯誤;
class Demo() {};
嚴格模式
類和模塊內部默認已經是嚴格模式;
class繼承
** 基本用法 **
通過 extends
實現繼承, 這點比 es5
實現繼承要清晰和方便;
class Demo extends Array {}
類的內部用 super
代指父類, 子類沒有自己的 this
對象, 而是繼承了父類的 this
對象, 然後對其加工, 如果不調用 super
, 子類就拿不到 this
對象
** 原生構造函數的繼承 **
由於 class
是先拿到父級的 this
, 這點和 es5
不一樣, 子類能拿到原生構造器內部的屬性, 所以能夠完整繼承原生構造器
class Demo extends Array {
constructor(...args) {
super(...args);
}
push(num) {
super.push(num);
return this;
}
}
let arr = new Demo(1, 2);
arr.push(3); // [1, 2, 3]
小結
class
繼承機制和es5
不同, 在子類的constructor
中要首先拿到父類super
的this
, 而es5
的是先創建this
;class
的繼承相對於es5
的繼承實現起來比較簡單清晰, 能夠繼承js
原生構造器;class
內部定義的的方法均是不可見的;
ES6中的Class