ES6中類的概念

Class

在JavaScript中,是通過構造函數來生成實例對象。

function A(a){
    this.a=a
}
A.prototype.sayA=function(){
    console.log(this.a)
}
var a=new A('a')
a.sayA()

在ES6中引入了class(類)的概念,通過class關鍵字可以定義類。這種寫法使得對象原型的寫法更加清晰、更像面對對象編程的語法了。

class A{
    constructor(a){
        this.a=a
    }
    sayA(){
        console.log(this.a)
    }
}
var a=new A('a')
a.sayA()

在定義類的方法時,不需要加上function關鍵字,使用的時候也是直接對類進行new命令,跟構造函數是一樣的。

構造函數的prototype屬性,在 ES6 的類中繼續存在,類的所有方法都定義在類的prototype屬性上面。

class A{
    constructor(){
    }
    sayA(){}
    sayB(){}
}

相當於

A.prototype={
	sayA(){},
	sayB(){}
}

因此在類的實例中調用方法,其實調用的是原型上的方法。而且,類的內部定義的所有方法都是不可枚舉的,而es5中的是可枚舉的。

class A{
    constructor(){
    }
    sayA(){}
    sayB(){}
}
Object.keys(A.prototype) //[]

function A(){}
A.prototype.sayA=function(){}
A.prototype.sayB=function(){}
Object.keys(A.prototype) //['sayA','sayB]

constructor

constructor方法是類的默認方法,通過new命令生成對象實例時,自動調用該方法。一個類必須有constructor方法,如果沒有顯式定義,一個空的constructor方法會被默認添加。

class A(){}
//等同
class A(){
	constructor(){}
}

類的實例

實例的屬性除非顯式定義在其本身(即定義在this對象上),否則都是定義在原型上(即定義在class上)。

class A{
    constructor(a){
        this.a=a
    }
    sayA(){
        console.log(this.a)
    }
}
var a=new A('a')
console.log(a.hasOwnProperty('a'))    //true
console.log(a.hasOwnProperty('sayA'))  //false
console.log(a.__proto__.hasOwnProperty('sayA'))  //true

類的所有實例共享一個原型對象。

var a=new A('a')
var b=new A('b')
console.log(a.__proto__===b.__proto__)   //true

可以通過__proto__屬性對類添加方法。

getter、setter

在類的內部可以使用getset關鍵字,對某個屬性設置存取函數,攔截屬性的存取行爲。

class A{
    constructor(a){
        this.a=a
    }
    get value(){
        return this.a
    }
    set value(val){
        this.a=val
    }
}
var a=new A()
a.value=3
console.log(a.value)  //3

屬性表達式

類的屬性名,可以通過表達式設置

let methodsName1='sayA'
class A{
    constructor(){}
	[methodsName1](){}
}

class表達式

與函數一樣,類也可以用表達式的形式進行定義。

const Aclass= class A{
	sayA(){
		return A.value
	}
}

這個類的名字是AA只在 Class 的內部可用,指代當前類。在 Class 外部,這個類只能用AClass引用。如果類的內部沒有用到的話,可以直接寫成

const Aclass=class{}

採用class表達式的寫法,可以寫出立即執行的class

const Aclass=new class A{
    constructor(value){
        this.value=value
    }
	sayA(){
		console.log(this.value)
	}
}('a')
Aclass.sayA()   //a

靜態方法

在方法前面加上static關鍵字,就表示該方法不會被實例繼承,而是直接通過類來調用,這就稱爲“靜態方法”。

class A{
	static aMethod(){
		console.log('hi')
	}
}
A.aMethod()   //hi
var a=new A() 
a.aMethod()   //TypeError: a.aMethod is not a function

如果靜態方法包含this關鍵字,這個this指的是類,而不是實例。靜態方法可以與非靜態方法重名

class A{
	static aMethod1(){
		this.aMethod2()   //this指向了類A,而不是實例
    }
    static aMethod2(){
        console.log('hi2')
    }
    aMethod1(){    //與靜態方法重名了
        console.log('sup?')
    }
}
A.aMethod1()   //hi2
var a=new A()
a.aMethod1()   //sup?

父類的靜態方法,可以被子類繼承。

class A{
	static aMethod(){
		console.log('hi')
	}
}
class AA extends A{
}
AA.aMethod()  //hi

靜態方法可以從super對象上調用的。

class A{
	static aMethod(){
		return `hi`
	}
}
class AA extends A{
    static aMethod(){
        console.log(`${super.aMethod()} , sup?`)
    }
}
AA.aMethod()  // hi , sup?

私有屬性

私有屬性只能在類的內部調用,在類的外部調用就會報錯。引入一個新的前綴#表示私有屬性。

class A{
    #val='value',
    sayValue(){
        console.log(this.#val)
    }
}
var a=new A()
console.log(a.#val)    //Private field '#val' must be declared in an enclosing class
console.log(a.sayValue())  //value

注意點

1、不存在變量提升

new A(); // ReferenceError
class A {}

2、es6默認就是嚴格模式

3、generator方法
在某個方法之前加上星號(*),就表示該方法是一個 Generator 函數。

class A {
  constructor(...args) {
    this.val = args;
  }
  * [Symbol.iterator]() {
    for (let arg of this.val) {
      yield arg;
    }
  }
}
for (let x of new A('a', 'b')) {
  console.log(x);
}
// a
// b

Symbol.iterator方法返回類的默認遍歷器,for...of循環會自動調用這個遍歷器。

4、this指向
類的方法內部如果含有this,它默認指向類的實例,但是類的內部採用的是嚴格模式,很容易報錯。

class A{
    sayA(a='a'){
        this.log(a)
    }
    log(val){
        console.log(val)
    }
}
const a=new A()
const {sayA}=a;
sayA()   //Uncaught TypeError: Cannot read property 'log' of undefined

將方法提取出來單獨使用,this會指向該方法運行時所在的環境(由於 class 內部是嚴格模式,所以 this 實際指向的是undefined),從而導致找不到方法而報錯。

一個比較簡單的解決方法是,在構造方法中綁定this,就不會找不到方法了。

class A{
    constructor(){
        this.sayA=this.sayA.bind(this)    //對方法進行綁定
        //this.sayA=()=>this       //通過箭頭函數也可以實現。
    }
    sayA(a='a'){
        this.log(a)
    }
    log(val){
        console.log(val)
    }
}
const a=new A()
const {sayA}=a;
sayA()
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章