class

i涵涵發表於2019-02-21

Class

ES6當中引入了類的概念。當然類在ES6當中是基於原型的語法糖,所以,ES6中類的方法基本都可以通過原型來實現。

那麼以生成一個身份證資訊為例。來介紹一下ES6的類。

定義一個構造器函式 傳統方式定義 function Make(name, id){ this.name = name; this.id = id; } Make.prototype.printName = function() { console.log(this.name); } Make.prototype.nation = "中國"; Make.prototype.desc = "身份證生成";

ES6類的宣告 class Make{ constructor(name, id) { this.name = name; this.id = id; } printName() { console.log(this.name); } } Make.prototype.nation = "中國"; Make.prototype.desc = "身份證生成";

ES6當中的類像極了函式的宣告。實際上

console.log(typeof Make); //function 但是實際上,class與函式宣告又有本質的不同:

class 並不存在函式提升 函式可以直接呼叫,類宣告必須使用new呼叫 類的繼承 傳統方式構造器函式繼承 因為在ES6之前沒有類的概念,我們更多的是使用原型繼承和繼承構造器函式。 在ES6之前,我們通過去整合一個構造器函式最簡單的方法就是使用Parent.call(this);如下:

function Animal() { this.type = "哺乳動物" } function Dog(name) { Animal.call(this); this.name = name; } console.log(new Dog("大黃狗")); 那麼,我們的Dog構造器就繼承了Animal構造器函式;Dog例項如下:

image;

ES6類的構造器函式繼承 在ES6當中,繼承必須使用extends關鍵字去繼承。程式碼如下:

class Animal{ constructor() { this.type = "哺乳動物"; } } class Dog extends Animal{ constructor(name) { super(); this.name = name; } } console.log(new Dog("大黃狗")); 可以看到,在ES6當中,繼承一個構造器函式需要做兩件事:

定義子類的時候,使用extends關鍵字。 在子類的構造器函式中呼叫super()。 這個super()實際上類似於Animal.call(this);但是又有所不同。

注意點:

super()方法必須存在且是函式呼叫,不然無法呼叫。 super()方法和call去呼叫有本質的不同之處。因為在類的繼承當中,super()方法將會優先於Animal.call(this)執行。 原生構造器函式的繼承 傳統方式無法繼承原生構造器函式 在ES6之前,去繼承一個原生的構造器函式是做不到的。例如,我們都知道,Array是陣列的構造器函式。那麼,如果我們去整合這個Array的構造器函式,就可以生成一個自己的陣列構造器,然後還可以新增上自己的方法。但是,這是做不到的。例如:

function MyArray() { Array.call(this,arguments); }

const myarr = new MyArray(1,2,3); MyArray.prototype = {...Array.prototype}; MyArray.constructor = MyArray; console.log(myarr);

image

結果並沒有生成一個新的陣列。

ES6類繼承原生構造器函式 我們使用extends和super()去繼承原生構造器函式,程式碼如下:

class MyArray extends Array{ constructor(...args) { super(...args); } }

const myarr = new MyArray(1,2,3); console.log(myarr);

image;

可以發現,我們確確實實通過了自己的建構函式生成了一個陣列。那麼就實現了繼承原生構造器函式。我們還可以在這個子類上新增各種方法,來實現封裝我們自己的陣列函式。還可以呼叫陣列上的各種快捷操作。

ES6類能繼承原生構造器函式的本質原因

前面我們說過,super()方法類似於Parent.call(this);究其原因還要分析道 new 做的幾件事當中去。

新生成一個物件。 將構造器函式的this指向新生成的物件。 將新生成物件通過__proto__指向構造器函式的原型。 返回新生成的物件。 在我們使用call方法去實現繼承的時候,實際上,已經做到了第二件事之後。那麼,在ES6之前,原生的構造器方法內部的this是不接受call方法傳入的。也就是說,我們無法通過call方法去呼叫原生構造器上的屬性和方法。導致繼承失敗。

在ES6的super()方法當中,super()方法將作為優先執行。那麼將發生在第二件事之前。所以,相當於已經生成了一個新的陣列物件,然後再將新生成物件中的this修飾為新生成的物件。那麼,我就可以在這個陣列物件上呼叫陣列物件的方法了。做完這件事之後。才可以去做第二件事。這也是為什麼如果沒有super方法使用new會報錯。因為,在沒有super方法之前。第二件事也就沒有辦法完成,導致瀏覽器報錯。

所以為了符合語義:

總是保證在有extends關鍵字的情況下使用super()方法。 super()方法寫在子類構造器函式的最開頭。 完成一個例子 需求:

使用類的繼承,實現繼承原生構造器的陣列。然後通過傳入電影的物件,生成陣列。該例項物件具有排序方法,總是返回電影前3的電影排名。

需求程式碼:

const movie = new Movies({ name: "復聯者聯盟3", numbers: 1111 }, { name: "摔跤吧!爸爸", numbers: 998 }, { name: "捉妖記2", numbers: 1000 }, { name: "大開眼戒", numbers: 777 }, { name: "東方列車謀殺案", numbers: 2222 }); 通過傳入物件,生成一個陣列,該陣列實現了票房資料的排序。

實現程式碼:

class Movies extends Array{ constructor(...movies) { super(...movies); let now = new Date(); this.name = ${now.getMonth()+1}月${now.getDate()}日電影票房資料 }

getTop (){
    return this.sort((prev, curr) => curr.numbers-prev.numbers)
}
getTop3 (){
    let arr = this.getTop();
    return arr.slice(0,3);
}
複製程式碼

}

相關文章