@lppx/nlearn 1.1.3 → 1.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/cli/cli.js +43 -0
- package/dist/src/cli/index.js +33 -0
- package/dist/src/demo/class/01-/345/237/272/347/241/200/346/246/202/345/277/265.js +169 -0
- package/dist/src/demo/class/02-/347/273/247/346/211/277/344/270/216/345/244/232/346/200/201.js +232 -0
- package/dist/src/demo/class/03-/351/235/231/346/200/201/346/210/220/345/221/230/344/270/216/345/215/225/344/276/213.js +221 -0
- package/dist/src/demo/class/04-/346/216/245/345/217/243/344/270/216/345/256/236/347/216/260.js +163 -0
- package/dist/src/demo/fuse/01-/345/237/272/347/241/200/346/246/202/345/277/265.js +168 -0
- package/dist/src/demo/fuse/02-/351/253/230/347/272/247/346/220/234/347/264/242.js +212 -0
- package/dist/src/demo/fuse/03-/351/205/215/347/275/256/350/257/246/350/247/243.js +261 -0
- package/dist/src/demo/fuse/04-/345/256/236/346/210/230/346/241/210/344/276/213.js +354 -0
- package/package.json +1 -1
package/dist/src/cli/cli.js
CHANGED
|
@@ -1 +1,44 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.scanDemoFunctions = scanDemoFunctions;
|
|
4
|
+
const promises_1 = require("node:fs/promises");
|
|
5
|
+
const node_path_1 = require("node:path");
|
|
6
|
+
/**
|
|
7
|
+
* 扫描 demo 文件夹中的所有示例函数
|
|
8
|
+
*/
|
|
9
|
+
async function scanDemoFunctions() {
|
|
10
|
+
const demoPath = (0, node_path_1.join)(process.cwd(), 'src', 'demo');
|
|
11
|
+
const results = [];
|
|
12
|
+
try {
|
|
13
|
+
// 读取所有文件夹
|
|
14
|
+
const folders = await (0, promises_1.readdir)(demoPath, { withFileTypes: true });
|
|
15
|
+
for (const folder of folders) {
|
|
16
|
+
if (!folder.isDirectory())
|
|
17
|
+
continue;
|
|
18
|
+
const folderPath = (0, node_path_1.join)(demoPath, folder.name);
|
|
19
|
+
const files = await (0, promises_1.readdir)(folderPath, { withFileTypes: true });
|
|
20
|
+
for (const file of files) {
|
|
21
|
+
if (!file.isFile() || !file.name.endsWith('.ts'))
|
|
22
|
+
continue;
|
|
23
|
+
const filePath = (0, node_path_1.join)(folderPath, file.name);
|
|
24
|
+
const content = await (0, promises_1.readFile)(filePath, 'utf-8');
|
|
25
|
+
// 提取函数名(匹配 async function 和 function 声明,支持中文)
|
|
26
|
+
const functionRegex = /(?:async\s+)?function\s+([\w\u4e00-\u9fa5]+)\s*\(/g;
|
|
27
|
+
let match;
|
|
28
|
+
while ((match = functionRegex.exec(content)) !== null) {
|
|
29
|
+
const functionName = match[1];
|
|
30
|
+
results.push({
|
|
31
|
+
folder: folder.name,
|
|
32
|
+
file: file.name.replace('.ts', ''),
|
|
33
|
+
functionName
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return results;
|
|
39
|
+
}
|
|
40
|
+
catch (error) {
|
|
41
|
+
console.error('扫描示例函数时出错:', error);
|
|
42
|
+
return [];
|
|
43
|
+
}
|
|
44
|
+
}
|
package/dist/src/cli/index.js
CHANGED
|
@@ -2,9 +2,42 @@
|
|
|
2
2
|
"use strict";
|
|
3
3
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
4
|
const commander_1 = require("commander");
|
|
5
|
+
const node_console_1 = require("node:console");
|
|
6
|
+
const cli_js_1 = require("./cli.js");
|
|
5
7
|
const program = new commander_1.Command();
|
|
6
8
|
program
|
|
7
9
|
.name('nlearn')
|
|
8
10
|
.description('nodejs 生态学习工具')
|
|
9
11
|
.version('1.0.0');
|
|
12
|
+
program.command("list")
|
|
13
|
+
.alias("ls")
|
|
14
|
+
.description("列出所有模块")
|
|
15
|
+
.action(async () => {
|
|
16
|
+
(0, node_console_1.log)("列出所有示例\n");
|
|
17
|
+
const functions = await (0, cli_js_1.scanDemoFunctions)();
|
|
18
|
+
if (functions.length === 0) {
|
|
19
|
+
(0, node_console_1.log)("未找到任何示例函数");
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
// 按文件夹分组显示
|
|
23
|
+
const grouped = functions.reduce((acc, item) => {
|
|
24
|
+
if (!acc[item.folder]) {
|
|
25
|
+
acc[item.folder] = [];
|
|
26
|
+
}
|
|
27
|
+
acc[item.folder].push(item);
|
|
28
|
+
return acc;
|
|
29
|
+
}, {});
|
|
30
|
+
for (const [folder, items] of Object.entries(grouped)) {
|
|
31
|
+
(0, node_console_1.log)(`\n📦 ${folder}`);
|
|
32
|
+
items.forEach(item => {
|
|
33
|
+
(0, node_console_1.log)(` ${item.folder}@${item.file}@${item.functionName}`);
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
(0, node_console_1.log)(`\n共找到 ${functions.length} 个示例函数`);
|
|
37
|
+
});
|
|
38
|
+
program.command("run")
|
|
39
|
+
.description("运行示例函数")
|
|
40
|
+
.action(async () => {
|
|
41
|
+
(0, node_console_1.log)("运行用户选择的示例函数");
|
|
42
|
+
});
|
|
10
43
|
program.parse(process.argv);
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* TypeScript 类的基础概念
|
|
4
|
+
* ========================
|
|
5
|
+
* 介绍类的基本定义、构造函数、属性和方法
|
|
6
|
+
* 适用于 TypeScript 3.0+
|
|
7
|
+
*/
|
|
8
|
+
// #region 示例1: 基本类定义
|
|
9
|
+
class Person {
|
|
10
|
+
constructor(name, age) {
|
|
11
|
+
this.name = name;
|
|
12
|
+
this.age = age;
|
|
13
|
+
}
|
|
14
|
+
greet() {
|
|
15
|
+
console.log(`你好,我是 ${this.name},今年 ${this.age} 岁`);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
function basicClassDemo() {
|
|
19
|
+
const person = new Person('张三', 25);
|
|
20
|
+
person.greet();
|
|
21
|
+
console.log('姓名:', person.name);
|
|
22
|
+
console.log('年龄:', person.age);
|
|
23
|
+
}
|
|
24
|
+
// #endregion
|
|
25
|
+
// #region 示例2: 访问修饰符
|
|
26
|
+
class BankAccount {
|
|
27
|
+
constructor(accountNumber, owner, initialBalance) {
|
|
28
|
+
this.accountNumber = accountNumber;
|
|
29
|
+
this.owner = owner;
|
|
30
|
+
this.balance = initialBalance;
|
|
31
|
+
}
|
|
32
|
+
// 公开方法
|
|
33
|
+
deposit(amount) {
|
|
34
|
+
this.balance += amount;
|
|
35
|
+
console.log(`存入 ${amount} 元,当前余额: ${this.balance} 元`);
|
|
36
|
+
}
|
|
37
|
+
// 私有方法
|
|
38
|
+
validateAmount(amount) {
|
|
39
|
+
return amount > 0;
|
|
40
|
+
}
|
|
41
|
+
withdraw(amount) {
|
|
42
|
+
if (this.validateAmount(amount) && amount <= this.balance) {
|
|
43
|
+
this.balance -= amount;
|
|
44
|
+
console.log(`取出 ${amount} 元,当前余额: ${this.balance} 元`);
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
console.log('取款失败:金额无效或余额不足');
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
getBalance() {
|
|
51
|
+
return this.balance;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
function accessModifiersDemo() {
|
|
55
|
+
const account = new BankAccount('6222021234567890', '李四', 1000);
|
|
56
|
+
console.log('账号:', account.accountNumber);
|
|
57
|
+
account.deposit(500);
|
|
58
|
+
account.withdraw(300);
|
|
59
|
+
console.log('最终余额:', account.getBalance());
|
|
60
|
+
// console.log(account.balance); // 错误:balance 是私有属性
|
|
61
|
+
}
|
|
62
|
+
// #endregion
|
|
63
|
+
// #region 示例3: 属性简写
|
|
64
|
+
class Product {
|
|
65
|
+
// 构造函数参数属性简写
|
|
66
|
+
constructor(name, price, stock) {
|
|
67
|
+
this.name = name;
|
|
68
|
+
this.price = price;
|
|
69
|
+
this.stock = stock;
|
|
70
|
+
}
|
|
71
|
+
displayInfo() {
|
|
72
|
+
console.log(`商品: ${this.name}, 价格: ¥${this.price}, 库存: ${this.stock}`);
|
|
73
|
+
}
|
|
74
|
+
sell(quantity) {
|
|
75
|
+
if (quantity <= this.stock) {
|
|
76
|
+
this.stock -= quantity;
|
|
77
|
+
console.log(`售出 ${quantity} 件,剩余库存: ${this.stock}`);
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
console.log('库存不足');
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
function propertyShorthandDemo() {
|
|
85
|
+
const product = new Product('笔记本电脑', 5999, 10);
|
|
86
|
+
product.displayInfo();
|
|
87
|
+
product.sell(3);
|
|
88
|
+
product.displayInfo();
|
|
89
|
+
}
|
|
90
|
+
// #endregion
|
|
91
|
+
// #region 示例4: Getter 和 Setter
|
|
92
|
+
class Temperature {
|
|
93
|
+
constructor() {
|
|
94
|
+
this._celsius = 0;
|
|
95
|
+
}
|
|
96
|
+
get celsius() {
|
|
97
|
+
return this._celsius;
|
|
98
|
+
}
|
|
99
|
+
set celsius(value) {
|
|
100
|
+
if (value < -273.15) {
|
|
101
|
+
console.log('温度不能低于绝对零度');
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
this._celsius = value;
|
|
105
|
+
}
|
|
106
|
+
get fahrenheit() {
|
|
107
|
+
return this._celsius * 9 / 5 + 32;
|
|
108
|
+
}
|
|
109
|
+
set fahrenheit(value) {
|
|
110
|
+
this.celsius = (value - 32) * 5 / 9;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
function getterSetterDemo() {
|
|
114
|
+
const temp = new Temperature();
|
|
115
|
+
temp.celsius = 25;
|
|
116
|
+
console.log(`摄氏度: ${temp.celsius}°C`);
|
|
117
|
+
console.log(`华氏度: ${temp.fahrenheit}°F`);
|
|
118
|
+
temp.fahrenheit = 86;
|
|
119
|
+
console.log(`摄氏度: ${temp.celsius}°C`);
|
|
120
|
+
console.log(`华氏度: ${temp.fahrenheit}°F`);
|
|
121
|
+
temp.celsius = -300; // 触发验证
|
|
122
|
+
}
|
|
123
|
+
// #endregion
|
|
124
|
+
// #region 示例5: 只读属性
|
|
125
|
+
class Book {
|
|
126
|
+
constructor(isbn, title, author) {
|
|
127
|
+
this.isbn = isbn;
|
|
128
|
+
this.title = title;
|
|
129
|
+
this.author = author;
|
|
130
|
+
}
|
|
131
|
+
updateAuthor(newAuthor) {
|
|
132
|
+
this.author = newAuthor;
|
|
133
|
+
// this.isbn = '123'; // 错误:不能修改只读属性
|
|
134
|
+
}
|
|
135
|
+
displayInfo() {
|
|
136
|
+
console.log(`ISBN: ${this.isbn}`);
|
|
137
|
+
console.log(`书名: ${this.title}`);
|
|
138
|
+
console.log(`作者: ${this.author}`);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
function readonlyPropertyDemo() {
|
|
142
|
+
const book = new Book('978-7-115-12345-6', 'TypeScript 入门', '王五');
|
|
143
|
+
book.displayInfo();
|
|
144
|
+
book.updateAuthor('赵六');
|
|
145
|
+
console.log('\n更新作者后:');
|
|
146
|
+
book.displayInfo();
|
|
147
|
+
}
|
|
148
|
+
// #endregion
|
|
149
|
+
if (require.main === module) {
|
|
150
|
+
const demos = [
|
|
151
|
+
basicClassDemo,
|
|
152
|
+
accessModifiersDemo,
|
|
153
|
+
propertyShorthandDemo,
|
|
154
|
+
getterSetterDemo,
|
|
155
|
+
readonlyPropertyDemo
|
|
156
|
+
];
|
|
157
|
+
const index = parseInt(process.argv[2]) || 0;
|
|
158
|
+
if (index > 0 && index <= demos.length) {
|
|
159
|
+
console.log(`\n=== 运行示例 ${index} ===\n`);
|
|
160
|
+
demos[index - 1]();
|
|
161
|
+
}
|
|
162
|
+
else {
|
|
163
|
+
console.log('=== 运行所有示例 ===\n');
|
|
164
|
+
demos.forEach((demo, i) => {
|
|
165
|
+
console.log(`\n--- 示例 ${i + 1}: ${demo.name} ---\n`);
|
|
166
|
+
demo();
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
}
|
package/dist/src/demo/class/02-/347/273/247/346/211/277/344/270/216/345/244/232/346/200/201.js
ADDED
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* TypeScript 类的继承与多态
|
|
4
|
+
* ==========================
|
|
5
|
+
* 介绍类的继承、方法重写、super 关键字和多态性
|
|
6
|
+
* 适用于 TypeScript 3.0+
|
|
7
|
+
*/
|
|
8
|
+
// #region 示例1: 基本继承
|
|
9
|
+
class Animal {
|
|
10
|
+
constructor(name) {
|
|
11
|
+
this.name = name;
|
|
12
|
+
}
|
|
13
|
+
move(distance = 0) {
|
|
14
|
+
console.log(`${this.name} 移动了 ${distance} 米`);
|
|
15
|
+
}
|
|
16
|
+
makeSound() {
|
|
17
|
+
console.log(`${this.name} 发出声音`);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
class Dog extends Animal {
|
|
21
|
+
constructor(name, breed) {
|
|
22
|
+
super(name); // 调用父类构造函数
|
|
23
|
+
this.breed = breed;
|
|
24
|
+
}
|
|
25
|
+
makeSound() {
|
|
26
|
+
console.log(`${this.name} 汪汪叫`);
|
|
27
|
+
}
|
|
28
|
+
fetch() {
|
|
29
|
+
console.log(`${this.name} 去捡球`);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
function basicInheritanceDemo() {
|
|
33
|
+
const animal = new Animal('动物');
|
|
34
|
+
animal.makeSound();
|
|
35
|
+
animal.move(10);
|
|
36
|
+
console.log();
|
|
37
|
+
const dog = new Dog('旺财', '金毛');
|
|
38
|
+
dog.makeSound();
|
|
39
|
+
dog.move(20);
|
|
40
|
+
dog.fetch();
|
|
41
|
+
console.log(`品种: ${dog.breed}`);
|
|
42
|
+
}
|
|
43
|
+
// #endregion
|
|
44
|
+
// #region 示例2: 方法重写与 super
|
|
45
|
+
class Shape {
|
|
46
|
+
constructor(color) {
|
|
47
|
+
this.color = color;
|
|
48
|
+
}
|
|
49
|
+
describe() {
|
|
50
|
+
console.log(`这是一个 ${this.color} 的图形`);
|
|
51
|
+
}
|
|
52
|
+
getArea() {
|
|
53
|
+
return 0;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
class Rectangle extends Shape {
|
|
57
|
+
constructor(color, width, height) {
|
|
58
|
+
super(color);
|
|
59
|
+
this.width = width;
|
|
60
|
+
this.height = height;
|
|
61
|
+
}
|
|
62
|
+
describe() {
|
|
63
|
+
super.describe(); // 调用父类方法
|
|
64
|
+
console.log(`宽度: ${this.width}, 高度: ${this.height}`);
|
|
65
|
+
}
|
|
66
|
+
getArea() {
|
|
67
|
+
return this.width * this.height;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
class Circle extends Shape {
|
|
71
|
+
constructor(color, radius) {
|
|
72
|
+
super(color);
|
|
73
|
+
this.radius = radius;
|
|
74
|
+
}
|
|
75
|
+
describe() {
|
|
76
|
+
super.describe();
|
|
77
|
+
console.log(`半径: ${this.radius}`);
|
|
78
|
+
}
|
|
79
|
+
getArea() {
|
|
80
|
+
return Math.PI * this.radius ** 2;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
function methodOverrideDemo() {
|
|
84
|
+
const rect = new Rectangle('红色', 10, 5);
|
|
85
|
+
rect.describe();
|
|
86
|
+
console.log(`面积: ${rect.getArea()}\n`);
|
|
87
|
+
const circle = new Circle('蓝色', 7);
|
|
88
|
+
circle.describe();
|
|
89
|
+
console.log(`面积: ${circle.getArea().toFixed(2)}`);
|
|
90
|
+
}
|
|
91
|
+
// #endregion
|
|
92
|
+
// #region 示例3: 多态性
|
|
93
|
+
class Employee {
|
|
94
|
+
constructor(name, salary) {
|
|
95
|
+
this.name = name;
|
|
96
|
+
this.salary = salary;
|
|
97
|
+
}
|
|
98
|
+
calculateBonus() {
|
|
99
|
+
return this.salary * 0.1;
|
|
100
|
+
}
|
|
101
|
+
displayInfo() {
|
|
102
|
+
console.log(`员工: ${this.name}`);
|
|
103
|
+
console.log(`基本工资: ¥${this.salary}`);
|
|
104
|
+
console.log(`奖金: ¥${this.calculateBonus()}`);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
class Manager extends Employee {
|
|
108
|
+
constructor(name, salary, teamSize) {
|
|
109
|
+
super(name, salary);
|
|
110
|
+
this.teamSize = teamSize;
|
|
111
|
+
}
|
|
112
|
+
calculateBonus() {
|
|
113
|
+
return this.salary * 0.2 + this.teamSize * 1000;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
class Developer extends Employee {
|
|
117
|
+
constructor(name, salary, projectCount) {
|
|
118
|
+
super(name, salary);
|
|
119
|
+
this.projectCount = projectCount;
|
|
120
|
+
}
|
|
121
|
+
calculateBonus() {
|
|
122
|
+
return this.salary * 0.15 + this.projectCount * 500;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
function polymorphismDemo() {
|
|
126
|
+
const employees = [
|
|
127
|
+
new Employee('张三', 8000),
|
|
128
|
+
new Manager('李四', 15000, 5),
|
|
129
|
+
new Developer('王五', 12000, 3)
|
|
130
|
+
];
|
|
131
|
+
employees.forEach((emp, index) => {
|
|
132
|
+
console.log(`\n--- 员工 ${index + 1} ---`);
|
|
133
|
+
emp.displayInfo();
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
// #endregion
|
|
137
|
+
// #region 示例4: 抽象类
|
|
138
|
+
class Vehicle {
|
|
139
|
+
constructor(brand) {
|
|
140
|
+
this.brand = brand;
|
|
141
|
+
}
|
|
142
|
+
// 普通方法,子类可以直接使用
|
|
143
|
+
displayBrand() {
|
|
144
|
+
console.log(`品牌: ${this.brand}`);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
class Car extends Vehicle {
|
|
148
|
+
constructor(brand, model) {
|
|
149
|
+
super(brand);
|
|
150
|
+
this.model = model;
|
|
151
|
+
}
|
|
152
|
+
start() {
|
|
153
|
+
console.log(`${this.brand} ${this.model} 启动发动机`);
|
|
154
|
+
}
|
|
155
|
+
stop() {
|
|
156
|
+
console.log(`${this.brand} ${this.model} 熄火`);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
class Bicycle extends Vehicle {
|
|
160
|
+
constructor(brand, type) {
|
|
161
|
+
super(brand);
|
|
162
|
+
this.type = type;
|
|
163
|
+
}
|
|
164
|
+
start() {
|
|
165
|
+
console.log(`${this.brand} ${this.type} 开始骑行`);
|
|
166
|
+
}
|
|
167
|
+
stop() {
|
|
168
|
+
console.log(`${this.brand} ${this.type} 停止骑行`);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
function abstractClassDemo() {
|
|
172
|
+
// const vehicle = new Vehicle('通用'); // 错误:不能实例化抽象类
|
|
173
|
+
const car = new Car('特斯拉', 'Model 3');
|
|
174
|
+
car.displayBrand();
|
|
175
|
+
car.start();
|
|
176
|
+
car.stop();
|
|
177
|
+
console.log();
|
|
178
|
+
const bike = new Bicycle('捷安特', '山地车');
|
|
179
|
+
bike.displayBrand();
|
|
180
|
+
bike.start();
|
|
181
|
+
bike.stop();
|
|
182
|
+
}
|
|
183
|
+
// #endregion
|
|
184
|
+
// #region 示例5: 受保护成员的继承
|
|
185
|
+
class BankAccountBase {
|
|
186
|
+
constructor(initialBalance) {
|
|
187
|
+
this.balance = initialBalance;
|
|
188
|
+
}
|
|
189
|
+
getBalance() {
|
|
190
|
+
return this.balance;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
class SavingsAccount extends BankAccountBase {
|
|
194
|
+
constructor(initialBalance, interestRate) {
|
|
195
|
+
super(initialBalance);
|
|
196
|
+
this.interestRate = interestRate;
|
|
197
|
+
}
|
|
198
|
+
addInterest() {
|
|
199
|
+
const interest = this.balance * this.interestRate;
|
|
200
|
+
this.balance += interest; // 可以访问父类的 protected 成员
|
|
201
|
+
console.log(`添加利息 ¥${interest.toFixed(2)}`);
|
|
202
|
+
console.log(`新余额: ¥${this.balance.toFixed(2)}`);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
function protectedMemberDemo() {
|
|
206
|
+
const savings = new SavingsAccount(10000, 0.03);
|
|
207
|
+
console.log(`初始余额: ¥${savings.getBalance()}`);
|
|
208
|
+
savings.addInterest();
|
|
209
|
+
// console.log(savings.balance); // 错误:balance 是受保护的
|
|
210
|
+
}
|
|
211
|
+
// #endregion
|
|
212
|
+
if (require.main === module) {
|
|
213
|
+
const demos = [
|
|
214
|
+
basicInheritanceDemo,
|
|
215
|
+
methodOverrideDemo,
|
|
216
|
+
polymorphismDemo,
|
|
217
|
+
abstractClassDemo,
|
|
218
|
+
protectedMemberDemo
|
|
219
|
+
];
|
|
220
|
+
const index = parseInt(process.argv[2]) || 0;
|
|
221
|
+
if (index > 0 && index <= demos.length) {
|
|
222
|
+
console.log(`\n=== 运行示例 ${index} ===\n`);
|
|
223
|
+
demos[index - 1]();
|
|
224
|
+
}
|
|
225
|
+
else {
|
|
226
|
+
console.log('=== 运行所有示例 ===\n');
|
|
227
|
+
demos.forEach((demo, i) => {
|
|
228
|
+
console.log(`\n--- 示例 ${i + 1}: ${demo.name} ---\n`);
|
|
229
|
+
demo();
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
}
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* TypeScript 类的静态成员与单例模式
|
|
4
|
+
* ===================================
|
|
5
|
+
* 介绍静态属性、静态方法和单例模式的实现
|
|
6
|
+
* 适用于 TypeScript 3.0+
|
|
7
|
+
*/
|
|
8
|
+
// #region 示例1: 静态属性和方法
|
|
9
|
+
class MathUtils {
|
|
10
|
+
static add(a, b) {
|
|
11
|
+
return a + b;
|
|
12
|
+
}
|
|
13
|
+
static multiply(a, b) {
|
|
14
|
+
return a * b;
|
|
15
|
+
}
|
|
16
|
+
static circleArea(radius) {
|
|
17
|
+
return this.PI * radius ** 2;
|
|
18
|
+
}
|
|
19
|
+
static power(base, exponent) {
|
|
20
|
+
return Math.pow(base, exponent);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
MathUtils.PI = 3.14159;
|
|
24
|
+
MathUtils.E = 2.71828;
|
|
25
|
+
function staticMembersDemo() {
|
|
26
|
+
// 直接通过类名访问静态成员,无需实例化
|
|
27
|
+
console.log('PI 的值:', MathUtils.PI);
|
|
28
|
+
console.log('E 的值:', MathUtils.E);
|
|
29
|
+
console.log('5 + 3 =', MathUtils.add(5, 3));
|
|
30
|
+
console.log('4 × 6 =', MathUtils.multiply(4, 6));
|
|
31
|
+
console.log('半径为 5 的圆面积:', MathUtils.circleArea(5).toFixed(2));
|
|
32
|
+
console.log('2 的 8 次方:', MathUtils.power(2, 8));
|
|
33
|
+
}
|
|
34
|
+
// #endregion
|
|
35
|
+
// #region 示例2: 静态属性计数器
|
|
36
|
+
class User {
|
|
37
|
+
constructor(username) {
|
|
38
|
+
this.username = username;
|
|
39
|
+
User.userCount++;
|
|
40
|
+
this.id = User.userCount;
|
|
41
|
+
User.users.push(this);
|
|
42
|
+
}
|
|
43
|
+
static getUserCount() {
|
|
44
|
+
return User.userCount;
|
|
45
|
+
}
|
|
46
|
+
static getAllUsers() {
|
|
47
|
+
return User.users;
|
|
48
|
+
}
|
|
49
|
+
static findUserById(id) {
|
|
50
|
+
return User.users.find(user => user.id === id);
|
|
51
|
+
}
|
|
52
|
+
displayInfo() {
|
|
53
|
+
console.log(`用户 ID: ${this.id}, 用户名: ${this.username}`);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
User.userCount = 0;
|
|
57
|
+
User.users = [];
|
|
58
|
+
function staticCounterDemo() {
|
|
59
|
+
console.log('初始用户数:', User.getUserCount());
|
|
60
|
+
const user1 = new User('张三');
|
|
61
|
+
const user2 = new User('李四');
|
|
62
|
+
const user3 = new User('王五');
|
|
63
|
+
console.log('当前用户数:', User.getUserCount());
|
|
64
|
+
console.log('\n所有用户:');
|
|
65
|
+
User.getAllUsers().forEach(user => user.displayInfo());
|
|
66
|
+
console.log('\n查找 ID 为 2 的用户:');
|
|
67
|
+
const foundUser = User.findUserById(2);
|
|
68
|
+
foundUser?.displayInfo();
|
|
69
|
+
}
|
|
70
|
+
// #endregion
|
|
71
|
+
// #region 示例3: 单例模式 - 基础实现
|
|
72
|
+
class Database {
|
|
73
|
+
// 私有构造函数,防止外部实例化
|
|
74
|
+
constructor() {
|
|
75
|
+
this.connectionString = 'mongodb://localhost:27017/mydb';
|
|
76
|
+
console.log('数据库连接已创建');
|
|
77
|
+
}
|
|
78
|
+
static getInstance() {
|
|
79
|
+
if (!Database.instance) {
|
|
80
|
+
Database.instance = new Database();
|
|
81
|
+
}
|
|
82
|
+
return Database.instance;
|
|
83
|
+
}
|
|
84
|
+
query(sql) {
|
|
85
|
+
console.log(`执行查询: ${sql}`);
|
|
86
|
+
console.log(`连接字符串: ${this.connectionString}`);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
function singletonBasicDemo() {
|
|
90
|
+
// const db = new Database(); // 错误:构造函数是私有的
|
|
91
|
+
const db1 = Database.getInstance();
|
|
92
|
+
db1.query('SELECT * FROM users');
|
|
93
|
+
console.log();
|
|
94
|
+
const db2 = Database.getInstance();
|
|
95
|
+
db2.query('SELECT * FROM products');
|
|
96
|
+
console.log();
|
|
97
|
+
console.log('db1 和 db2 是同一个实例:', db1 === db2);
|
|
98
|
+
}
|
|
99
|
+
// #endregion
|
|
100
|
+
// #region 示例4: 单例模式 - 配置管理器
|
|
101
|
+
class ConfigManager {
|
|
102
|
+
constructor() {
|
|
103
|
+
this.config = new Map();
|
|
104
|
+
this.loadDefaultConfig();
|
|
105
|
+
}
|
|
106
|
+
static getInstance() {
|
|
107
|
+
if (!ConfigManager.instance) {
|
|
108
|
+
ConfigManager.instance = new ConfigManager();
|
|
109
|
+
}
|
|
110
|
+
return ConfigManager.instance;
|
|
111
|
+
}
|
|
112
|
+
loadDefaultConfig() {
|
|
113
|
+
this.config.set('appName', 'MyApp');
|
|
114
|
+
this.config.set('version', '1.0.0');
|
|
115
|
+
this.config.set('debug', false);
|
|
116
|
+
console.log('默认配置已加载');
|
|
117
|
+
}
|
|
118
|
+
get(key) {
|
|
119
|
+
return this.config.get(key);
|
|
120
|
+
}
|
|
121
|
+
set(key, value) {
|
|
122
|
+
this.config.set(key, value);
|
|
123
|
+
console.log(`配置已更新: ${key} = ${value}`);
|
|
124
|
+
}
|
|
125
|
+
getAll() {
|
|
126
|
+
return Object.fromEntries(this.config);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
function configManagerDemo() {
|
|
130
|
+
const config1 = ConfigManager.getInstance();
|
|
131
|
+
console.log('应用名称:', config1.get('appName'));
|
|
132
|
+
console.log('版本:', config1.get('version'));
|
|
133
|
+
console.log();
|
|
134
|
+
config1.set('debug', true);
|
|
135
|
+
config1.set('port', 3000);
|
|
136
|
+
console.log();
|
|
137
|
+
const config2 = ConfigManager.getInstance();
|
|
138
|
+
console.log('所有配置:', config2.getAll());
|
|
139
|
+
console.log('config1 和 config2 是同一个实例:', config1 === config2);
|
|
140
|
+
}
|
|
141
|
+
// #endregion
|
|
142
|
+
// #region 示例5: 静态工厂方法
|
|
143
|
+
class Logger {
|
|
144
|
+
constructor(level, prefix) {
|
|
145
|
+
this.level = level;
|
|
146
|
+
this.prefix = prefix;
|
|
147
|
+
}
|
|
148
|
+
static createConsoleLogger() {
|
|
149
|
+
return new Logger('INFO', '[Console]');
|
|
150
|
+
}
|
|
151
|
+
static createFileLogger() {
|
|
152
|
+
return new Logger('DEBUG', '[File]');
|
|
153
|
+
}
|
|
154
|
+
static createErrorLogger() {
|
|
155
|
+
return new Logger('ERROR', '[Error]');
|
|
156
|
+
}
|
|
157
|
+
log(message) {
|
|
158
|
+
console.log(`${this.prefix} [${this.level}] ${message}`);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
class DateFormatter {
|
|
162
|
+
constructor(formatPattern) {
|
|
163
|
+
this.formatPattern = formatPattern;
|
|
164
|
+
}
|
|
165
|
+
static createShortFormat() {
|
|
166
|
+
return new DateFormatter('YYYY-MM-DD');
|
|
167
|
+
}
|
|
168
|
+
static createLongFormat() {
|
|
169
|
+
return new DateFormatter('YYYY-MM-DD HH:mm:ss');
|
|
170
|
+
}
|
|
171
|
+
format(date) {
|
|
172
|
+
const year = date.getFullYear();
|
|
173
|
+
const month = String(date.getMonth() + 1).padStart(2, '0');
|
|
174
|
+
const day = String(date.getDate()).padStart(2, '0');
|
|
175
|
+
if (this.formatPattern === 'YYYY-MM-DD') {
|
|
176
|
+
return `${year}-${month}-${day}`;
|
|
177
|
+
}
|
|
178
|
+
else {
|
|
179
|
+
const hours = String(date.getHours()).padStart(2, '0');
|
|
180
|
+
const minutes = String(date.getMinutes()).padStart(2, '0');
|
|
181
|
+
const seconds = String(date.getSeconds()).padStart(2, '0');
|
|
182
|
+
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
function staticFactoryDemo() {
|
|
187
|
+
const consoleLogger = Logger.createConsoleLogger();
|
|
188
|
+
const fileLogger = Logger.createFileLogger();
|
|
189
|
+
const errorLogger = Logger.createErrorLogger();
|
|
190
|
+
consoleLogger.log('这是一条控制台日志');
|
|
191
|
+
fileLogger.log('这是一条文件日志');
|
|
192
|
+
errorLogger.log('这是一条错误日志');
|
|
193
|
+
console.log();
|
|
194
|
+
const now = new Date();
|
|
195
|
+
const shortFormatter = DateFormatter.createShortFormat();
|
|
196
|
+
const longFormatter = DateFormatter.createLongFormat();
|
|
197
|
+
console.log('短格式:', shortFormatter.format(now));
|
|
198
|
+
console.log('长格式:', longFormatter.format(now));
|
|
199
|
+
}
|
|
200
|
+
// #endregion
|
|
201
|
+
if (require.main === module) {
|
|
202
|
+
const demos = [
|
|
203
|
+
staticMembersDemo,
|
|
204
|
+
staticCounterDemo,
|
|
205
|
+
singletonBasicDemo,
|
|
206
|
+
configManagerDemo,
|
|
207
|
+
staticFactoryDemo
|
|
208
|
+
];
|
|
209
|
+
const index = parseInt(process.argv[2]) || 0;
|
|
210
|
+
if (index > 0 && index <= demos.length) {
|
|
211
|
+
console.log(`\n=== 运行示例 ${index} ===\n`);
|
|
212
|
+
demos[index - 1]();
|
|
213
|
+
}
|
|
214
|
+
else {
|
|
215
|
+
console.log('=== 运行所有示例 ===\n');
|
|
216
|
+
demos.forEach((demo, i) => {
|
|
217
|
+
console.log(`\n--- 示例 ${i + 1}: ${demo.name} ---\n`);
|
|
218
|
+
demo();
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
}
|