目前我正在这样做:
foo.js
const FOO = 5;
module.exports = {
FOO: FOO
};
在bar.js
中使用它:
var foo = require('foo');
foo.FOO; // 5
有更好的方法吗?在exports对象中声明常量会感觉很尴尬。
答案 0 :(得分:238)
在我看来,利用Object.freeze
允许DRYer和更具说明性的风格。我的首选模式是:
./lib/constants.js
module.exports = Object.freeze({
MY_CONSTANT: 'some value',
ANOTHER_CONSTANT: 'another value'
});
./lib/some-module.js
var constants = require('./constants');
console.log(constants.MY_CONSTANT); // 'some value'
constants.MY_CONSTANT = 'some other value';
console.log(constants.MY_CONSTANT); // 'some value'
以下问题已于2014年1月在v8中修复,与大多数开发人员不再相关:
请注意,将可写入设置为false并使用Object.freeze在v8中都会造成巨大的性能损失 - https://bugs.chromium.org/p/v8/issues/detail?id=1858和http://jsperf.com/performance-frozen-object
答案 1 :(得分:156)
从技术上讲,const
不是ECMAScript规范的一部分。此外,使用您注意到的“CommonJS模块”模式,您可以更改“常量”的值,因为它现在只是一个对象属性。 (不确定是否会将所有更改级联到需要相同模块的其他脚本,但这是可能的)
要获得您也可以分享的真实常量,请查看Object.create
,Object.defineProperty
和Object.defineProperties
。如果设置writable: false
,则无法修改“常量”中的值。 :)
它有点冗长,(但即使可以用一点JS来改变)但是你应该只为你的常量模块做一次。使用这些方法,您省略的任何属性都默认为false
。 (而不是通过赋值定义属性,将所有属性默认为true
)
因此,假设您可以设置value
和enumerable
,而不会writable
和configurable
,因为它们默认为false
,我为了清楚起见,我们只是将它们包括在内。
更新 - 我为这个用例创建了一个带有辅助函数的新模块(node-constants)。
Object.defineProperty(exports, "PI", {
value: 3.14,
enumerable: true,
writable: false,
configurable: false
});
function define(name, value) {
Object.defineProperty(exports, name, {
value: value,
enumerable: true
});
}
define("PI", 3.14);
var constants = require("./constants");
console.log(constants.PI); // 3.14
constants.PI = 5;
console.log(constants.PI); // still 3.14
答案 2 :(得分:73)
您可以使用global.FOO = 5
将其明确导出到全局范围。然后你只需要要求文件,甚至不保存你的返回值。
但实际上,你不应该这样做。保持正确封装的东西是一件好事。你已经有了正确的想法,所以继续做你正在做的事情。
答案 3 :(得分:69)
ES6方式。
在foo.js中导出
const FOO = 'bar';
module.exports = {
FOO
}
导入bar.js
const {FOO} = require('foo');
答案 4 :(得分:15)
我发现Dominic建议的解决方案是最好的,但它仍然错过了“const”声明的一个特性。当您使用“const”关键字在JS中声明常量时,将在分析时检查常量的存在,而不是在运行时。因此,如果您在代码中稍后某处拼错了常量的名称,则在尝试启动node.js程序时会出现错误。这是一个更好的拼写错误检查。
如果使用像Dominic建议的define()函数定义常量,如果拼错常量,则不会出现错误,并且拼写错误常量的值将是未定义的(这可能导致调试问题)。
但我想这是我们能得到的最好的。
此外,这是对constans函数的一种改进,在constans.js中:
global.define = function ( name, value, exportsObject )
{
if ( !exportsObject )
{
if ( exports.exportsObject )
exportsObject = exports.exportsObject;
else
exportsObject = exports;
}
Object.defineProperty( exportsObject, name, {
'value': value,
'enumerable': true,
'writable': false,
});
}
exports.exportObject = null;
通过这种方式,您可以在其他模块中使用define()函数,它允许您在constants.js模块内部定义常量,并在模块内部定义您调用该函数的常量。然后可以通过两种方式(在script.js中)声明模块常量。
首先:
require( './constants.js' );
define( 'SOME_LOCAL_CONSTANT', "const value 1", this ); // constant in script.js
define( 'SOME_OTHER_LOCAL_CONSTANT', "const value 2", this ); // constant in script.js
define( 'CONSTANT_IN_CONSTANTS_MODULE', "const value x" ); // this is a constant in constants.js module
第二
constants = require( './constants.js' );
// More convenient for setting a lot of constants inside the module
constants.exportsObject = this;
define( 'SOME_CONSTANT', "const value 1" ); // constant in script.js
define( 'SOME_OTHER_CONSTANT', "const value 2" ); // constant in script.js
另外,如果你想只从constants模块调用define()函数(不要膨胀全局对象),你可以在constants.js中这样定义它:
exports.define = function ( name, value, exportsObject )
并在script.js中使用它:
constants.define( 'SOME_CONSTANT', "const value 1" );
答案 5 :(得分:8)
从以前的项目经验来看,这是一个很好的方法:
在constants.js中:
// constants.js
'use strict';
let constants = {
key1: "value1",
key2: "value2",
key3: {
subkey1: "subvalue1",
subkey2: "subvalue2"
}
};
module.exports =
Object.freeze(constants); // freeze prevents changes by users
在main.js(或app.js等)中,使用如下:
// main.js
let constants = require('./constants');
console.log(constants.key1);
console.dir(constants.key3);
答案 6 :(得分:5)
我认为const
解决了大多数寻找这个问题的人的问题。如果你真的需要一个不可变的常量,请查看其他答案。
为了保持一切有条理,我将所有常量保存在一个文件夹中,然后需要整个文件夹。
src / main.js文件
const constants = require("./consts_folder");
的src / consts_folder / index.js
const deal = require("./deal.js")
const note = require("./note.js")
module.exports = {
deal,
note
}
聚苯乙烯。这里deal
和note
将是main.js的第一级
的src / consts_folder / note.js
exports.obj = {
type: "object",
description: "I'm a note object"
}
聚苯乙烯。 obj
将是main.js上的第二级
的src / consts_folder / deal.js
exports.str = "I'm a deal string"
聚苯乙烯。 str
将是main.js上的第二级
main.js文件的最终结果:
console.log(constants.deal);
输出继电器:
{deal:{str:'我是一个交易字符串'},
console.log(constants.note);
输出继电器:
注意:{obj:{type:'object',描述:'我是一个音符对象'}}
答案 7 :(得分:3)
作为替代方案,您可以对"常数"进行分组。本地对象中的值,并导出一个返回此对象的浅层克隆的函数。
var constants = { FOO: "foo" }
module.exports = function() {
return Object.assign({}, constants)
}
如果有人重新分配FOO,那将无关紧要,因为它只会影响他们的本地副本。
答案 8 :(得分:3)
import
和export
(问题需要像2018年的babel一样使用导入)
types.js
export const BLUE = 'BLUE'
export const RED = 'RED'
myApp.js
import * as types from './types.js'
const MyApp = () => {
let colour = types.RED
}
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import
答案 9 :(得分:2)
由于Node.js正在使用CommonJS模式,您只能在module.exports
模块之间共享变量,或者像在浏览器中那样设置全局变量,而不是使用窗口,而是使用{{1} }。
答案 10 :(得分:1)
我最终通过导出具有匿名getter函数的冻结对象而不是常量本身来完成此操作。这降低了由于const名称的简单错误引入的令人讨厌的错误的风险,因为在输入错误的情况下将抛出运行时错误。这是一个完整的例子,它也使用ES6符号表示常量,确保唯一性和ES6箭头功能。如果这种方法中的任何内容似乎都有问题,我们会很感激。
'use strict';
const DIRECTORY = Symbol('the directory of all sheets');
const SHEET = Symbol('an individual sheet');
const COMPOSER = Symbol('the sheet composer');
module.exports = Object.freeze({
getDirectory: () => DIRECTORY,
getSheet: () => SHEET,
getComposer: () => COMPOSER
});
答案 11 :(得分:0)
我建议使用webpack(假设您正在使用webpack)。
定义常量就像设置webpack配置文件一样简单:
var webpack = require('webpack');
module.exports = {
plugins: [
new webpack.DefinePlugin({
'APP_ENV': '"dev"',
'process.env': {
'NODE_ENV': '"development"'
}
})
],
};
这样您就可以在源代码之外定义它们,并且它们将在您的所有文件中可用。
答案 12 :(得分:0)
我认为从模块入侵GLOBAL空间是一种很好的做法,但在实施它的情况下可能是绝对必要的:
Object.defineProperty(global,'MYCONSTANT',{value:'foo',writable:false,configurable:false});
必须考虑此资源的影响。如果没有正确命名这些常量,那么OVERWRITTING已经定义的全局变量的风险就是真实的。