ES6 class和面向?qū)ο缶幊?/h1>

在ES5中,我們經(jīng)常使用方法或者對(duì)象去模擬類的使用,并基于原型實(shí)現(xiàn)繼承,雖然可以實(shí)現(xiàn)功能,但是代碼并不優(yōu)雅,很多人還是傾向于用 class 來(lái)組織代碼,很多類庫(kù)、框架創(chuàng)造了自己的 API 來(lái)實(shí)現(xiàn) class 的功能。
ES6 時(shí)代終于有了 class (類)語(yǔ)法,能讓我們可以用更簡(jiǎn)明的語(yǔ)法實(shí)現(xiàn)繼承,也使代碼的可讀性變得更高,同時(shí)為以后的JavaScript語(yǔ)言版本添加更多的面向?qū)ο筇卣鞔蛳禄A(chǔ)。
一、 類的定義

  1. ES5使用函數(shù)模擬類
function Person( name , age ) {
    this.name = name;
    this.age = age;
}
Person.prototype.say = function(){
    return '我叫' + this.name + ',今年' + this.age + '歲';
}
var  p = new Person('xiaoming',33);  // Person {name: "xiaoming", age: 33}
p.say();

使用ES5語(yǔ)法定義了一個(gè)Person類,該類有name age food三個(gè)屬性和一個(gè)原型eat方法。

2.ES class定義類

class Person{
    constructor(name,age){
        this.name = name;
        this.age = age;
    }
    say(){
        return '我叫' + this.name + ',今年' + this.age + '歲';
    }
}
var stu = new Person("xiaoming",22);
p.say();

上面代碼定義了一個(gè)同樣的Person類,constructor方法就是構(gòu)造方法,而this關(guān)鍵字則代表實(shí)例對(duì)象;
注:雖然ES6引入了class關(guān)鍵字,但并沒(méi)有真的引入類這個(gè)概念,通過(guò)class定義的仍然是函數(shù),數(shù)據(jù)類型中也沒(méi)有class類型。

console.log(typeof Person);//還是'function'

所以說(shuō),class僅僅是通過(guò)更簡(jiǎn)單直觀的語(yǔ)法去實(shí)現(xiàn)原型鏈繼承。這種對(duì)語(yǔ)言功能沒(méi)有影響、但是給程序員帶來(lái)方便的新語(yǔ)法,被稱為語(yǔ)法糖。

二、類的傳參
在類的參數(shù)傳遞中,我們?cè)赾onstructor( )進(jìn)行傳參,傳遞參數(shù)后可以直接使用this.xxx進(jìn)行調(diào)用。

class Person{
    constructor(x,y){
        this.x = x;
        this.y = y;
    }
    add(){
        return this.a + this.b;
    }
}
let stu = new Person(11,22);
stu.add();//11+22=33

用constructor來(lái)傳遞參數(shù),然后用了一個(gè)add方法,把參數(shù)相加。

三、靜態(tài)方法

  1. 使用函數(shù)模擬類時(shí),通過(guò)函數(shù)名.靜態(tài)方法名,來(lái)定義靜態(tài)方法:
function Person(name,age){
    this.name = name;
    this.age = age;
    Person.say = function(){
        return "I can say!"
    }
}
Person.say();//I can say!
var student = new Person("xiaoming",11);
student.say();//報(bào)錯(cuò)

靜態(tài)方法是不需要實(shí)例化,可以通過(guò)類名直接調(diào)用,注意的是靜態(tài)方法不會(huì)繼承到類實(shí)例中,因此靜態(tài)方法經(jīng)常用來(lái)作為工具函數(shù)。比如我們經(jīng)常用的Math.random()。

  1. 在ES6 class類定義中,可以使用static關(guān)鍵字定義靜態(tài)方法:
class A{
    constructor(){};
    static say(){
        console.log("I can say!");
    }
}
A.say();//I can say
var a = new A();
a.say()//error

跟之前一樣,通過(guò)類名直接調(diào)用,不會(huì)繼承到類實(shí)例中。
static關(guān)鍵字是ES6的另一個(gè)語(yǔ)法糖,static 使靜態(tài)方法聲明也成為了一個(gè)一等公民。

四、封裝和繼承

  1. ES6之前子類對(duì)象是通過(guò)使用原型來(lái)實(shí)現(xiàn)繼承父類,子類函數(shù)和父類函數(shù)共享原型的形式來(lái)實(shí)現(xiàn):
function Person(name,age){
    this.name = name;
    this.age = age;
}
function father(name,age,firstname,lastname){
    Person.call(this,name,age);//通過(guò)call來(lái)繼承父類的方法來(lái)實(shí)現(xiàn)自己的功能
    this.lastname = lastname;
    this.firstname = firstname;
}
console.log(new father('zhangsan',11,'zhang','san'));
//father {name: "zhangsan", age: 11, lastname: "san", firstname: "zhang"}
function son(name,age,firstname,lastname){
    father.call(this,name,age,firstname,lastname);
};
son.prototype = Object.create(father.prototype);
son.constructor = son;
console.log(new son('zhangsi',5,'zhang','si'));
//son {name: "zhangsi", age: 5, lastname: "si", firstname: "zhang"}
  1. ES6中新的extends關(guān)鍵字解決了這個(gè)麻煩問(wèn)題:
語(yǔ)法:class son extends father{}

下面定義了一個(gè)Child類,該類通過(guò)extends關(guān)鍵字,繼承了Parent類的所有屬性和方法。

class Parent{
    constructor(firstname,lastname){
        this.firstname = firstname;
        this.lastname = lastname;
    }
}
class Child extends Parent{
    constructor (firstname,lastname,name){
        super(firstname,lastname);
        this.name = name;
    }
    say(){
        console.log("I can say!")
    }
}
console.log(new Child("蒙奇","D","路飛"));
//Child {firstname: "蒙奇", lastname: "D", name: "路飛"}
  1. super關(guān)鍵字
    super表示超,超類,父類。既可以當(dāng)作函數(shù),也可以當(dāng)作對(duì)象使用。
    (1)super作為函數(shù)調(diào)用,代表父類的構(gòu)造函數(shù)。
    注意,ES6中規(guī)定,子類的構(gòu)造函數(shù)必須執(zhí)行一次super函數(shù)。格式:
class Parent{}
class Child extends Parent{
    constructor (){
        super();
        // ...
    }
    // ...
}  
class Parent{}
class Child extends Parent{
    constructor (){
        // super();  如果調(diào)用super,程序會(huì)報(bào)錯(cuò)Uncaught ReferenceError: this is not defined
        // ...
    }
    // ...
}
new Child();

注意,super雖然代表父類中的構(gòu)造函數(shù),但是返回的是子類的實(shí)例,即super內(nèi)部的this指的是子類Child,在這種情況下,super()相當(dāng)于Parent.prototype.constructor.call(this)。
(2)super作為對(duì)象,代表父類的原型對(duì)象。

class Parent{
    constructor(firstname,lastname,age){
        this.firstname = firstname;
        this.lastname = lastname;
        this.age = age;
    }
    say(){
        console.log("I can say.");
    }
}
class Child extends Parent{
    constructor (firstname,lastname,age,score){
        super(firstname,lastname,age); //super在這里代表父類的構(gòu)造函數(shù) 
        this.score = score;
        super.say();//super在這里代表父類的原型對(duì)象,可以調(diào)用父類的方法
    }
    
}

console.log(new Child("蒙奇","路飛",18,100));
// I can say.
// {firstname: "蒙奇", lastname: "路飛", age: 18, score: 100}

使用extends關(guān)鍵字實(shí)現(xiàn)繼承,那么子類中可以通過(guò)super關(guān)鍵字調(diào)用父類的東西
(3)4.3 getter(取值)、 setter(存值)
與 ES5 一樣,在“類”的內(nèi)部可以使用get和set,對(duì)某個(gè)屬性設(shè)置存值函數(shù)和取值函數(shù),攔截該屬性的存取行為。

class Parent{
    constructor(){}
    get firstname(){
        return "D.";
    }
    set lastname(value){
        console.log('我的名是:' + value);
    }
}

let p = new Parent();
console.log(p.firstname);//D.
console.log(p.lastname = "路飛")  ;
//我的名是:路飛
//路飛

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容