如何在NodeJS模块中共享常量?
目前我正在这样做:
foo.js
const FOO = 5; module.exports = { FOO: FOO };  并在bar.js使用它: 
 var foo = require('foo'); foo.FOO; // 5 
有一个更好的方法吗? 在导出对象中声明常量感觉很尴尬。
 您可以使用global.FOO = 5将其显式导出到全局范围。 那么你只需要文件,甚至不保存你的返回值。 
但是,真的,你不应该这样做。 妥善封装是件好事。 你有正确的想法,所以继续做你在做什么。
 从技术上讲, const不是ECMAScript规范的一部分。 另外,使用你注意到的“CommonJS模块”模式,你可以改变这个“常量”的值,因为它现在只是一个对象属性。  (不知道这是否会改变其他脚本,需要相同的模块,但它是可能的) 
 为了得到一个真正的常量,你也可以分享,检查出Object.create , Object.defineProperty和Object.defineProperties 。 如果你设置writable: false ,那么你的“常数”中的值是不能修改的。  🙂 
 这有点冗长,(但即使这样可以改变一个小的JS),但你只需要为你的常量模块做一次。 使用这些方法,任何你离开的属性默认为false 。  (而不是通过赋值来定义属性,这将默认所有的属性为true ) 
 所以,假设你可以设置value和enumerable value ,因为它们默认为false ,所以enumerable writable和configurable ,为了清晰起见,我只是将它们包含在内。 
更新 – 我已经创build了一个新的模块( 节点常数 )与辅助函数为这个非常用例。
constants.js – 好
 Object.defineProperty(exports, "PI", { value: 3.14, enumerable: true, writable: false, configurable: false }); 
constants.js – 更好
 function define(name, value) { Object.defineProperty(exports, name, { value: value, enumerable: true }); } define("PI", 3.14); 
的script.js
 var constants = require("./constants"); console.log(constants.PI); // 3.14 constants.PI = 5; console.log(constants.PI); // still 3.14 
 在我看来,利用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' 
请注意,这两个设置可写为false,并使用Object.freeze在v8中有一个巨大的性能损失 – https://bugs.chromium.org/p/v8/issues/detail?id=1858和http://jsperf.com /性能冰冻对象
ES6的方式。
在foo.js中导出
 const FOO = 'bar'; module.exports = { FOO } 
导入bar.js
 const {FOO} = require('foo'); 
我发现Dominicbuild议的解决scheme是最好的解决scheme,但它仍然遗漏了“const”声明的一个特性。 当用“const”关键字在JS中声明一个常量时,在parsing时检查常量的存在,而不是在运行时检查。 所以如果你在代码的某个地方拼错了常量的名字,当你尝试启动你的node.js程序的时候会出现错误。 这是一个更好的错误检查。
如果使用像Dominic这样的define()函数来定义这个常量,那么如果拼错这个常量,那么你将不会得到一个错误,而且这个拼写错误的常量的值将会是未定义的(这会导致debugging头痛)。
但我想这是最好的,我们可以得到。
另外,在constans.js中,Dominic的函数有一些改进:
 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" ); 
或者,您可以将“常量”值分组到本地对象中,并导出一个函数,该函数返回此对象的浅表副本。
 var constants = { FOO: "foo" } module.exports = function() { return Object.assign({}, constants) } 
那么是否有人重新分配FOO并不重要,因为这只会影响他们的本地副本。
 由于Node.js使用的是CommonJS模式,所以你只能在模块之间共享variables,通过module.exports或者像在浏览器中一样设置一个全局variables,而不是使用你使用global.your_var = value;窗口global.your_var = value;  。 
我最终通过导出一个具有匿名getter函数的冻结对象而不是常量本身来做到这一点。 这减less了由于常量名称的简单拼写而引入的讨厌错误的风险,因为在错字的情况下将会抛出运行时错误。 这里是一个完整的例子,它也使用常量的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 }); 
从以前的项目经验来看,这是一个好方法:
在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); 
我build议用webpack来做 (假设你使用的是webpack)。
定义常量与设置webpackconfiguration文件一样简单:
 var webpack = require('webpack'); module.exports = { plugins: [ new webpack.DefinePlugin({ 'APP_ENV': '"dev"', 'process.env': { 'NODE_ENV': '"development"' } }) ], }; 
这样你就可以在你的源代码之外定义它们,它们将在你的所有文件中可用。
我不认为从模块入侵GLOBAL空间是一种好的做法,但是在可能严格需要实施的情况下:
 Object.defineProperty(global,'MYCONSTANT',{value:'foo',writable:false,configurable:false}); 
必须考虑到这种资源的影响。 如果没有对这些常数进行适当的命名,覆盖已经定义了全局variables的风险是真实的。