当前位置:网站首页>ES6深入—ES6 Class 类
ES6深入—ES6 Class 类
2022-07-05 15:27:00 【橘猫烧鲷鱼ᅟᅠ】
前言
本文会简要介绍 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
// declared
let 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); // Exam
let 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); // Exam
let 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); // true
class 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); // true
class 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_); // true
exam1.__proto__.sub = function () {
return this.a - this.b;
};
console.log(exam1.sum()); // 8
console.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_); // true
exam1.__proto__.sub = function () {
return this.a - this.b;
};
console.log(exam1.sum()); // 8
console.log(exam2.sum()); // 9
在终端运行,结果如下所示:
五、decorator
decorator 是一个函数,用来修改类的行为,在代码编译时产生作用。
类修饰
一个参数。
第一个参数 target,指向类本身。
function testable(target) {
target.isTestable = true;
}
@testable
class 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,最终导致 RangeError
class 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,最终导致 RangeError
class 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); // undefined
class 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 运行,结果如下所示:

# 总结
本文介绍了 ES6 Class 的 ES6 类的定义及使用的 constructor() 方法、Class 表达式和 super 关键字。
下文讲解ES6 Generator 函数。
边栏推荐
- vant tabbar遮挡内容的解决方式
- abstract关键字和哪些关键字会发生冲突呢
- Quick completion guide for manipulator (IX): forward kinematics analysis
- Data communication foundation - dynamic routing protocol rip
- Data communication foundation smart_ Link_&_ Monitor_ Link
- Data communication foundation OSPF Foundation
- Defining strict standards, Intel Evo 3.0 is accelerating the upgrading of the PC industry
- 21. [STM32] I don't understand the I2C protocol. Dig deep into the sequence diagram to help you write the underlying driver
- 对象和类的关系
- Lesson 4 knowledge summary
猜你喜欢
I include of spring and Autumn
Data communication foundation - routing communication between VLANs
Bugku's Ping
abstract关键字和哪些关键字会发生冲突呢
F. Min cost string problem solving Report
力扣今日题-729. 我的日程安排表 I
lvgl 显示图片示例
Defining strict standards, Intel Evo 3.0 is accelerating the upgrading of the PC industry
vlunhub- BoredHackerBlog Social Network
vant tabbar遮挡内容的解决方式
随机推荐
写单元测试的时候犯的错
视觉体验全面升级,豪威集团与英特尔Evo 3.0共同加速PC产业变革
RLock锁的使用
F. Weights assignment for tree edges problem solving Report
vulnhub-Root_ this_ box
Summary of the second lesson
18.[STM32]读取DS18B20温度传感器的ROM并实现多点测量温度
机械臂速成小指南(九):正运动学分析
The OBD deployment mode of oceanbase Community Edition is installed locally
[brief notes] solve the problem of IDE golang code red and error reporting
Object. defineProperty() - VS - new Proxy()
Temporary cramming before DFS examination
lv_ font_ Conv offline conversion
Value series solution report
复现Thinkphp 2.x 任意代码执行漏洞
Noi / 1.5 06: element maximum span value of integer sequence
【 note 】 résoudre l'erreur de code IDE golang
Replknet: it's not that large convolution is bad, but that convolution is not large enough. 31x31 convolution. Let's have a look at | CVPR 2022
Vulnhub-Moneybox
后台系统发送验证码功能