聊聊es6之class

類:構造函數的語法糖

傳統的構造函數的問題

  • 屬性和原型方法定義分離,降低了可讀性
  • 原型成員可以被枚舉
  • 默認情況下,構造函數仍然可以被當作普通函數使用

類的寫法

在es6的class中一個類的靜態方法,私有屬性,原型方法均寫在了一起,解決了傳統構造函數的屬性原型分離的問題

class Plane {
    // 靜態屬性,相當於Plane.alive
    static alive() {
        return true
    }
    constructor(name) { // 這裏是參數
        // 私有屬性
        this.name = name || '普通飛機';
        this.blood = 100;
    }
    // 原型方法 forin不可枚舉此方法
    fly() {
        console.log('fly')
    }
}

類的特點

  • 類聲明不會被提升,與 let 和 const 一樣,存在暫時性死區
console.log(Plane);
class Plane {
    constructor(type) {
        this.type = type
    }
}
// Uncaught ReferenceError: Cannot access 'Plane' before initialization
  • 類中的所有代碼均在嚴格模式下執行
class Plane {
    constructor(type) {
        this.type = type;
        a = 1
    }
}
new Plane()
// Uncaught ReferenceError: a is not defined
  • 類的所有原型方法都是不可枚舉的(私有方法可枚舉)
class Plane {
    constructor(type) {
        this.type = type; // 私有屬性可枚舉
        this.fn = () => {}; // 私有方法可枚舉
    }
    fly() {console.log('fly')} // 原型方法不可枚舉
}
let p = new Plane();
for (const key in p) {
    console.log(key) // type fn
}
  • 類的所有方法都無法被當作構造函數使用(包括靜態方法)
class Plane {
    static fn () { // 靜態方法不可new
        this.name = 'a'
    }
    constructor(type) {
        this.type = type;
    }
    fly() {console.log('fly')} // 原型方法不可new
}
let p = new Plane();
new Plane.fn(); // Uncaught TypeError: Plane.fn is not a constructor
new p.fly(); // Uncaught TypeError: p.fly is not a constructor
  • 類的構造器必須使用 new 來調用
class Plane {
    constructor(type) {
        this.type = type; 
    }
}
Plane(); // Uncaught TypeError: Class constructor Plane cannot be invoked without 'new'

類的其他書寫方式

  • 可計算屬性名
let flyName = 'fly'
class Plane {
    constructor(type) {
        this.type = type; 
    }
    [flyName]() {console.log('fly')} // 計算屬性名
}
let p = new Plane(); 
p[flyName]()
  • getter和setter
// 假設飛機壽命只能爲0-10年
class Plane {
    constructor(type, age) {
        this.type = type;
        this.age = age
    }
    set age(age) {
        if(age < 0) {
            this._age = 0;
        } else if (age > 10) {
            this._age = 10
        } else {
            this._age = age
        }
    }
    get age() {
        return this._age + '歲'
    }
}
let p = new Plane('plane', 2); 
console.log(p.age) // 2歲
  • 靜態成員
class Plane {
    static canFly = true;
    constructor(type, age) {
        this.type = type;
    }
}
console.log(Plane.canFly); // true
  • 字段初始化器
class Plane {
    constructor(type) {
        this.type = type;
    }
    name = '飛機'; // name屬性是私有屬性
    // 這種寫法會將print變爲私有方法
    // 由於使用了箭頭函數,箭頭函數沒有this,所以this永遠爲實例對象
    print = () => {
        console.log(this.type)
    }
}
let p = new Plane('普通飛機');
p.print(); // 普通飛機
let print = p.print; // 即使改變執行環境,也會輸出p的type
print(); // 普通飛機
  • 類表達式
let a = class { // 等同於 class a {...}
    constructor() {
        this.a = 1;
        this.b = 2;
    }
}
console.log(new a())

繼承

繼承有兩個新增關鍵字extends和super
extends用於繼承
super兩個用法
在constructor裏面要先調用super(向父類傳入所需參數)
在方法裏面使用super,super代表父類的原型
用法如下

class Animal {
    constructor(type, name, age, sex) {
        this.type = type;
        this.name = name;
        this.age = age;
        this.sex = sex;
    }
    print() {
        console.log(`【種類】:${this.type}`);
        console.log(`【名字】:${this.name}`);
        console.log(`【年齡】:${this.age}`);
        console.log(`【性別】:${this.sex}`);
    }
}
class Dog extends Animal {
    constructor(name, age, sex) {
        super('犬類', name, age, sex); // 繼承的子類在constructor裏面先調super方法,傳入父類所需參數
        this.like = '喫骨頭'; // 然後添加子類的特有屬性(不能寫在super前面)
    }
    print() { // 覆蓋父類方法
        super.print(); // 調用父類方法使用super
        console.log(`【愛好】:${this.like}`);
    }
}
const a = new Dog("旺財", 3, "男");
a.print()

冷知識
一般情況下,父類是不可以直接new的,創建實例對象是通過子類構造函數來創建,所以可以給父類構造函數做一個處理

class Animal {
    constructor(type, name, age, sex) {
        if (new.target == Animal) { // 可以通過new.target獲得創建實例的構造函數
            throw('不能直接通過Animal創建實例')
        }
        this.type = type;
        this.name = name;
        this.age = age;
        this.sex = sex;
    }
    print() {
        console.log(`【種類】:${this.type}`);
        console.log(`【名字】:${this.name}`);
        console.log(`【年齡】:${this.age}`);
        console.log(`【性別】:${this.sex}`);
    }
}
class Dog extends Animal {
    constructor(name, age, sex) {
        super('犬類', name, age, sex); // 繼承的子類在constructor裏面先調super方法,傳入父類所需參數
        this.like = '喫骨頭'; // 添加子類的特有屬性
    }
    print() { // 覆蓋父類方法
        super.print(); // 調用父類方法使用super
        console.log(`【愛好】:${this.like}`);
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章