我想在 class
中实现常量,因为这是在代码中定位它们的意义所在。
到目前为止,我一直在使用静态方法实现以下解决方法:
class MyClass {
static constant1() { return 33; }
static constant2() { return 2; }
// ...
}
我知道有可能摆弄原型,但许多人建议不要这样做。
有没有更好的方法在 ES6 类中实现常量?
以下是您可以做的几件事:
从 模块 导出一个 const
。根据您的用例,您可以:
export const constant1 = 33;
并在必要时从模块中导入。或者,基于您的静态方法理念,您可以声明一个 static
get accessor:
const constant1 = 33,
constant2 = 2;
class Example {
static get constant1() {
return constant1;
}
static get constant2() {
return constant2;
}
}
这样,您将不需要括号:
const one = Example.constant1;
然后,正如您所说,由于 class
只是函数的语法糖,您可以添加一个不可写属性,如下所示:
class Example {
}
Object.defineProperty(Example, 'constant1', {
value: 33,
writable : false,
enumerable : true,
configurable : false
});
Example.constant1; // 33
Example.constant1 = 15; // TypeError
如果我们可以做类似的事情可能会很好:
class Example {
static const constant1 = 33;
}
但不幸的是,这个 class property syntax 仅在 ES7 提案中,即使那样它也不允许将 const
添加到属性中。
class Whatever {
static get MyConst() { return 10; }
}
let a = Whatever.MyConst;
似乎对我有用。
Whatever
实例中使用 this.MyConst
,因此您必须始终这样编写:Whatever.MyConst
我正在使用 babel
并且以下语法对我有用:
class MyClass {
static constant1 = 33;
static constant2 = {
case1: 1,
case2: 2,
};
// ...
}
MyClass.constant1 === 33
MyClass.constant2.case1 === 1
请考虑您需要预设 "stage-0"
。
要安装它:
npm install --save-dev babel-preset-stage-0
// in .babelrc
{
"presets": ["stage-0"]
}
更新:
当前使用 stage-3
stage-2
Object.freeze()
会解决这个问题吗?
在 this document 中它指出:
(故意)没有直接的声明方式来定义原型数据属性(方法除外)类属性或实例属性
这意味着它是故意这样的。
也许你可以在构造函数中定义一个变量?
constructor(){
this.key = value
}
也可以在您的 class(es6)/constructor function(es5) 对象上使用 Object.freeze
以使其不可变:
class MyConstants {}
MyConstants.staticValue = 3;
MyConstants.staticMethod = function() {
return 4;
}
Object.freeze(MyConstants);
// after the freeze, any attempts of altering the MyConstants class will have no result
// (either trying to alter, add or delete a property)
MyConstants.staticValue === 3; // true
MyConstants.staticValue = 55; // will have no effect
MyConstants.staticValue === 3; // true
MyConstants.otherStaticValue = "other" // will have no effect
MyConstants.otherStaticValue === undefined // true
delete MyConstants.staticMethod // false
typeof(MyConstants.staticMethod) === "function" // true
试图改变类会给你一个软失败(不会抛出任何错误,它根本没有效果)。
Object.freeze()
强制执行不变性,并且最近一直在使用它。只是不要忘记递归应用它!
也许只是把你所有的常量放在一个冻结的对象中?
class MyClass {
constructor() {
this.constants = Object.freeze({
constant1: 33,
constant2: 2,
});
}
static get constant1() {
return this.constants.constant1;
}
doThisAndThat() {
//...
let value = this.constants.constant2;
//...
}
}
您可以使用 ES6 类的奇怪特性创建一种在类上定义静态常量的方法。由于静态是由其子类继承的,因此您可以执行以下操作:
const withConsts = (map, BaseClass = Object) => {
class ConstClass extends BaseClass { }
Object.keys(map).forEach(key => {
Object.defineProperty(ConstClass, key, {
value: map[key],
writable : false,
enumerable : true,
configurable : false
});
});
return ConstClass;
};
class MyClass extends withConsts({ MY_CONST: 'this is defined' }) {
foo() {
console.log(MyClass.MY_CONST);
}
}
正如 https://stackoverflow.com/users/2784136/rodrigo-botti 所说,我认为您正在寻找 Object.freeze()
。这是一个具有不可变静态的类的示例:
class User {
constructor(username, age) {
if (age < User.minimumAge) {
throw new Error('You are too young to be here!');
}
this.username = username;
this.age = age;
this.state = 'active';
}
}
User.minimumAge = 16;
User.validStates = ['active', 'inactive', 'archived'];
deepFreeze(User);
function deepFreeze(value) {
if (typeof value === 'object' && value !== null) {
Object.freeze(value);
Object.getOwnPropertyNames(value).forEach(property => {
deepFreeze(value[property]);
});
}
return value;
}
我这样做了。
class Circle
{
constuctor(radius)
{
this.radius = radius;
}
static get PI()
{
return 3.14159;
}
}
PI 的值不会被更改,因为它是从函数返回的值。您可以通过 Circle.PI 访问它。任何分配给它的尝试都会以类似于尝试通过 [] 分配给字符串字符的方式简单地丢弃在地板上。
您可以通过冻结类将“常量”设为只读(不可变)。例如
class Foo {
static BAR = "bat"; //public static read-only
}
Object.freeze(Foo);
/*
Uncaught TypeError: Cannot assign to read only property 'BAR' of function 'class Foo {
static BAR = "bat"; //public static read-only
}'
*/
Foo.BAR = "wut";
Object.freeze()
的不可变属性之外的可变类属性,只需将它们包装到某个可变对象中即可。示例:代替 class Cnt { static __cnt=0; get uniq() { return ++Cnt.__cnt } }; Object.freeze(Cnt)
执行 class Cnt { static __var={cnt:0}; get uniq() { return ++Cnt.__var.cnt } }; Object.freeze(Cnt)
这是您可以做的另一种方法
/* 在类中声明常量的另一种方法,注意 - 必须在定义类之后声明常量 */ class Auto{ //其他方法 } Auto.CONSTANT1 = "const1"; Auto.CONSTANT2 = "const2"; console.log(Auto.CONSTANT1) console.log(Auto.CONSTANT2);
注意 - 顺序很重要,你不能有上面的常量
用法
console.log(Auto.CONSTANT1);
您可以使用 import * as
语法。虽然不是一个类,但它们是真正的 const
变量。
常量.js
export const factor = 3;
export const pi = 3.141592;
index.js
import * as Constants from 'Constants.js'
console.log( Constants.factor );
我发现的最简洁的方法是使用 TypeScript - 请参阅 How to implement class constants?
class MyClass {
static readonly CONST1: string = "one";
static readonly CONST2: string = "two";
static readonly CONST3: string = "three";
}
MyClass['CO'+'NST1']='bug'
仍然会更改常量! readonly
只是编译时的糖,因为 Typescript 编译器不能神奇地从无到有地创建不可变的类属性。 因此,编译器既不保护它不理解的任何东西,也不保护运行时不被意外更改。 更糟糕的是:你可能认为你受到保护,但实际上并没有!(YMMV ,来自 Ubuntu 20.04 的经过测试的 Typescript 编译器显然不使用 Object.freeze()
)
如果试图使一个类的常量/变量静态;尝试使用哈希 (#) 来定义占位符,而不是使用函数来访问它。
class Region {
// initially empty, not accessible from outside
static #empty_region = null;
/*
Make it visible to the outside and unchangeable
[note] created on first call to getter.
*/
static EMPTY() {
if (!this.#empty_region)
this.#empty_region = new Region(0, 0, 0, 0);
return this.#empty_region;
}
#reg = {x0:0, y0:0, x1:0, y1:0};
constructor(x0, y0, x1, y1) {
this.setRegion(x0, y0, x1, y1);
}
// setters/getters
}
执行:
let someRegion = Region.EMPTY();
let anotherRegion = Region.EMPTY();
只需将您的变量声明为私有并使用 get 方法来检索它们。
class MyClass {
#myConst = 'Something';
static #anotherConst = 'Something Else';
get myConst() {
return this.#myConst; // instance method
}
static get anotherConst() {
return MyClass.#anotherConst; // static method
}
}
let myClass = new MyClass();
console.log( myClass.myConst + ' is not ' + MyClass.anotherConst );
用户无法更改原始变量,您可以编写类以使用 get 方法而不是私有变量本身。
如果您喜欢在函数和类语法之间混合和匹配,您可以在类之后声明常量(常量被“提升”)。请注意,Visual Studio Code 将难以自动格式化混合语法(尽管它有效)。
class MyClass { // ... } MyClass.prototype.consts = { constant1: 33, constant2: 32 }; mc = new MyClass();控制台.log(mc.consts.constant2);
添加其他答案,您需要导出类以在不同的类中使用。这是它的打字稿版本。
//Constants.tsx const DEBUG: boolean = true;导出类常量 { static get DEBUG(): boolean { return DEBUG; } } //Anotherclass.tsx import { Constants } from "Constants"; if (Constants.DEBUG) { console.log("调试模式") }
干得好!
const Status = Object.freeze(class Status {
static Disabled = 0
static Live = 1
})
不定期副业成功案例分享
super
关键字不仅仅是语法糖