1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        ES6 之 Class 的基本語(yǔ)法和繼承

        共 6455字,需瀏覽 13分鐘

         ·

        2020-12-31 19:48

        來(lái)源 |?https://segmentfault.com/a/1190000020652616

        Class 類(lèi)基本用法

        Class 類(lèi)完全可以看作構(gòu)造函數(shù)的另一種寫(xiě)法,類(lèi)的數(shù)據(jù)類(lèi)型其實(shí)就是函數(shù),類(lèi)本身也就是其實(shí)例的構(gòu)造函數(shù)。使用的時(shí)候也是使用 new 命令。
        class Person { constructor(name,age) { this.name = name; this.age = age; }
        getName(){ console.log(`My name is ${this.name}!`) }
        static sayHi() { console.log('Hi'); }}
        let p = new Person();
        typeof Person // "function"p instanceof Person // true

        constructor 方法

        constructor 方法就是類(lèi)的構(gòu)造方法,this 關(guān)鍵字代表實(shí)例對(duì)象。其對(duì)應(yīng)的也就是 ES5 的構(gòu)造函數(shù) Person。
        constructor 方法是類(lèi)的默認(rèn)方法,通過(guò) new 命令生成對(duì)象實(shí)例時(shí),會(huì)自動(dòng)調(diào)用該方法。一個(gè)類(lèi)必須有 constructor 方法,如果沒(méi)有顯式定義,會(huì)默認(rèn)添加一個(gè)空的 constructor 方法。
        class Person {}
        Person.prototype // {construtor:f}
        constructor 方法默認(rèn)返回實(shí)例對(duì)象,也完全可以 return 另外一個(gè)對(duì)象。
        class Foo { constructor(){ return Object.create(null); } }
        new Foo() instanceof Foo // false
        類(lèi)必須使用 new 調(diào)用,也就是 constructor 方法只能通過(guò) new 命令執(zhí)行,否則會(huì)報(bào)錯(cuò)。
        class Foo { constructor(){} }
        Foo() // TypeError: Class constructor Foo cannot be invoked without 'new'

        Class 的自定義方法

        Class 類(lèi)依舊存在 prototype 屬性,且類(lèi)的所有方法都定義在 prototype 屬性上面。
        class Person { constructor() {} aaa(){} bbb(){}}
        Object.getOwnPropertyNames(Person.prototype) // ["constructor", "aaa", "bbb"]
        prototype 對(duì)象的 constructor 屬性,也是直接指向類(lèi)本身。
        Person.prototype.constructor === Person // truep.constructor === Person // true
        類(lèi)的新方法可通過(guò)?Object.assign?向?prototype?一次性添加多個(gè)。
        class Person { constructor() {}}
        Object.assign(Person.prototype, { aaa(){}, bbb(){}})
        注意,定義類(lèi)的時(shí)候,前面不需要加上?function?關(guān)鍵字,也不需要逗號(hào)分隔。
        與 ES5 構(gòu)造函數(shù)的不同的是,Class?內(nèi)部所有定義的方法,都是不可枚舉的。
        class Person { constructor() {} aaa(){}}
        Object.keys(Person.prototype) // []Object.getOwnPropertyNames(Person.prototype) // ["constructor", "aaa"]
        而 ES5 的構(gòu)造函數(shù)的?prototype?原型定義的方法是可枚舉的。
        let Person = function(){};Person.prototype.aaa = function(){};
        Object.keys(Person.prototype) // ["aaa"]Object.getOwnPropertyNames(Person.prototype) // ["constructor", "aaa"]
        Class 類(lèi)的屬性名,可以采用表達(dá)式。
        let methodName = 'getName';
        class Person { constructor() {} [methodName](){}}
        Object.getOwnPropertyNames(Person.prototype) // ["constructor", "getName"]

        取值函數(shù) getter 和存值函數(shù) setter

        與 ES5 一樣,在 Class 內(nèi)部可以使用 get 和 set 關(guān)鍵字,對(duì)某個(gè)屬性設(shè)置存值函數(shù)和取值函數(shù),攔截該屬性的存取行為。
        class Person { constructor() { this.name = 'dora'; } get author() { return this.name; } set author(value) { this.name = this.name + value; console.log(this.name); }}
        let p = new Person();p.author // dorap.author = 666; // dora666
        且其中 author 屬性定義在 Person.prototype 上,但 get 和 set 函數(shù)是設(shè)置在 author 屬性描述對(duì)象 Descriptor 上的。
        Object.getOwnPropertyNames(Person.prototype) // ["constructor", "author"]
        Object.getOwnPropertyDescriptor(Person.prototype,'author')// { get: ? author()(),// set: ? author()(value),// ...// }

        Class 的 static 靜態(tài)方法

        類(lèi)相當(dāng)于實(shí)例的原型,所有在類(lèi)中定義的方法,都會(huì)被實(shí)例繼承。但如果在一個(gè)方法前,加上 static 關(guān)鍵字,就表示該方法不會(huì)被實(shí)例繼承,而是直接通過(guò)類(lèi)來(lái)調(diào)用,這就稱(chēng)為“靜態(tài)方法”。
        class Person { static sayHi() { console.log('Hi'); }}
        Person.sayHi() // "Hi"
        let p = new Person();p.sayHi() // TypeError: p.sayHi is not a function
        如果靜態(tài)方法包含?this?關(guān)鍵字,這個(gè)?this?指的是類(lèi),而不是實(shí)例。靜態(tài)方法可以與非靜態(tài)方法重名。
        class Person { static sayHi() { this.hi(); }
        static hi(){ console.log('hello') }
        hi(){ console.log('world') }}
        Person.sayHi() // "hello"

        實(shí)例屬性的另一種寫(xiě)法

        實(shí)例屬性除了定義在 constructor()?方法里面的 this 上面,也可以定義在類(lèi)的最頂層。此時(shí)定義的時(shí)候,屬性前面不需要加上 this。而在類(lèi)內(nèi)部其它地方調(diào)用的時(shí)候,需要加上 this。
        class Person { name = 'dora'; getName() { return this.name; }}
        let p = new Person();p.name // "dora"Object.keys(p) // ["name"]
        這種寫(xiě)法的好處是,所有實(shí)例對(duì)象自身的屬性都定義在類(lèi)的頭部,看上去比較整齊,寫(xiě)法簡(jiǎn)潔,一眼就能看出這個(gè)類(lèi)有哪些實(shí)例屬性。

        Class 的繼承

        Class 子類(lèi)可以通過(guò) extends 關(guān)鍵字實(shí)現(xiàn)繼承。
        class Person { constructor() {} sayHi() { return 'Hi'; }}
        class Teacher extends Person { constructor() { super(); }}
        let t = new Teacher();t.sayHi(); // "Hi"

        子類(lèi)的 constructor

        子類(lèi)必須在 constructor 方法中調(diào)用 super()?方法,否則新建實(shí)例時(shí)會(huì)報(bào)錯(cuò)。
        如果子類(lèi)沒(méi)有定義 constructor 方法,這個(gè)方法會(huì)被默認(rèn)添加,且子類(lèi)默認(rèn)添加的 constructor 方法都會(huì)默認(rèn)執(zhí)行 super()?方法。
        class Teacher extends Person {}
        let t = new Teacher();t.sayHi(); // "Hi"
        等同于
        class Teacher extends Person { constructor(...args) { super(...args); }}

        super 關(guān)鍵字

        super 這個(gè)關(guān)鍵字,既可以當(dāng)作函數(shù)使用,也可以當(dāng)作對(duì)象使用。用法完全不同。

        super() 方法

        super 作為函數(shù)調(diào)用時(shí),代表父類(lèi)的構(gòu)造函數(shù)。子類(lèi)的構(gòu)造函數(shù)必須執(zhí)行一次 super()?方法。
        因?yàn)?ES6 的繼承機(jī)制與 ES5 構(gòu)造函數(shù)不同,ES6 的子類(lèi)實(shí)例對(duì)象 this 必須先通過(guò)父類(lèi)的構(gòu)造函數(shù)創(chuàng)建,得到與父類(lèi)同樣的實(shí)例屬性和方法后再添加子類(lèi)自己的實(shí)例屬性和方法。因此如果不調(diào)用 super()?方法,子類(lèi)就得不到 this 對(duì)象。
        super 雖然代表了父類(lèi)的構(gòu)造函數(shù),但返回的是子類(lèi)的實(shí)例,即通過(guò)super 執(zhí)行父類(lèi)構(gòu)造函數(shù)時(shí),this 指的都是子類(lèi)的實(shí)例。也就是 super()?相當(dāng)于 Person.call(this)。
        class A { constructor() { console.log(this.constructor.name) }}
        class B extends A { constructor() { super(); }}
        new A() // Anew B() // B
        作為函數(shù)時(shí),super()?只能在子類(lèi)的構(gòu)造函數(shù)之中,用在其他地方就會(huì)報(bào)錯(cuò)。

        super 對(duì)象

        在普通方法中指向父類(lèi)的?prototype?原型
        super 作為對(duì)象時(shí),在普通方法中,指向父類(lèi)的 prototype 原型,因此不在原型 prototype 上的屬性和方法不可以通過(guò) super 調(diào)用。
        class A { constructor() { this.a = 3; } p() {return 2;}}A.prototype.m = 6;
        class B extends A { constructor() { super(); console.log(super.a); // undefined console.log(super.p()); // 2 console.log(super.m); // 6 }}
        new B();
        在子類(lèi)普通方法中通過(guò)?super?調(diào)用父類(lèi)方法時(shí),方法內(nèi)部的?this?指向當(dāng)前的子類(lèi)實(shí)例。
        class A { constructor() { this.x = 'a'; } aX() { console.log(this.x); }}
        class B extends A { constructor() { super(); this.x = 'b'; } bX() { super.aX(); }}
        (new B()).bX() // 'b'
        在靜態(tài)方法中,指向父類(lèi)
        class A { static m(msg) { console.log('static', msg); } m(msg) { console.log('instance', msg); }}
        class B extends A { static m(msg) { super.m(msg); } m(msg) { super.m(msg); }}
        B.m(1); // "static" 1(new B()).m(2) // "instance" 2
        在子類(lèi)靜態(tài)方法中通過(guò) super 調(diào)用父類(lèi)方法時(shí),方法內(nèi)部的 this 指向當(dāng)前的子類(lèi),而不是子類(lèi)的實(shí)例。

        任意對(duì)象的 super

        由于對(duì)象總是繼承其它對(duì)象的,所以可以在任意一個(gè)對(duì)象中,使用 super 關(guān)鍵字,指向的是該對(duì)象的構(gòu)造函數(shù)的 prototype 原型。
        let obj = { m() { return super.constructor.name; }};obj.m(); // Object
        注意,使用 super 的時(shí)候,必須顯式的指定是作為函數(shù)還是作為對(duì)象使用,否則會(huì)報(bào)錯(cuò)。
        class B extends A { m() { console.log(super); }}// SyntaxError: 'super' keyword unexpected here

        靜態(tài)方法的繼承

        父類(lèi)的靜態(tài)方法,可以被子類(lèi)繼承。
        class Person { static sayHi() { return 'hello'; }}
        class Teacher extends Person {}
        Teacher.sayHi() // "hello"
        在子類(lèi)的 static 內(nèi)部,可以從 super 對(duì)象上調(diào)用父類(lèi)的靜態(tài)方法。
        class Teacher extends Person { static sayHi() { super.sayHi(); }}
        Teacher.sayHi() // "hello"

        new.target 屬性

        Class 內(nèi)部調(diào)用 new.target,返回當(dāng)前 Class。且子類(lèi)繼承父類(lèi)時(shí),new.target 會(huì)返回子類(lèi)。因此利用這個(gè)特點(diǎn),可以寫(xiě)出不能獨(dú)立使用必須繼承后才能使用的類(lèi)。
        class Shape { constructor() { if(new.target === Shape) { throw new Error('本類(lèi)不能實(shí)例化'); } }}
        class Circle extends Shape { constructor(radius) { super(); console.log('ok'); }}let s = new Shape(); // 報(bào)錯(cuò)let?cir?=?new?Circle(6);??//?'ok'

        本文完?

        瀏覽 26
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        評(píng)論
        圖片
        表情
        推薦
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            国产精品91一区 | 特级西西444WWw高清大胆 | 亚洲AV色情成人www | 极品美女高潮出白浆 | 综合激情五月丁香婷婷 | 人人草人人看 | 国产极品无码 | 草草黑森林av导航 | 午夜福利免费在线观看 | 亚洲精品无码视频 |