Javascript - 如何在多个模块中定义一个 class?
Javascript - How to define a class in multiple modules?
我有一个 class,它变得很长。我已经确定了多个不同的概念,它们一起赋予了我 class.
意义
"MyService" class 由:"auth", "storage", "数据库", ...概念。
我认为(也许我错了)在多个文件中定义 class“MyService”将是一个很好的重构。类似于:
MyService/MyService.js
从“./myService”导入我的服务;
export default function MyService() {
if(!isInitialized) {
myService.initializeApp(config);
// Only after doing myService.initializeApp(config);
this.auth = myService.auth();
this.storage = myService.storage();
this.database = myService.database();
isInitialized = true;
}
}
MyService/Auth.js
Add auth methods to MyService class prototype
MyService/Storage.js
Add storage methods to MyService class prototype
...
我该怎么做?这个技巧有name/exists吗?这是重构我的 class 的好方法吗?如果是,为什么?如果不是,那么,为什么?
谢谢。
更新
也许,将 class 拆分成更小的 classes 是最好的主意,但我不知道如何让它工作以访问 myService 功能,
这条线
myService.initializeApp(config);
之前必须在单例上执行过。
基于解决方案的示例
/* Simulate myService CLI SDK */
function myService() {}
myService.key = undefined;
myService.initializeApp = function (key) {
this.key = key;
}
myService.auth = function () {
if(!this.key) {
throw new Error("Please, initialize app");
}
console.log(`You have access to all auth methods! Key: ${this.key}`);
}
myService.storage = function () {
if(!this.key) {
throw new Error("Please, initialize app")
}
console.log(`You have access to all storage methods! Key: ${this.key}`);
}
/* Classes that compose the main class */
function Auth() {
this.auth = myService.auth();
}
Auth.prototype.login = function (username, password) {
console.log("Login!");
}
function Storage() {
this.storage = myService.storage();
}
Storage.prototype.uploadFile = function (file, path) {
console.log("Uploading file!")
}
/* Main class */
let isInitialized = false;
function Firebase() {
if(!isInitialized) { // Singleton
myService.initializeApp("raul");
this.auth = new Auth(); // Composition
this.storage = new Storage(); // Composition
isInitialized = true;
}
}
const f = new Firebase();
f.auth.login();
f.storage.uploadFile();
与其将 MyService
分散到多个模块中,不如将其分解成更小的 class。你说过:
"MyService" class is composed by: "auth", "storage", "database", ... concepts.
所以可能有一个 class 用于身份验证,另一个用于存储,另一个用于数据库,然后 MyService
使用其他 classes 的实例作为一部分它的实施。
您不能跨模块传播 class
定义。(您的编辑表明出于某种原因您没有使用 class
语法。 ) 您 可以 在 class 之后添加近方法,如下所示:
class Example {
// ...
}
然后在另一个模块中:
import Example from "./Example.js";
// (You'd probably have a utility method for this, `addMethod` or similar)
Object.defineProperty(Example.prototype, "methodName", {
value() {
// ...method implementation...
},
enumerable: false, // (You can leave this off, false is the default)
configurable: true,
writable: true,
});
但是像这样分散定义可能不是最佳实践,并且存在局限性,尤其是在子classes中(super
在以这种方式添加的方法中将不起作用super
在 class
定义中定义的方法中的方式)。 (您的编辑表明您没有使用 class
语法,因此这与您无关。)
所以我会坚持将 MyService
分解成更小的 class 可以组成的。
您可能想知道为什么我在上面使用 Object.defineProperty
,而不仅仅是:
Example.prototype.methodName = function() {
// ...
};
区别在于可枚举性。如果您使用这样的赋值添加方法,它会创建一个可枚举的 属性,但如果您使用 Object.defineProperty
,则不会,如上所示。我对 enumerable
、configurable
和 writable
使用与 class
定义在创建方法时使用的相同标志。这是差异的示例:
class A { }
Object.defineProperty(A.prototype, "example", {
value() {},
enumerable: false,
configurable: true,
writable: true,
});
class B { }
B.prototype.example = function() { };
const a = new A();
console.log(`typeof a.example = ${typeof a.example}`);
console.log(`a's enumerable non-Symbol properties:`);
let count = 0;
for (const name in a) {
console.log(`* ${name}`);
++count;
}
console.log(`Total: ${count}`);
const b = new B();
console.log(`typeof b.example = ${typeof b.example}`);
console.log(`b's enumerable non-Symbol properties:`);
count = 0;
for (const name in b) {
console.log(`* ${name}`);
++count;
}
console.log(`Total: ${count}`);
.as-console-wrapper {
max-height: 100% !important;
}
请注意 a
没有任何可枚举的属性,但 b
有——因为它继承了一个
我有一个 class,它变得很长。我已经确定了多个不同的概念,它们一起赋予了我 class.
意义"MyService" class 由:"auth", "storage", "数据库", ...概念。
我认为(也许我错了)在多个文件中定义 class“MyService”将是一个很好的重构。类似于:
MyService/MyService.js 从“./myService”导入我的服务;
export default function MyService() {
if(!isInitialized) {
myService.initializeApp(config);
// Only after doing myService.initializeApp(config);
this.auth = myService.auth();
this.storage = myService.storage();
this.database = myService.database();
isInitialized = true;
}
}
MyService/Auth.js
Add auth methods to MyService class prototype
MyService/Storage.js
Add storage methods to MyService class prototype
...
我该怎么做?这个技巧有name/exists吗?这是重构我的 class 的好方法吗?如果是,为什么?如果不是,那么,为什么?
谢谢。
更新
也许,将 class 拆分成更小的 classes 是最好的主意,但我不知道如何让它工作以访问 myService 功能, 这条线
myService.initializeApp(config);
之前必须在单例上执行过。
基于解决方案的示例
/* Simulate myService CLI SDK */
function myService() {}
myService.key = undefined;
myService.initializeApp = function (key) {
this.key = key;
}
myService.auth = function () {
if(!this.key) {
throw new Error("Please, initialize app");
}
console.log(`You have access to all auth methods! Key: ${this.key}`);
}
myService.storage = function () {
if(!this.key) {
throw new Error("Please, initialize app")
}
console.log(`You have access to all storage methods! Key: ${this.key}`);
}
/* Classes that compose the main class */
function Auth() {
this.auth = myService.auth();
}
Auth.prototype.login = function (username, password) {
console.log("Login!");
}
function Storage() {
this.storage = myService.storage();
}
Storage.prototype.uploadFile = function (file, path) {
console.log("Uploading file!")
}
/* Main class */
let isInitialized = false;
function Firebase() {
if(!isInitialized) { // Singleton
myService.initializeApp("raul");
this.auth = new Auth(); // Composition
this.storage = new Storage(); // Composition
isInitialized = true;
}
}
const f = new Firebase();
f.auth.login();
f.storage.uploadFile();
与其将 MyService
分散到多个模块中,不如将其分解成更小的 class。你说过:
"MyService" class is composed by: "auth", "storage", "database", ... concepts.
所以可能有一个 class 用于身份验证,另一个用于存储,另一个用于数据库,然后 MyService
使用其他 classes 的实例作为一部分它的实施。
您不能跨模块传播 (您的编辑表明出于某种原因您没有使用 class
定义。class
语法。 ) 您 可以 在 class 之后添加近方法,如下所示:
class Example {
// ...
}
然后在另一个模块中:
import Example from "./Example.js";
// (You'd probably have a utility method for this, `addMethod` or similar)
Object.defineProperty(Example.prototype, "methodName", {
value() {
// ...method implementation...
},
enumerable: false, // (You can leave this off, false is the default)
configurable: true,
writable: true,
});
但是像这样分散定义可能不是最佳实践,并且存在局限性,尤其是在子classes中(super
在以这种方式添加的方法中将不起作用super
在 class
定义中定义的方法中的方式)。 (您的编辑表明您没有使用 class
语法,因此这与您无关。)
所以我会坚持将 MyService
分解成更小的 class 可以组成的。
您可能想知道为什么我在上面使用 Object.defineProperty
,而不仅仅是:
Example.prototype.methodName = function() {
// ...
};
区别在于可枚举性。如果您使用这样的赋值添加方法,它会创建一个可枚举的 属性,但如果您使用 Object.defineProperty
,则不会,如上所示。我对 enumerable
、configurable
和 writable
使用与 class
定义在创建方法时使用的相同标志。这是差异的示例:
class A { }
Object.defineProperty(A.prototype, "example", {
value() {},
enumerable: false,
configurable: true,
writable: true,
});
class B { }
B.prototype.example = function() { };
const a = new A();
console.log(`typeof a.example = ${typeof a.example}`);
console.log(`a's enumerable non-Symbol properties:`);
let count = 0;
for (const name in a) {
console.log(`* ${name}`);
++count;
}
console.log(`Total: ${count}`);
const b = new B();
console.log(`typeof b.example = ${typeof b.example}`);
console.log(`b's enumerable non-Symbol properties:`);
count = 0;
for (const name in b) {
console.log(`* ${name}`);
++count;
}
console.log(`Total: ${count}`);
.as-console-wrapper {
max-height: 100% !important;
}
请注意 a
没有任何可枚举的属性,但 b
有——因为它继承了一个