深切明白ES6笔记(九)JS的类(class)

主要知识点:类声明、类表达式、类的主要要点以及类继续

《深切明白ES6笔记(九)JS的类(class)》

《深切明白ES6》笔记 目次

ES5 中的仿类组织

JS 在 ES5 及更早版本中都不存在类。与类最接近的是:建立一个组织器,然后将要领指派到该组织器的原型上。这类体式格局一般被称为建立一个自定义类型:

function PersonType(name) {
    this.name = name;
}
PersonType.prototype.sayName = function() {
    console.log(this.name);
};
let person = new PersonType("Nicholas");
person.sayName(); // 输出 "Nicholas"
console.log(person instanceof PersonType); // true
console.log(person instanceof Object); // true

类的声明

基础的类声明

类声明以 class 关键字最先,厥后是类的称号;盈余部份的语法看起来就像对象字面量中的要领简写,而且在要领之间不需要运用逗号:

class PersonClass {
    // 等价于 PersonType 组织器,自有属性
    constructor(name) {
        this.name = name;
    }
    // 等价于 PersonType.prototype.sayName
    sayName() {
        console.log(this.name);
    }
}
let person = new PersonClass("Nicholas");
person.sayName(); // 输出 "Nicholas"
console.log(person instanceof PersonClass); // true
console.log(person instanceof Object); // true
console.log(typeof PersonClass); // "function"
console.log(typeof PersonClass.prototype.sayName); // "function"

类声明和函数声明的区分和特征

  1. 类声明不会被提拔,这与函数定义差别。类声明的行动与 let 类似,因而在顺序的实行抵达声明处之前,类会存在于暂时性死区内。
  2. 类声明中的一切代码会自动运行在严厉情势下,而且也没法退出严厉情势。
  3. 类的一切要领都是不可枚举的,这是关于自定义类型的明显变化,后者必须用Object.defineProperty() 才能将要领改变成不可枚举。
  4. 类的一切要领内部都没有 [[Construct]] ,因而运用 new 来挪用它们会抛出毛病。
  5. 挪用类组织器时不运用 new ,会抛出毛病。
  6. 试图在类的要领内部重写类名,会抛出毛病。

用ES5完成适才的类的功用:

// 直接等价于 PersonClass
let PersonType2 = (function() {
    "use strict";
    //确保在类的内部不能够重写类名
    const PersonType2 = function(name) {
    // 确认函数被挪用时运用了 new
        if (typeof new.target === "undefined") {
            throw new Error("Constructor must be called with new.");
        }
        this.name = name;
    }
    Object.defineProperty(PersonType2.prototype, "sayName", {
     value: function() {
        // 确认函数被挪用时没有运用 new
        if (typeof new.target !== "undefined") {
            throw new Error("Method cannot be called with new.");
        }
        console.log(this.name);
    },
    //定义为不可枚举
    enumerable: false,
    writable: true,
    configurable: true
    });
    return PersonType2;
}());

此例说清楚明了只管不运用新语法也能完成类的任何特征,但类语法明显简化了一切功用的代码。

类表达式

类与函数有类似之处,即它们都有两种情势:声明与表达式。

//声明式
class B {
  constructor() {}
}

//匿名表达式
let PersonClass = class {
    // 等价于 PersonType 组织器
    constructor(name) {
    this.name = name;
    }
    // 等价于 PersonType.prototype.sayName
    sayName() {
        console.log(this.name);
    }
};
let person = new PersonClass("Nicholas");
person.sayName(); // 输出 "Nicholas"
console.log(person instanceof PersonClass); // true
console.log(person instanceof Object); // true
console.log(typeof PersonClass); // "function"
console.log(typeof PersonClass.prototype.sayName); // "function"

//定名表达式,B能够在外部运用,而B1只能在内部运用
let PersonClass = class PersonClass2 {
    // 等价于 PersonType 组织器
        constructor(name) {
    this.name = name;
    }
    // 等价于 PersonType.prototype.sayName
    sayName() {
        console.log(this.name);
    }
};
console.log(typeof PersonClass); // "function"
console.log(typeof PersonClass2); // "undefined",只要在类内部才能够接见到

作为一级国民的类

在编程中,能被看成值来运用的就称为一级国民( first-class citizen ),意味着它能作为参数传给函数、能作为函数返回值、能用来给变量赋值。
作为参数传入函数:

function createObject(classDef) {
    return new classDef();
}
let obj = createObject(class {
    sayHi() {
        console.log("Hi!");
    }
});
obj.sayHi(); // "Hi!"

经由过程马上挪用类组织函数能够建立单例:

//运用  new  来合营类表达式,并在表达式背面增加括号
let person = new class {
    constructor(name) {
        this.name = name;
    }
    sayName() {
        console.log(this.name);
    }
}("Nicholas");
person.sayName(); // "Nicholas"

接见器属性

自有属性需要在类组织器中建立,而类还许可你在原型上定义接见器属性:

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

非类的等价示意以下:

// 直接等价于上个类型
let CustomHTMLElement = (function() {
    "use strict";
    const CustomHTMLElement = function(element) {
        // 确认函数被挪用时运用了 new
        if (typeof new.target === "undefined") {
            throw new Error("Constructor must be called with new.");
        }
        this.element = element;
    }
Object.defineProperty(CustomHTMLElement.prototype, "html", {
    enumerable: false,
    configurable: true,
    get: function() {
        return this.element.innerHTML;
    },
    set: function(value) {
        this.element.innerHTML = value;
    }
});
    return CustomHTMLElement;
}());

需盘算的成员名

不必运用标识符,而是用方括号来包裹一个表达式:

let methodName = "sayName";
class PersonClass {
    constructor(name) {
        this.name = name;
    }
    [methodName]() {
        console.log(this.name);
    }
}
let me = new PersonClass("Nicholas");
me.sayName(); // "Nicholas"

接见器属性能以雷同体式格局运用需盘算的称号,就像如许:

let propertyName = "html";
class CustomHTMLElement {
    constructor(element) {
        this.element = element;
    }
    get [propertyName]() {
        return this.element.innerHTML;
    }
    set [propertyName](value) {
        this.element.innerHTML = value;
    }
}

生成器要领

你已学会怎样在对象字面量上定义一个生成器:只要在要领称号前附加一个星号( * )。这一语法对类一样有用,许可将任何要领变成一个生成器:

class MyClass {
    *createIterator() {
        yield 1;
        yield 2;
        yield 3;
    }
}
let instance = new MyClass();
let iterator = instance.createIterator();

静态成员

直接在组织器上增加分外要领来模仿静态成员,这在 ES5 及更早版本中是另一个通用的情势:

function PersonType(name) {
    this.name = name;
}
// 静态要领
PersonType.create = function(name) {
    return new PersonType(name);
};
// 实例要领
PersonType.prototype.sayName = function() {
    console.log(this.name);
};
var person = PersonType.create("Nicholas");

ES6 的类简化了静态成员的建立,只要在要领与接见器属性的称号前增加正式的 static 标注:

class PersonClass {
    // 等价于 PersonType 组织器
    constructor(name) {
        this.name = name;
    }
    // 等价于 PersonType.prototype.sayName
    sayName() {
        console.log(this.name);
    }
    // 等价于 PersonType.create
    static create(name) {
        return new PersonClass(name);
    }
}
let person = PersonClass.create("Nicholas");

和一般要领不一样的是,static润饰的要领不能在实例中接见,只能在类中直接接见。

    原文作者:sevencui
    原文地址: https://segmentfault.com/a/1190000016124990
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞