目前,我正在这样做:
foo.js
const FOO = 5;
module.exports = {
FOO: FOO
};
并在中使用它bar.js
:
var foo = require('foo');
foo.FOO; // 5
有一个更好的方法吗?在exports对象中声明常量感觉很尴尬。
export const FOO = 5;
。
module.exports={FOO:5};
吗?
目前,我正在这样做:
foo.js
const FOO = 5;
module.exports = {
FOO: FOO
};
并在中使用它bar.js
:
var foo = require('foo');
foo.FOO; // 5
有一个更好的方法吗?在exports对象中声明常量感觉很尴尬。
export const FOO = 5;
。
module.exports={FOO:5};
吗?
Answers:
您可以使用将其显式导出到全局范围global.FOO = 5
。然后,您只需要提供文件,甚至不保存您的返回值。
但实际上,您不应该这样做。保持适当封装是一件好事。您已经有了正确的想法,因此请继续做您正在做的事情。
在我看来,利用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 /性能冻结对象
从技术上讲 const
它不是ECMAScript规范的一部分。另外,使用您注意到的“ CommonJS Module”模式,您可以更改该“ constant”的值,因为它现在只是一个对象属性。(不确定是否会将对同一脚本的其他更改进行级联,但是有可能)
要获得真正的常数,你也可以分享,看看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
Object.defineProperty()
。false
在此上下文中假定所有未指定的属性。
我发现Dominic建议的解决方案是最好的解决方案,但它仍然缺少“ const”声明的一项功能。当您使用“ const”关键字在JS中声明一个常量时,将在解析时而不是在运行时检查该常量的存在。因此,如果您稍后在代码中的某个地方拼写了常量的名称,则在尝试启动node.js程序时会收到错误消息。这是一个更好的拼写检查。
如果使用像Dominic建议的define()函数定义常量,则如果拼写错误的常量将不会出错,并且拼写错误的常量的值将是未定义的(这可能导致调试麻烦)。
但是我想这是我们能得到的最好的结果。
另外,这是对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
另外,如果只希望从常量模块调用define()函数(而不是膨胀全局对象),则可以在constants.js中这样定义它:
exports.define = function ( name, value, exportsObject )
并在script.js中像这样使用它:
constants.define( 'SOME_CONSTANT', "const value 1" );
根据以前的项目经验,这是一个好方法:
在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);
我认为这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
and 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:'I \'ma deal string'},
console.log(constants.note);
输出:
注意:{obj:{类型:“对象”,描述:“ I \'ma note对象”}}
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/zh-CN/docs/Web/JavaScript/Reference/Statements/import
最后,我通过导出具有匿名getter函数而不是常量本身的冻结对象来完成此操作。这减少了由于const名称的简单错字而引入的令人讨厌的bug的风险,因为如果遇到错字,将抛出运行时错误。这是一个完整的示例,该示例还将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
});
exports
。这有什么尴尬?