我希望在一个class
中实现常量,因为这是将常量放置在代码中的合理位置。
到目前为止,我一直在使用静态方法来实现以下解决方案:
class MyClass {
static constant1() { return 33; }
static constant2() { return 2; }
// ...
}
我知道可以在原型中进行更改,但是很多人建议不要这样做。
在ES6类中实现常量有更好的方法吗?
我希望在一个class
中实现常量,因为这是将常量放置在代码中的合理位置。
到目前为止,我一直在使用静态方法来实现以下解决方案:
class MyClass {
static constant1() { return 33; }
static constant2() { return 2; }
// ...
}
我知道可以在原型中进行更改,但是很多人建议不要这样做。
在ES6类中实现常量有更好的方法吗?
这里有几件事情可以做:
从 模块 中导出一个const
。根据你的使用情况,你可以只需:
export const constant1 = 33;
在必要的模块中导入它。或者,基于您的静态方法的想法,您可以声明一个static
get访问器:
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;
}
但是不幸的是,这个类属性语法仅存在于ES7提案中,而且即使如此,它也不能允许在属性中添加const
。
class Whatever {
static get MyConst() { return 10; }
}
let a = Whatever.MyConst;
对我来说似乎有效。
Whatever
实例内部使用 this.MyConst
,您必须始终像这样编写:Whatever.MyConst
。 - Chunky Chunkstatic set MyConst(value) { throw new Error('cannot redefine constant'); }
,以避免 @jave.web提到的静默错误。 - jbuhacoffObject.defineProperty
让我实现了类似于 Java 常量的功能,非常不错。 - FtheBuilder我正在使用 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
。
Babel 7 更新:
根据 Babel 7 的官方声明,阶段预设(stage presets)已被弃用。
使用的 Babel 插件是@babel/plugin-proposal-class-properties
。
npm i --save-dev @babel/plugin-proposal-class-properties
{
"plugins": ["@babel/plugin-proposal-class-properties"]
}
注意: 此插件已包含在 @babel/preset-env 中。
stage-2
阶段。 - bmaupinObject.freeze()
方法能解决这个问题吗? - Antimony在这篇文档中,它说:
意图上不存在直接的声明方式来定义原型数据属性(方法以外的其他属性),类属性或实例属性。
这意味着这是故意这样的。
也许你可以在构造函数中定义一个变量?
constructor(){
this.key = value
}
你也可以在你的类(es6)/构造函数(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()
来强制实现不可变性,并且最近一直在大量使用它。只是不要忘记递归应用它! - jeffwtribbleclass 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);
}
}
这里还有一种方法可以实现
/*
one more way of declaring constants in a class,
Note - the constants have to be declared after the class is defined
*/
class Auto{
//other methods
}
Auto.CONSTANT1 = "const1";
Auto.CONSTANT2 = "const2";
console.log(Auto.CONSTANT1)
console.log(Auto.CONSTANT2);
console.log(Auto.CONSTANT1);
就像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 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)
。 - Tino