在传统的js里没有类的概念,只有对象,但在ES6里引用了类class,ES6引入了Class(类)这个概念,通过class关键字可以定义类。该关键字的出现使得其在对象写法上更加清晰,更像是一种面向对象的语言。ES6本文介绍了 ES6 Class 的 ES6 类的定义及使用的 constructor() 方法、Class 表达式和 super 关键字。
本文会简要介绍 ES6 Class 类的知识,如何定义如何使用,通过本节实验,需要熟练掌握 ES6 当中类的定义和使用。
一、基础用法
类定义
类表达式可以是匿名或命名的方式。
// 匿名类let ExampleA = class { constructor(count) {this.count = count; }};// 命名类let ExampleB = class ExampleB { constructor(a) {this.a = a; }};
类声明
class ExampleC { constructor(a) {this.a = a; }}
注意要点:不可以重复声明,不然报错。
class ExampleA {}class ExampleA {}// Uncaught SyntaxError: Identifier 'ExampleA' has already been// declaredlet Example1 = class {};class ExampleA {}// Uncaught SyntaxError: Identifier 'Example' has already been// declared
注意:必须在访问前对类进行定义,否则就会报错。类中方法不需要 function 关键字。方法间不能加分号。
new Example(); class Example {}
步骤如下:
创建名称为 test1.js 的文件,并且输入下面的代码。
// 匿名类let ExampleA = class { constructor(count) {this.count = count; }};// 命名类let ExampleB = class ExampleB { constructor(a) {this.a = a; }};console.log(ExampleA);console.log(ExampleB);
在终端运行,结果如下所示:
二、类的主体
属性 prototype
ES6 中,prototype 仍旧存在,虽然可以直接在类中定义方法,但是其实方法还是定义在 prototype 上的。覆盖方法 / 初始化时添加方法如下:
ExampleA.prototype = { // methods};
添加方法:
Object.assign(ExampleA.prototype, { // methods});
静态属性
静态属性:class 本身的属性,也就是直接定义在类内部的属性( Class.propname ),不需要实例化。ES6 中规定,Class 内部只有静态方法,没有静态属性。
class ExampleD { a = 2; constructor() {console.log(this.a); }}
name 属性
返回跟在 class 后的类名(存在时)。
let ExampleE = class Exam { constructor(a) {this.a = a; }};console.log(ExampleE.name); // Examlet ExampleF = class { constructor(a) {this.a = a; }};console.log(ExampleF.name); // ExampleF
实例:
创建名称为 test2.js 的文件,并且输入下面的代码。
// 静态属性class ExampleA { // 新提案 static a = 3;}// 目前可行写法ExampleA.b = 3;// 公共属性class ExampleB {}ExampleB.prototype.a = 2;// 实例属性class ExampleC { a = 2; constructor() {console.log(this.a); }}// name 属性let ExampleD = class ExamD { constructor(a) {this.a = a; }};console.log(ExampleD.name); // Examlet ExampleE = class { constructor(a) {this.a = a; }};console.log(ExampleE.name); // Example
在终端运行,结果如下所示:
三、方法
constructor 方法
constructor 方法是类的默认的方法,创建类的实例化对象时被调用。
class Example { constructor() {console.log("我是constructor"); }}new Example(); // 我是 constructor
返回对象
class Test { constructor() {// 默认返回实例对象 this }}console.log(new Test() instanceof Test); // trueclass Example { constructor() {// 指定返回对象return new Test(); }}console.log(new Example() instanceof Example); // false
静态方法
class Example { static sum(a, b) {console.log(a + b); }}Example.sum(1, 2); // 3
原型方法
class Example { constructor() {this.sum = (a, b) => { console.log(a + b);}; }}
实例方法
class Example { constructor() {this.sum = (a, b) => { console.log(a + b);}; }}
实例:
创建名称为 test3.js 的文件,并且输入下面的代码。
// constructor 方法class Example { constructor() {console.log("我是constructor"); }}new Example(); // 我是 constructor// 返回对象class Test { constructor() {// 默认返回实例对象 this }}console.log(new Test() instanceof Test); // trueclass ExampleB { constructor() {// 指定返回对象return new Test(); }}console.log(new Example() instanceof ExampleB); // false// 静态方法class ExampleD { static sum(a, b) {console.log(a + b); }}ExampleD.sum(1, 2); // 3// 原型方法class ExampleE { constructor() {this.sum = (a, b) => { console.log(a + b);}; }}// 实例方法class ExampleF { constructor() {this.sum = (a, b) => { console.log(a + b);}; }}
在终端运行,结果如下所示:
四、类的实例化
new
类的实例化,必须通过 new 关键字。
class ExampleG {}let exam1 = ExampleG();// Class constructor Example cannot be invoked without 'new'
实例化对象
共享原型对象。
class ExampleH { constructor(m, n) {this.m = m;this.n = n;console.log("ExampleH"); } sum() {return this.m + this.n; }}let exam1 = new ExampleH(5, 3);let exam2 = new ExampleH(2, 7);console.log(exam1._proto_ == exam2._proto_); // trueexam1.__proto__.sub = function () { return this.a - this.b;};console.log(exam1.sum()); // 8console.log(exam2.sum()); // 9
实例:
创建名称为 test4.js 的文件,并且输入下面的代码。
class ExampleH { constructor(m, n) {this.m = m;this.n = n;console.log("ExampleH"); } sum() {return this.m + this.n; }}let exam1 = new ExampleH(5, 3);let exam2 = new ExampleH(2, 7);console.log(exam1._proto_ == exam2._proto_); // trueexam1.__proto__.sub = function () { return this.a - this.b;};console.log(exam1.sum()); // 8console.log(exam2.sum()); // 9
在终端运行,结果如下所示:
五、decorator
decorator 是一个函数,用来修改类的行为,在代码编译时产生作用。
类修饰
一个参数。
第一个参数 target,指向类本身。
function testable(target) { target.isTestable = true;}@testableclass Example {}Example.isTestable; // true
多个参数——嵌套实现。
function testable(isTestable) { return function (target) {target.isTestable = isTestable; };}@testable(true)class Example {}Example.isTestable; // true
实例属性,上面两个例子添加的是静态属性,若要添加实例属性,在类的 prototype 上操作即可。
方法修饰
3 个参数:target(类的原型对象)、name(修饰的属性名)、descriptor(该属性的描述对象)。
class Example { @writable sum(a, b) {return a + b; }}function writable(target, name, descriptor) { descriptor.writable = false; return descriptor; // 必须返回}
修饰器执行顺序
由外向内进入,由内向外执行。
class Example { @logMethod(1) @logMthod(2) sum(a, b) {return a + b; }}function logMethod(id) { console.log("evaluated logMethod" + id); return (target, name, desctiptor) =>console.log("excuted logMethod " + id);}// evaluated logMethod 1// evaluated logMethod 2// excuted logMethod 2// excuted logMethod 1
六、封装与继承
getter / setter
定义如下所示:
class Example { constructor(a, b) {this.a = a; // 实例化时调用 set 方法this.b = b; } get a() {console.log("getter");return this.a; } set a(a) {console.log("setter");this.a = a; // 自身递归调用 }}let exam = new Example(1, 2); // 不断输出 setter,最终导致 RangeErrorclass Example1 { constructor(a, b) {this.a = a;this.b = b; } get a() {console.log("getter");return this._a; } set a(a) {console.log("setter");this._a = a; }}let exam1 = new Example1(1, 2); // 只输出 setter, 不会调用 getter 方法console.log(exam._a); // 1, 可以直接访问
创建 名称为 test5.js 的文件,并且输入下面的代码。
class Example { constructor(a, b) {this.a = a; // 实例化时调用 set 方法this.b = b; } get a() {console.log("getter");return this.a; } set a(a) {console.log("setter");this.a = a; // 自身递归调用 }}let exam = new Example(1, 2); // 不断输出 setter,最终导致 RangeErrorclass Example1 { constructor(a, b) {this.a = a;this.b = b; } get a() {console.log("getter");return this._a; } set a(a) {console.log("setter");this._a = a; }}let exam1 = new Example1(1, 2); // 只输出 setter, 不会调用 getter 方法console.log(exam._a); // 1, 可以直接访问
在终端输入 node test5.js 运行,结果如下所示:
特殊情况:getter 不可单独出现。
class Example { constructor(a) {this.a = a; } get a() {return this.a; }}let exam = new Example(1); // Uncaught TypeError: Cannot set property // a of #<Example> which has only a getter
要点:getter 与 setter 必须同级出现。
class Father { constructor() {} get a() {return this._a; }}class Child extends Father { constructor() {super(); } set a(a) {this._a = a; }}let test = new Child();test.a = 2;console.log(test.a); // undefinedclass Father1 { constructor() {} // 或者都放在子类中 get a() {return this._a; } set a(a) {this._a = a; }}class Child1 extends Father1 { constructor() {super(); }}let test1 = new Child1();test1.a = 2;console.log(test1.a); // 2
创建名称为 test6.js 的文件,并且输入上面的代码。
在终端输入 node test6.js 后运行,结果如下所示:
extends
通过 extends 实现类的继承。
class Child extends Father { ... }
七、super
子类 constructor 方法中必须有 super,且必须出现在 this 之前,下面的代码就是没有 super 函数导致出错的情况。
class Father { constructor() {} } class Child extends Father { constructor() {} // or // constructor(a) { // this.a = a; // super(); // 这里必须要有,如果没有super()会报错 // } } let test = new Child(); // Uncaught ReferenceError: Must call super // constructor in derived class before accessing 'this' or returning // from derived constructor
注意要点
不可继承常规对象。
var Father = { // ...};class Child extends Father { // ...}// Uncaught TypeError: Class extends value #<Object> is not a constructor or null// 解决方案Object.setPrototypeOf(Child.prototype, Father);
创建名称为 test7.js 的文件,并且输入下面的代码。
class Father { constructor() {}}class Child extends Father { constructor(a) {super();this.a = a;console.log(a); // print 12 }}let test = new Child(12);test;在终端输入 node test7.js 运行,结果如下所示:![请添加图片描述](https://img-blog.csdnimg.cn/4509b3f5e73e4cf197c4235c9d0a5406.png)# 总结 本文介绍了 ES6 Class 的 ES6 类的定义及使用的 constructor() 方法、Class 表达式和 super 关键字。 下文讲解ES6 Generator 函数。,可点击上面演示按钮看HTML页面效果,有需要可直接下载或开通SVIP终生会员全站免费下载。