关键词搜索

全站搜索×
注册会员
×

已有账号? 请点击

使用其他方式登录

ES6 Class类深入讲解

发布2022-06-20浏览27次

详情内容

这是一个

在传统的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 {}

步骤如下:

  1. 创建名称为 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);

  1. 在终端运行,结果如下所示:

请添加图片描述

二、类的主体

属性 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终生会员全站免费下载。
点击QQ咨询
开通会员
返回顶部
×
  • 微信支付
  • 支付宝付款
微信扫码支付
微信扫码支付
请使用微信描二维码支付
×

提示信息

×

选择支付方式

  • 微信支付
  • 支付宝付款
确定支付下载