@lppx/nlearn 1.1.4 → 1.1.7
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 +103 -3
- package/dist/src/cli/index.js +15 -1
- 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,8 +1,48 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
+
};
|
|
2
38
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
39
|
exports.scanDemoFunctions = scanDemoFunctions;
|
|
40
|
+
exports.selectFunctionWithFuzzySearch = selectFunctionWithFuzzySearch;
|
|
41
|
+
exports.executeDemoFunction = executeDemoFunction;
|
|
4
42
|
const promises_1 = require("node:fs/promises");
|
|
5
43
|
const node_path_1 = require("node:path");
|
|
44
|
+
const prompts_1 = __importDefault(require("prompts"));
|
|
45
|
+
const fuse_js_1 = __importDefault(require("fuse.js"));
|
|
6
46
|
/**
|
|
7
47
|
* 扫描 demo 文件夹中的所有示例函数
|
|
8
48
|
*/
|
|
@@ -22,15 +62,17 @@ async function scanDemoFunctions() {
|
|
|
22
62
|
continue;
|
|
23
63
|
const filePath = (0, node_path_1.join)(folderPath, file.name);
|
|
24
64
|
const content = await (0, promises_1.readFile)(filePath, 'utf-8');
|
|
25
|
-
// 提取函数名(匹配 async function 和 function
|
|
26
|
-
const functionRegex = /(?:async\s+)?function\s+(\w+)\s*\(/g;
|
|
65
|
+
// 提取函数名(匹配 async function 和 function 声明,支持中文)
|
|
66
|
+
const functionRegex = /(?:async\s+)?function\s+([\w\u4e00-\u9fa5]+)\s*\(/g;
|
|
27
67
|
let match;
|
|
28
68
|
while ((match = functionRegex.exec(content)) !== null) {
|
|
29
69
|
const functionName = match[1];
|
|
70
|
+
const displayName = `${folder.name}@${file.name.replace('.ts', '')}@${functionName}`;
|
|
30
71
|
results.push({
|
|
31
72
|
folder: folder.name,
|
|
32
73
|
file: file.name.replace('.ts', ''),
|
|
33
|
-
functionName
|
|
74
|
+
functionName,
|
|
75
|
+
displayName
|
|
34
76
|
});
|
|
35
77
|
}
|
|
36
78
|
}
|
|
@@ -42,3 +84,61 @@ async function scanDemoFunctions() {
|
|
|
42
84
|
return [];
|
|
43
85
|
}
|
|
44
86
|
}
|
|
87
|
+
/**
|
|
88
|
+
* 使用 prompts 和 fuse.js 实现模糊搜索选择函数
|
|
89
|
+
*/
|
|
90
|
+
async function selectFunctionWithFuzzySearch(functions) {
|
|
91
|
+
// 配置 Fuse.js 进行模糊搜索
|
|
92
|
+
const fuse = new fuse_js_1.default(functions, {
|
|
93
|
+
keys: ['displayName', 'folder', 'file', 'functionName'],
|
|
94
|
+
threshold: 0.4,
|
|
95
|
+
includeScore: true
|
|
96
|
+
});
|
|
97
|
+
// 自定义搜索建议函数
|
|
98
|
+
const suggest = (input, choices) => {
|
|
99
|
+
if (!input) {
|
|
100
|
+
return Promise.resolve(choices);
|
|
101
|
+
}
|
|
102
|
+
const results = fuse.search(input);
|
|
103
|
+
return Promise.resolve(results.map(result => ({
|
|
104
|
+
title: result.item.displayName,
|
|
105
|
+
value: result.item
|
|
106
|
+
})));
|
|
107
|
+
};
|
|
108
|
+
const response = await (0, prompts_1.default)({
|
|
109
|
+
type: 'autocomplete',
|
|
110
|
+
name: 'selectedFunction',
|
|
111
|
+
message: '请选择要运行的示例函数 (支持模糊搜索):',
|
|
112
|
+
choices: functions.map(fn => ({
|
|
113
|
+
title: fn.displayName,
|
|
114
|
+
value: fn
|
|
115
|
+
})),
|
|
116
|
+
suggest
|
|
117
|
+
});
|
|
118
|
+
return response.selectedFunction || null;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* 动态导入并执行选中的函数
|
|
122
|
+
*/
|
|
123
|
+
async function executeDemoFunction(demoFunc) {
|
|
124
|
+
try {
|
|
125
|
+
console.log(`\n正在运行: ${demoFunc.displayName}\n`);
|
|
126
|
+
console.log('='.repeat(50));
|
|
127
|
+
// 构建模块路径
|
|
128
|
+
const modulePath = (0, node_path_1.join)(process.cwd(), 'src', 'demo', demoFunc.folder, `${demoFunc.file}.js`);
|
|
129
|
+
// 动态导入模块
|
|
130
|
+
const module = await Promise.resolve(`${modulePath}`).then(s => __importStar(require(s)));
|
|
131
|
+
// 检查函数是否存在
|
|
132
|
+
if (typeof module[demoFunc.functionName] !== 'function') {
|
|
133
|
+
console.error(`错误: 函数 ${demoFunc.functionName} 不存在或不是一个函数`);
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
// 执行函数
|
|
137
|
+
await module[demoFunc.functionName]();
|
|
138
|
+
console.log('\n' + '='.repeat(50));
|
|
139
|
+
console.log('✓ 执行完成\n');
|
|
140
|
+
}
|
|
141
|
+
catch (error) {
|
|
142
|
+
console.error('\n执行函数时出错:', error);
|
|
143
|
+
}
|
|
144
|
+
}
|
package/dist/src/cli/index.js
CHANGED
|
@@ -38,6 +38,20 @@ program.command("list")
|
|
|
38
38
|
program.command("run")
|
|
39
39
|
.description("运行示例函数")
|
|
40
40
|
.action(async () => {
|
|
41
|
-
(0, node_console_1.log)("
|
|
41
|
+
(0, node_console_1.log)("扫描示例函数...\n");
|
|
42
|
+
const functions = await (0, cli_js_1.scanDemoFunctions)();
|
|
43
|
+
if (functions.length === 0) {
|
|
44
|
+
(0, node_console_1.log)("未找到任何示例函数");
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
(0, node_console_1.log)(`找到 ${functions.length} 个示例函数\n`);
|
|
48
|
+
// 使用 prompts 和 fuse.js 实现模糊搜索选择
|
|
49
|
+
const selectedFunction = await (0, cli_js_1.selectFunctionWithFuzzySearch)(functions);
|
|
50
|
+
if (!selectedFunction) {
|
|
51
|
+
(0, node_console_1.log)("\n未选择任何函数");
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
// 执行选中的函数
|
|
55
|
+
await (0, cli_js_1.executeDemoFunction)(selectedFunction);
|
|
42
56
|
});
|
|
43
57
|
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
|
+
}
|