JavaScript 中的類別
function PersonType(name){ this.name = name;}PersonType.prototype.sayName = function(){ console.log(this.name)}var person = new PersonType("Nicholas")person.sayName(); // outputs "Nicholas"console.log(person instanceof PersonType) // trueconsole.log(person instanceof Object) // true類別宣告
class PersonClass { // 等價於PersonType建構函式 constructor(name){ this.name = name } // 等價於PersonType.prototype.sayName sayName(){ console.log(this.name) }}let person = new PersonClass("Nicholas");person.sayName(); // outputs "Nicholas"console.log(person instanceof PersonClass) //trueconsole.log(person instanceof Object) // trueconsole.log(typeof PersonClass) // functionconsole.log(typeof PersonClass.prototype.sayName) // functionclass是語法糖,PersonClass 宣告實際上建立了一個具有建構函式方法行為的函式。透過Symbol.iterator定義產生器方法即可定義預設迭代器
class Collection {
constructor(){
this.items = [];
}
*[Symbol.iterator](){
yield *this.items.values()
}
}
var collection = new Collection();
collection.items.push(1);
collection.items.push(2);
collection.items.push(3);
for(let x of collection){
console.log(x);
}
// 輸出:
// 1
// 2
// 3
靜態成員
ES6 類別語法簡化了建立靜態成員的過程,在方法或存取器屬性名前使用正式的靜態註釋即可。
class PersonClass {
// 等價於PersonType建構函式
constructor(name){
this.name = name
}
// 等價於PersonType.prototype.sayName
sayName(){
console.log(this.name)
}
// 等價於等價於PersonType.create
static create(name){
return new PersonClass(name)
}
}
let person = PersonClass.create("Nicholas")
繼承與衍生類別
實作繼承與自訂型別是一項不小的工作,嚴格意義上的繼承需要多個步驟來實作
function Rectangle(length,width){
this.length = length;
this.width = width;
}
Rectangle.prototype.getArea = function(){
return this.length*this.width
}
function Square(length){
Rectangle.call(this,length,length)
}
Square.prototype = Object.create(Rectangle.prototype,{
constructor:{
value:Square,
enumerable:true,
writable:true,
configurable:true
}
})
var square = new Square(3)
console.log(square.getArea()); // 9
console.log(square instanceof Square) // true
console.log(square instanceof Rectangle) // true
ES6 使用extends關鍵字可以指定類別繼承的函式。原型會自動調整,透過呼叫 super() 方法即可存取基底類別的建構函式
class Rectangle {
constructor(length,width){
this.length = length;
this.width = width
}
getArea(){
return this.length*this.width;
}
}
class Square extends Ractangle {
constructor(length){
// Rectangle.call(this,length,length)
super(length,length)
}
}
var square = new Square(3)
console.log(square.getArea()); // 9
console.log(square instanceof Square) // true
console.log(square instanceof Rectangle) // true
繼承自其的類別我們稱之為衍生類別,如果在衍生類別中指定了建構函式,則必須呼叫 super(),如果沒有這樣做,程式就會報錯。
- super
- 只能在衍生類別的建構函式中使用 super(),非衍生類別不可使用
- 在建構函式中存取 this 之前一定要呼叫 super,它負責初始化 this,
- 如果不想呼叫 super(),則唯一的方法是讓類別的建構函式回傳一個物件。
類別方法遮蔽
衍生類別中的存取總是會覆寫基底類別中的同名方法,如果想呼叫基底類別中的方法,我們可以使用super.getArea()
class Square extends Rectangle {
constructor(length){
super(length,length)
}
//覆蓋並遮蔽Rectangle.prototype.getArea()方法
getArea(){
return this.length*this.length
}
}
衍生自表達式的類別
ES6 最強大的一面或許是從表達式匯出類別的功能了。只要表達式可以被解析為一個函式並且具有[[Construct]]屬性與原型,那麼就可以用 extends 進行衍生。
內建物件的繼承
class MyArray extends Array {
// 空
}
var colors = new MyArray();
colors[0]="red"
console.log(colors.length) // 1
colors.length = 0
console.log(colors[0]); // undefined
MyArray 直接繼承自 Array,其行為與 Array 也很相似,操作數值型屬性會更新 length 屬性,操作 length 屬性也會更新數值型屬性。於是,可以正確地繼承 Array 物件來建立自己的衍生陣列型別
Symbol.species 屬性
內建物件繼承的一個實用之處是,原本在內建物件中回傳實例自身的方法將自動回傳衍生類別的實作。例如,如果你有一個繼承自 Array 的衍生類別 MyArray,那麼像 slice() 這樣的方法也會回傳一個 MyArray 的實例
class MyArray extends Array{
// 空
}
let items = new MyArray(1,2,3,4),
subitems = items.slice(1,3);
console.log(items instanceof MyArray); //true
console.log(subitems instanceof Myarray); // true
Symbol.species是諸多內部 Symbol 中的一個,它被用於定義回傳函式的靜態存取器屬性。被回傳的函式是一個建構函式,每當要在實例方法中(不是建構函式中)建立類別的實例時,必須使用這個建構函式。以下這些都是實作該屬性定義的Symbol.species
- Array
- ArrayBuffer
- Map
- Promise
- RegExp
- Set
- Typed arrays
// 幾個內建型別像這樣使用
class MyClass {
static get [Symbol.species](){
return this
}
constructor(value){
this.value = value
}
clone(){
return new this.constructor[Symbol.species](this.value)
}
}
在建構函式中使用 new.target
class Shape {
constructor(){
if(new.target === Shape){
throw new Error("這個類別是不能直接被實例化的")
}
}
}
class Rectangle extends Shape {
constructor(length,width){
super();
this.length = length;
this.width = width;
}
}
let x = new Shap(); // 拋出錯誤
let y = new Rectangle(3,4) // 正常執行
console.log(y instanceof Shape) //true
主題測試文章,只做測試使用。發佈者:Walker,轉轉請注明出處:https://walker-learn.xyz/archives/4335