1. 程式人生 > >ES6-18:class類及其繼承

ES6-18:class類及其繼承

數據 truct 否則 on() 自動 自己 ren ext clas

JavaScript作為一個動態語言,很大程度上的詬病就是缺少了面向對象的這個概念,ES5傳統的方法是通過構造函數來實現類的特性;ES6引入了類這一概念,將Class這個概念作為對象的模板,通過關鍵字class可以定義類;本質上ES6中引入的類是一個語法糖,其大部分功能ES5均可實現;

JavaScript語言可以實現繼承的特征,但ES5與ES6在實現的機制上確迥然不同:

  • ES5繼承的實質:先創造子類的實例對象this,然後將父類的方法添加到this上面,及Parent.apply(this);
  • ES6繼承的實質:先創造父類的實例對象this,然後再用子類的構造函數修改 this,因此ES6子類繼承必須先調用super
    方法;

1.類與對象的區別

1. 先來看一下對象和類的定義
②對象,是一個具體的個體,擁有對象名、屬性、方法三個特征;每個對象擁有自己獨立的屬性,依靠屬性來區分不同的對象,方法是對象的動態屬性,也成為方法/服務;每個方法用來確定對象的一種行為或功能;   
①類,是抽象的概念集合,擁有類標識、屬性、方法三個特征,是一類具有相同特性的個體的抽象和歸納;類是抽象出能反映與當前目標有關的本質特征,忽略那些與當前目標無關的非本質特征,從而找出事物的共性,把具有共同性質的事物歸結為一類,進而抽象出的概念;

類的變量:一個類所包含的變量根據其可訪問性的差別分為:①局部變量:定義在方法、構造方法、語句塊中的變量,方法結束後變量就自動銷毀;②成員變量

:定義在類中,方法體之外的變量,可被類中的方法、構造方法、語句塊訪問;③成員變量:定義在類中,方法體之外,且用static修飾的變量;

類的修飾符:類的變量修飾符有4種:publicprivateprotectedfriendly;類的方法有7種修飾符:publicprivateprotectedstaticabstractfinalsynchronized;其區別如下:

  • public:在類中任意地方可見、對子類可見、對繼承對象可見;
  • private:在類中任意地方可見、在類外不可見;
  • protected:在類中任意地方可見、在類外不可見,不可被外部修改

類和對象都是面向對象程序設計的基本組成單元,但兩者又有所不同,簡單來說:
兩者之間的主要區別如下:

  • 類是對象的模板,對象是類的實例;
  • 類不能直接使用,只有通過對象才可使用,而對象可以直接使用;
  • 類需要在對象之前創建,對象可以繼承類;
  • 類和對象都具有一系列屬性(靜態屬性)、方法(動態屬性/服務/操作);

2. ES6 類的特性

  • 類的數據類型就是函數,類本身指向構造函數;
  • 類具有構造方法constructor(),類內部this指向實例對象;
  • 類的所有方法都定義在類的prototype屬性上,類方法的調用其調用實質上就是調用原型上的方法;
  • 類內部定義的所有方法都是不可枚舉的;而ES5原型上的所有方法都是可以枚舉的;
  • 類的屬性名可以采用表達式;
  • 類和模塊內部默認使用嚴格模式;
  • 類的方法之間不需要逗號分隔,加了會報錯;
  • 類必須用new來調用,否則會報錯;
  • 類的實例化對象必須使用new,否則會報錯;
  • 類中變量的定義不存在變量提升,這一點是為了保證子類繼承必須在父類之後定義
// 案例1:類的創建
class Person{};      // 類聲名方式
class Cat=class cat{};// 表達式方式

// 案例2
class Person1{
    constructor(name,age){
        this.name=name;
        this.age=age;
    }
    sayHi(){
        console.log(‘My name is‘+this.name+‘; and I‘m ‘+this.age);
    }
}
Person1===Person1.prototype.constructor;//true
// 以上寫法和下面寫法本質上一樣
class Person2{
    constructor(name,age){
        this.name=name;
        this.age=age;
    }
};
Person2.prototype.sayHi=function(){
    console.log(‘My name is‘+this.name+‘; and I‘m ‘+this.age);
}
// 或
class Person2{
    constructor(name,age){
        this.name=name;
        this.age=age;
    }
};
Person2.prototype={
    sayHi(){
        console.log(‘My name is‘+this.name+‘; and I‘m ‘+this.age);
    }
}

3. ES6類的私有屬性、私有方法

ES6並沒有提供類的私有屬性、私有方法特性,所以私有屬性、私有方法都需要通過其他方法模擬實現;

  • 私有屬性實現:私有屬性提案屬性前加#

    class Piont{
    #x
    cnstructor(x=0){
        #x=x*2;
    }
    }
  • 私有方法實現:利用Symbol+表達式方法名;

    const foo=Symbol(‘foo‘);
    export default class Cat{
    bar(){console.log(‘這是一個公有方法‘)}
    [foo](){console.log(‘這是一個私有方法)}
    }

4. ES6類中靜態屬性、靜態方法

類是實例的原型,所有類中的方法和屬性都會被實例繼承,而靜態屬性、靜態方法不會被實例繼承,可以被子類繼承,並且通過直接調用;類中的靜態屬性、靜態方法在類中都采用static關鍵字;此外靜態屬性和靜態方法還可以在類外部定義

// 示例1 關鍵字stativc定義靜態屬性、靜態方法
class Foo{
    name=1;
    static age=2;
    sayMethod(){console.log(‘這是一個公有方法‘)}
    static say(){console.log(‘這是一個私有方法‘)}  
}
let foo=new Foo();
class Bar extends Foo{};


consle.log(foo.name);//1
consle.log(foo.age);// Type Error foo.age is undefined
Foo.say(); // 這是一個私有方法
bar.say();  // 這是一個私有方法
foo.sayMethod(); // 這是一個公有方法
foo.say();   // TyoeError: foo.say is not a function

5. Class.name 、new.target屬性

  • name屬性:返回一個類的標識;
  • target屬性:返回new命令所用的構造函數,而子類繼承父類,是new.target返回子類;該屬性可用於確定構造函數是如何調用的;

    // name屬性
    class Foo{};
    console.og(foo.name);//Foo
    // target屬性
    class Person{
    constructor(age,name){
        this.age=age;
        this.width=name;
        console.log(new.target===Person);
    }
    }
    var obj=new Person(13,‘John‘);// true
    var obj0=Person.call(obj,(24,‘Lilly‘));//false
    class Person1 extends Person{
    constructor(age,name){
        super(age,name);
    }
    }
    let obj1=new Person1(23,‘Jim‘);// false

6. ES6類的繼承

參考:

  • JAVA中類與對象的概念
  • java類的結構(屬性、方法、構造函數)

ES6-18:class類及其繼承