類這個概念對於作後臺的應該是很是熟悉,JavaScript的類對於其餘面向對象的語言差別很大,只能使用構造函數生成實例對象。爲了接近傳統語言,ES6引入了class類這個概念,經過class關鍵字定義類。編程
Class實際上是一個語法糖,幾乎全部功能均可以用其餘方法實現,只是讓代碼更清晰,更像面向對象編程。bash
語法:函數
class User{
constructor(){
console.log('默認調用');
}
eat(){
console.log('eat方法');
}
}
var user = new User();//默認調用
user.eat()//eat方法
複製代碼
注意,類的方法是不能加function關鍵字,方法之間也不能用逗號分隔,否則會報錯。類的全部方法都定義在類的prototype方法。在類的實例調用方法就是調用原型上的方法。ui
class User{
eat(){}
}
複製代碼
等同於:this
function User() {}
User.prototype.eat = function () {}
複製代碼
類內部定義的方法都是不可枚舉的,這跟ES5不同。spa
Constructor方法:prototype
這個方法是默認方法,經過new生成實例對象的時候自動調用,每一個類都會有,若是沒有顯式定義,會自動添加一個空的constructor方法。默認返回實例對象,也就是this。你也能夠返回另外的對象,這跟構造函數是同樣的。類必須使用new調用,而咱們的構造函數還能當作方法直接調用。code
與 ES5 同樣,實例的屬性除非顯式定義在其自己(即定義在this對象上),不然都是定義在原型上(即定義在class上),類的全部實例共享一個原型對象,所以一個實例對象經過原型__proto__改寫了原型,全部實例對象都會改變,全部不推薦使用實例的__proto__改寫原型。cdn
一樣的,getter函數和setter函數也能夠在類裏面使用關鍵字get和set:對象
class User{
constructor(){
this.name = 'wade';
} get eat(){
return '這是get';
}
set eat(val){
console.log('set調用了');
}
}
var user = new User();
user.eat = 3//set調用了
console.log(user.eat);//這是get
複製代碼
表達式:
屬性能夠用[]表達式,這個跟對象是同樣的,類也能夠直接用表達式定義:
var val = 'my'
var User = class Muser{
[val](){
}
}
複製代碼
Muser只能在class內部可用,class外部使用User。若是內部不使用,也能夠省略Muser或者當即執行class:
var User = class {}
var user = new class{}()
複製代碼
要注意,class默認就是嚴格模式,並且不存在變量提高,name的屬性也是返回class關鍵字後面的類名,還能夠使用Gernerator方法。類方法內部的this默認指向類的實例,單獨拿出來使用會報錯。
類的方法前面加上static關鍵字,那麼這個方法不會被實例繼承,能夠經過類調用,這個方法叫作靜態方法:
class User{
static eat(){
console.log('eat');
}
}var user = new User();
console.log(user.eat());//報錯
User.eat()//eat
複製代碼
若是靜態方法包含this關鍵字,這個this指的是類,而不是實例:
class User{
static eat() {
this.say();
}
static say() {
console.log('hello');
}
say() {
console.log('world');
}
}
User.eat() // hello
複製代碼
靜態方法和非靜態方法還能夠重名。靜態方法是能夠被子類繼承的。
實例屬性除了定義在constructor裏面,還能直接定義在最頂層:
class User1{
constructor(){
this.name = 'wade';
}
}
class User2{
name = 'kobe';
}
console.log(new User1().name);//wade
console.log(new User2().name);//kobe
複製代碼
Class自己的屬性叫作class的靜態屬性,Class.propName,不是定義在實例對象this上的屬性。Class內部只有靜態方法沒有靜態屬性,如今只有一種寫法:
class User{};User.prop = 1;
可是有提案使用static定義:
class User{
static prop = 1;
};
複製代碼
從代碼組織原則和聲明來看,這樣的寫法無疑是更好的。
咱們都知道代碼封裝私有屬性和私有方法是很重要的,可是ES6的class暫時是沒有提供的。變通的解決方法好比區分命名、方法移出模塊、用symbol變量等。但都不是很好。如今有個提案,使用#來提供私有屬性:
class User{
#prop = 1;
#eat(){}
};
複製代碼
只能在內部使用,外部訪問就報錯。私有屬性也能夠設置 getter 和 setter 方法。私有屬性不限於從this引用,只要是在類的內部,實例也能夠引用私有屬性:
class User{
#prop = 1;
static eat(user){
console.log(user.#prop);
}
};
User.eat(new User());//1
複製代碼
new是從構造函數生成實例對象的命令。ES6 爲new命令引入了一個new.target屬性,該屬性通常用在構造函數之中,返回new命令做用於的那個構造函數。若是構造函數不是經過new命令或Reflect.construct()調用的,new.target會返回undefined,所以這個屬性能夠用來肯定構造函數是怎麼調用的:
function User() {
console.log(new.target === User);//true
console.log(new.target !== undefined);//true
}
var user = new User();
複製代碼
若是不是new:
function User() {
console.log(new.target === User);//false
console.log(new.target !== undefined);//false
}
User();
複製代碼
Class 內部調用new.target,返回當前 Class:
class User{
constructor(){
console.log(new.target === User)//true
}
}
new User();
複製代碼
子類繼承父類時,new.target會返回子類。利用這個特色,能夠寫出不能獨立使用、必須繼承後才能使用的類。