成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

ES6系列---類

huayeluoliuhen / 2305人閱讀

摘要:原型會(huì)自動(dòng)調(diào)整,通過調(diào)用方法即可訪問基類的構(gòu)造函數(shù)。在簡單情況下,等于類的構(gòu)造函數(shù)的值是輸出這段代碼展示了當(dāng)調(diào)用時(shí)等于。

大多數(shù)面向?qū)ο缶幊陶Z言都支持類和類繼承的特性,而JavaScript只能通過各種特定方式模仿并關(guān)聯(lián)多個(gè)相似的對(duì)象。這個(gè)情況一直持續(xù)到ES5。由于類似的庫層出不窮,最終ES6引入了類特性,統(tǒng)一了類和類繼承的標(biāo)準(zhǔn)。

ES5模仿類

先看一段ES5中模仿類的代碼:

function PersonType(name) {
    this.name = name;
}

PersonType.prototype.sayName = function(){
    console.log(this.name);
};

var person = new PersonType("Nicholas");
person.sayName();

console.log(person instanceof PersonType);   // true
console.log(person instanceof Object);   // true

這段代碼中的PersonType是一個(gè)構(gòu)造函數(shù),執(zhí)行后創(chuàng)建一個(gè)名為name的屬性;給PersonType的原型添加一個(gè)sayName()方法,所以PersonType對(duì)象的所有實(shí)例共享這個(gè)方法。然后使用new操作符創(chuàng)建一個(gè)PersonType的實(shí)例person,并最終證實(shí)了person對(duì)象確實(shí)是PersonType的實(shí)例。

ES6的類

ES6有一種與其他語言中類似的類特性:類聲明。

類聲明語法
class PersonType {
    // 等價(jià)于PersonType構(gòu)造函數(shù)
    constructor(name) {
        this.name = name;
    }
    
    // 等價(jià)于PersonType.prototype.sayName
    sayName() {
        console.log(this.name);
    }
}

let person = new PersonType("Nicholas");
person.sayName();

console.log(person instanceof PersonType);   // true
console.log(person instanceof Object);   // true

console.log(typeof PersonType);   // "function"
console.log(typeof PersonType.prototype.sayName);   // "function"

通過類聲明語法定義PersonType的行為與之前創(chuàng)建PersonType構(gòu)造函數(shù)的過程相似,只是這里直接通過特殊的constructor方法名來定義構(gòu)造函數(shù)。

訪問器屬性

盡管應(yīng)該在類構(gòu)造函數(shù)中創(chuàng)建自己的屬性,但是類也支持直接在原型上定義訪問器屬性。創(chuàng)建getter時(shí),需要在關(guān)鍵字get后緊跟一個(gè)空格和相應(yīng)的標(biāo)識(shí)符;創(chuàng)建setter時(shí),只需把關(guān)鍵字get替換為set即可:

class CustomHTMLElement {
    constructor(element) {
        this.element = element;
    }
    
    get html() {
        return this.element.innerHTML;
    }
    
    set html(value) {
        this.element.innerHTML = value;
    }
}

var descriptor = Object.getOwnPropertyDescriptor(CustomHTMLElement.prototype, "html");
console.log("get" in descriptor);   // true
console.log("set" in descriptor);   // true
console.log(descriptor.enumerable);   // false

這段代碼中的CustomHTMLElement類是一個(gè)針對(duì)現(xiàn)有DOM元素的包裝器,并通過getter和setter方法將這個(gè)元素的innerHTML方法委托給html屬性,這個(gè)訪問器屬性是在CustomHTMLElement.prototype上創(chuàng)建的。

可計(jì)算成員名稱

類和對(duì)象字面量還有更多相似之處,類方法和訪問器屬性也支持使用可計(jì)算名稱:

let methodName = "sayName";

class PersonType {
    constructor(name) {
        this.name = name;
    }
    
    [methodName]() {
        console.log(this.name);
    }
}

let me = new PersonType("Nicholas");
me.sayName();

通過相同的方式可以在訪問器屬性中應(yīng)用可計(jì)算名稱:

let propertyName = "html";

class CustomHTMLElement {
    constructor(element) {
        this.element = element;
    }
    
    get [propertyName]() {
        return this.element.innerHTML;
    }
    
    set [propertyName](value) {
        this.element.innerHTML = value;
    }
}
生成器方法

關(guān)于生成器和迭代器的知識(shí)點(diǎn),可以參考ES6系列---生成器和迭代器。

在對(duì)象字面量中,可以通過在方法名前附加一個(gè)星號(hào)(*)的方式來定義生成器,在類中亦是如此:

class MyClass {
    *createIterator() {
        yield 1;
        yield 2;
        yield 3;
    }
}

let instance = new MyClass();
let iterator = instance.createIterator();

如果用對(duì)象來表示集合,又希望通過簡單的方法迭代集合中的值,那么生成器方法就派上用場了。數(shù)組、Set集合及Map集合為開發(fā)者們提供了多個(gè)生成器方法來與集合中的元素交互。
盡管生成器方法很實(shí)用,但如果你的類是用來表示值的集合的,那么定義一個(gè)默認(rèn)迭代器會(huì)更有用。通過Symbol.iterator定義生成器方法即可為類定義默認(rèn)迭代器:

class Collection {
    constructor() {
        this.items = [];
    }
    
    *[Symbol.iterator]() {
        yield *this.items.values();
    }
}

var collection = new Collection();
collection.items.push(1);
collection.items.push(2);
collection.items.push(3);

for (let x of collection) {
    console.log(x);
}

// 輸出:
// 1
// 2
// 3
靜態(tài)成員

在ES5及其早期版本中,直接將方法添加到構(gòu)造函數(shù)中類模擬靜態(tài)成員是一種常見模式:

function PersonType(name) {
    this.name = name;
}

// 靜態(tài)方法
PersonType.create = function(name) {
    return new PersonType(name);
};

// 實(shí)例方法
PersonType.prototype.sayName = function() {
    console.log(this.name);
};

var person = PersonType.create("Nicholas");

ES6簡化了創(chuàng)建靜態(tài)成員的過程,在方法或訪問器屬性名前使用正式的靜態(tài)注釋即可:

class PersonType {
    // 等價(jià)于PersonType構(gòu)造函數(shù)
    constructor(name) {
        this.name = name;
    }
    
    // 等價(jià)于PersonType.prototype.sayName
    sayName() {
        console.log(this.name);
    }
    
    // 等價(jià)于PersonType.create
    static create(name) {
        return new PersonType(name);
    }
}

let person = PersonType.create("Nicholas");

靜態(tài)成員或方法,不可在實(shí)例中訪問,必須要直接在類上訪問。

繼承與派生類

在ES6之前,實(shí)現(xiàn)繼承與自定義類型是個(gè)不小的工作:

ES5中實(shí)現(xiàn)繼承
function Rectangle(length, width) {
    this.length = length;
    this.width = width;
}

Rectangle.prototype.getArea = function() {
    return this.length * this.width;
};

function Square(length) {
    Rectangle.call(this, length, length);
}

Square.prototype = Object.create(Rectangle.prototype, {
    constructor: {
        value: Square,
        enumerable: true,
        writable: true,
        configurable: true
    }
});

var square = new Square(3);

console.log(square.getArea());   // 9
console.log(square instanceof Square);  // true
console.log(square instanceof Rectangle);  // true

Square繼承自Rectangle,為了這樣做,必須用一個(gè)創(chuàng)建自Rectangle.prototype的新對(duì)象重寫Square.prototype并調(diào)用Rectangle.call()方法。

ES6中實(shí)現(xiàn)繼承

類的出現(xiàn)讓我們可以輕松地實(shí)現(xiàn)繼承功能,使用熟悉的extends關(guān)鍵字。原型會(huì)自動(dòng)調(diào)整,通過調(diào)用super()方法即可訪問基類的構(gòu)造函數(shù)。下面是之前示例的ES6等價(jià)版:

class Rectangle {
    constructor(length, width) {
        this.length = length;
        this.width = width;
    }
    
    getArea() {
        return this.length * this.width;
    }
}

class Square extends Rectangle {
    constructor(length) {
        // 等價(jià)于Rectangle.call(this, length, length)
        super(length, length);
    }
}

var square = new Square(3);

console.log(square.getArea());   // 9
console.log(square instanceof Square);  // true

這一次,Square類通過extends關(guān)鍵字繼承Rectangle類,在Square構(gòu)造函數(shù)中通過super()調(diào)用Rectangle構(gòu)造函數(shù)并傳入相應(yīng)參數(shù)。

類方法重寫

派生類中的方法總會(huì)覆蓋基類中的同名方法:

class Square extends Rectangle {
    constructor(length) {
        super(length, length);
    }
    
    // 重寫Rectangle.prototype.getArea()方法
    getArea() {
        return this.length * this.length;
    }
}

由于為Square定義了getArea()方法,便不能在Square實(shí)例中調(diào)用Rectangle.prototype.getArea()方法。當(dāng)然,如果你想調(diào)用基類中的方法,則可以調(diào)用super.getArea()方法,就像這樣:

class Square extends Rectangle {
    constructor(length) {
        super(length, length);
    }
    
    // 重寫后調(diào)用Rectangle.prototype.getArea()
    getArea() {
        return super.getArea();
    }
}
靜態(tài)成員繼承

如果基類有靜態(tài)成員,那么這些靜態(tài)成員在派生類中也可用:

class Rectangle {
    constructor(length, width) {
        this.length = length;
        this.width = width;
    }
    
    getArea() {
        return this.length * this.width;
    }
    
    static create(length, width) {
        return new Rectangle(length, width);
    }
}

class Square extends Rectangle {
    constructor(length) {
        // 等價(jià)于Rectangle.call(this, length, length)
        super(length, length);
    }
}

var rect = Square.create(3, 4);

console.log(rect instanceof Rectangle);   // true
console.log(rect.getArea());   // 12
console.log(rect instanceof Square);   // false

在這段代碼中,新的靜態(tài)方法create()被添加到Rectangle類中,繼承后的Square.create()與Rectangle.create()行為一致。

派生自表達(dá)式的類

ES6最強(qiáng)大的一面或許是從表達(dá)式導(dǎo)出類的功能了。只要表達(dá)式可以被解析為一個(gè)函數(shù)并且具有[[Construct]]屬性和原型,那么就可以用extends進(jìn)行派生:

function Rectangle(length, width) {
    this.length = length;
    this.width = width;
}

Rectangle.prototype.getArea = function() {
    return this.length * this.width;
};

class Square extends Rectangle {
    constructor(length) {
        super(length, length);
    }
}

var x = new Square(3);
console.log(x.getArea());   // 9
console.log(x instanceof Rectangle);   // true

Rectangle是一個(gè)ES5風(fēng)格的構(gòu)造函數(shù),Square是一個(gè)類,由于Rectangle具有[[Construct]]屬性和原型,因此Square類可以直接繼承它。
extends強(qiáng)大的功能使得類可以繼承自任意類型的表達(dá)式,從而創(chuàng)造更多可能性,例如動(dòng)態(tài)地確定類的繼承目標(biāo):

function Rectangle(length, width) {
    this.length = length;
    this.width = width;
}

Rectangle.prototype.getArea = function() {
    return this.length * this.width;
};

function getBase() {
    return Rectangle;
}

class Squre extends getBase() {
    constructor(length) {
        super(length, length);
    }
}

var x = new Square(3);
console.log(x.getArea());   // 9
console.log(x instanceof Rectangle);   // true

getBase()函數(shù)是類聲明的一部分,直接調(diào)用后返回Rectangle,此示例實(shí)現(xiàn)的功能與之前的示例等價(jià)。由于可以動(dòng)態(tài)確定使用哪個(gè)基類,因而可以創(chuàng)建不同的繼承方法。例如,可以這樣創(chuàng)建mixin:

let SerializableMixin = {
    serialize() {
        return JSON.stringify(this);
    }
};

let AreaMixin = {
    getArea() {
        return this.length * this.width;
    }
};

function mixin(...mixins) {
    var base = function() {};
    Object.assign(base.prototype, ...mixins);
    return base;
}

class Square extends mixin(AreaMixin, SerializableMixin) {
    constructor(length) {
        super();
        this.length = length;
        this.width = length;
    }
}

var x = new Square(3);
console.log(x.getArea());   // 9
console.log(x.serialize());   // "{"length":3, "width":3}"

這個(gè)示例使用了mixin函數(shù)代替?zhèn)鹘y(tǒng)的繼承方法,它可以接受任意數(shù)量的mixin對(duì)象作為參數(shù)。首先創(chuàng)建一個(gè)函數(shù)base,再將每一個(gè)mixin對(duì)象的屬性值賦值給base的原型,最后mixin函數(shù)返回這個(gè)base函數(shù),所以Square類就可以基于這個(gè)返回的函數(shù)用extends進(jìn)行擴(kuò)展。
Square的實(shí)例擁有來自AreaMixin對(duì)象的getArea()方法和來自SerializableMixin對(duì)象的serialize方法,這都是通過原型繼承實(shí)現(xiàn)的,mixin()函數(shù)會(huì)用所有mixin對(duì)象的自有屬性動(dòng)態(tài)填充新函數(shù)的原型。

類的構(gòu)造函數(shù)中使用new.target

在類的構(gòu)造函數(shù)中也可以通過new.target來確定類是如何被調(diào)用。在簡單情況下,new.target等于類的構(gòu)造函數(shù):

class Rectangle {
    constructor(length, width) {
        console.log(new.target === Rectangle);
        this.length = length;
        this.width = width;
    }
}

// new.target的值是Rectangle
var obj = new Rectangle(3, 4);   // 輸出true

這段代碼展示了當(dāng)調(diào)用new Rectangle(3, 4)時(shí)new.target等于Rectangle。
繼承情況下,有所不同:

class Rectangle {
    constructor(length, width) {
        console.log(new.target === Rectangle);
        this.length = length;
        this.width = width;
    }
}

class Square extends Rectangle {
    constructor(length) {
        super(length, length);
    }
}

// new.target的值是Square
var obj = new Square(3);   // 輸出false

Square調(diào)用Rectangle的構(gòu)造函數(shù),所以當(dāng)調(diào)用發(fā)生時(shí)new.target等于Square。據(jù)此,我們可以創(chuàng)建一個(gè)抽象基類(不能被實(shí)例化的類),就像這樣:

// 抽象基類
class Shape {
    constructor() {
        if (new.target === Shape) {
            throw new Error("這個(gè)類不能被直接實(shí)例化。");
        }
    }
}

class Rectangle extends Shape {
    constructor(length, width) {
        super();
        this.length = length;
        this.width = width;
    }
}

var x = new Shape();   // 拋出錯(cuò)誤

var y = new Rectangle(3, 4);   // 沒有錯(cuò)誤
console.log(y instanceof Shape);   // true

在這個(gè)示例中,每當(dāng)new.target是Shape時(shí)構(gòu)造函數(shù)總會(huì)拋出錯(cuò)誤,這相當(dāng)于調(diào)用new Shape()時(shí)總會(huì)出錯(cuò)。但是,仍可用Shape作為基類派生其他類。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/91873.html

相關(guān)文章

  • ES6 系列之 Babel 是如何編譯 Class 的(上)

    摘要:前言在了解是如何編譯前,我們先看看的和的構(gòu)造函數(shù)是如何對(duì)應(yīng)的。這是它跟普通構(gòu)造函數(shù)的一個(gè)主要區(qū)別,后者不用也可以執(zhí)行。該函數(shù)的作用就是將函數(shù)數(shù)組中的方法添加到構(gòu)造函數(shù)或者構(gòu)造函數(shù)的原型中,最后返回這個(gè)構(gòu)造函數(shù)。 前言 在了解 Babel 是如何編譯 class 前,我們先看看 ES6 的 class 和 ES5 的構(gòu)造函數(shù)是如何對(duì)應(yīng)的。畢竟,ES6 的 class 可以看作一個(gè)語法糖,...

    shadajin 評(píng)論0 收藏0
  • [js高手之路] es6系列教程 - 新的語法實(shí)戰(zhàn)選項(xiàng)卡

    摘要:其實(shí)的面向?qū)ο蠛芏嘣砗蜋C(jī)制還是的,只不過把語法改成類似和老牌后端語言中的面向?qū)ο笳Z法一用封裝一個(gè)基本的類是不是很向和中的類其實(shí)本質(zhì)還是原型鏈,我們往下看就知道了首先說下語法規(guī)則中的就是類名,可以自定義就是構(gòu)造函數(shù),這個(gè)是關(guān)鍵字,當(dāng)實(shí)例化對(duì) 其實(shí)es6的面向?qū)ο蠛芏嘣砗蜋C(jī)制還是ES5的,只不過把語法改成類似php和java老牌后端語言中的面向?qū)ο笳Z法. 一、用es6封裝一個(gè)基本的類 ...

    yintaolaowanzi 評(píng)論0 收藏0
  • 揭秘babel的魔法之class繼承的處理2

    摘要:并且用驗(yàn)證了中一系列的實(shí)質(zhì)就是魔法糖的本質(zhì)。抽絲剝繭我們首先看的編譯結(jié)果這是一個(gè)自執(zhí)行函數(shù),它接受一個(gè)參數(shù)就是他要繼承的父類,返回一個(gè)構(gòu)造函數(shù)。 如果你已經(jīng)看過第一篇揭秘babel的魔法之class魔法處理,這篇將會(huì)是一個(gè)延伸;如果你還沒看過,并且也不想現(xiàn)在就去讀一下,單獨(dú)看這篇也沒有關(guān)系,并不存在理解上的障礙。 上一篇針對(duì)Babel對(duì)ES6里面基礎(chǔ)class的編譯進(jìn)行了分析。這一篇將...

    BlackHole1 評(píng)論0 收藏0
  • ES6 系列之私有變量的實(shí)現(xiàn)

    摘要:前言在閱讀入門的時(shí)候,零散的看到有私有變量的實(shí)現(xiàn),所以在此總結(jié)一篇。構(gòu)造函數(shù)應(yīng)該只做對(duì)象初始化的事情,現(xiàn)在為了實(shí)現(xiàn)私有變量,必須包含部分方法的實(shí)現(xiàn),代碼組織上略不清晰。 前言 在閱讀 《ECMAScript 6 入門》的時(shí)候,零散的看到有私有變量的實(shí)現(xiàn),所以在此總結(jié)一篇。 1. 約定 實(shí)現(xiàn) class Example { constructor() { this...

    lentoo 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<