2025-01-22 日报 Day74

2025-01-22 日报 Day74

Yuyang 前端小白🥬

今日的鸡汤

只要你开始思考、开始行动,你就已经走上了一条必然不易,但也充满希望的路途了。

今日学习内容

1、JS 红皮书 P254-256 第八章:对象、类与面向对象编程

今日笔记

1、类的语法可以非常方便地定义应该存在于实例上的成员、应该存在于原型上的成员,以及应该存在于类本身的成员。

  • 实例成员: 每次通过 new 调用类标识符时,都会执行类构造函数。在这个函数内部,可以为新创建的实例(this)添加“自有”属性。至于添加什么样的属性,则没有限制。另外,在构造函数执行完毕后,仍然可以给实例继续添加新成员。每个实例都对应一个唯一的成员对象,这意味着所有成员都不会在原型上共享:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Person {
constructor() {
// 这个例子先使用对象包装类型定义一个字符串
// 为的是在下面测试两个对象的相等性
this.name = new String("Jack");
this.sayName = () => console.log(this.name);
this.nicknames = ["Jake", "J-Dog"];
}
}
let p1 = new Person(),
p2 = new Person();
p1.sayName(); // Jack
p2.sayName(); // Jack
console.log(p1.name === p2.name); // false
console.log(p1.sayName === p2.sayName); // false
console.log(p1.nicknames === p2.nicknames); // false
p1.name = p1.nicknames[0];
p2.name = p2.nicknames[1];
p1.sayName(); // Jake
p2.sayName(); // J-Dog
  • 原型方法与访问器: 为了在实例间共享方法,类定义语法把在类块中定义的方法作为原型方法。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
class Person {
constructor() {
// 添加到 this 的所有内容都会存在于不同的实例上
this.locate = () => console.log("instance");
}
// 在类块中定义的所有内容都会定义在类的原型上
locate() {
console.log("prototype");
}
}
let p = new Person();
p.locate(); // instance
Person.prototype.locate(); // prototype
// 可以把方法定义在类构造函数中或者类块中,但不能在类块中给原型添加原始值或对象作为成员数据:
class Person {
name: "Jake";
}
// Uncaught SyntaxError: Unexpected token
// 类方法等同于对象属性,因此可以使用字符串、符号或计算的值作为键:
const symbolKey = Symbol("symbolKey");
class Person {
stringKey() {
console.log("invoked stringKey");
}
[symbolKey]() {
console.log("invoked symbolKey");
}
["computed" + "Key"]() {
console.log("invoked computedKey");
}
}
let p = new Person();
p.stringKey(); // invoked stringKey
p[symbolKey](); // invoked symbolKey
p.computedKey(); // invoked computedKey
// 类定义也支持获取和设置访问器。语法与行为跟普通对象一样:
class Person {
set name(newName) {
this.name_ = newName;
}
get name() {
return this.name_;
}
}
let p = new Person();
p.name = "Jake";
console.log(p.name); // Jake
  • 静态类方法: 可以在类上定义静态方法。这些方法通常用于执行不特定于实例的操作,也不要求存在类的实例。与原型成员类似,静态成员每个类上只能有一个。
    静态类成员在类定义中使用 static 关键字作为前缀。在静态成员中,this 引用类自身。其他所有约定跟原型成员一样:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
class Person {
constructor() {
// 添加到 this 的所有内容都会存在于不同的实例上
this.locate = () => console.log("instance", this);
}
// 定义在类的原型对象上
locate() {
console.log("prototype", this);
}
// 定义在类本身上
static locate() {
console.log("class", this);
}
}
let p = new Person();
p.locate(); // instance, Person {}
Person.prototype.locate(); // prototype, {constructor: ... }
Person.locate(); // class, class Person {}
// 静态类方法非常适合作为实例工厂:
class Person {
constructor(age) {
this.age_ = age;
}
sayAge() {
console.log(this.age_);
}
static create() {
// 使用随机年龄创建并返回一个 Person 实例
return new Person(Math.floor(Math.random() * 100));
}
}
console.log(Person.create()); // Person { age_: ... }
  • 非函数原型和类成员: 虽然类定义并不显式支持在原型或类上添加成员数据,但在类定义外部,可以手动添加:
1
2
3
4
5
6
7
8
9
10
11
class Person { 
sayName() {
console.log(`${Person.greeting} ${this.name}`);
}
}
// 在类上定义数据成员
Person.greeting = 'My name is';
// 在原型上定义数据成员
Person.prototype.name = 'Jake';
let p = new Person();
p.sayName(); // My name is Jake

注意 类定义中之所以没有显式支持添加数据成员,是因为在共享目标(原型和类)上添加可变(可修改)数据成员是一种反模式。一般来说,对象实例应该独自拥有通过 this引用的数据。

此页目录
2025-01-22 日报 Day74