你如何在NodeJS模块中共享常量?

Tow*_*wer 216 javascript node.js

目前我这样做:

foo.js

const FOO = 5;

module.exports = {
    FOO: FOO
};
Run Code Online (Sandbox Code Playgroud)

并在bar.js以下方面使用它:

var foo = require('foo');
foo.FOO; // 5
Run Code Online (Sandbox Code Playgroud)

有一个更好的方法吗?在exports对象中声明常量会感觉很尴尬.

Spa*_*ain 266

在我看来,利用Object.freeze允许DRYer和更具说明性的风格.我的首选模式是:

./lib/constants.js

module.exports = Object.freeze({
    MY_CONSTANT: 'some value',
    ANOTHER_CONSTANT: 'another value'
});
Run Code Online (Sandbox Code Playgroud)

./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'
Run Code Online (Sandbox Code Playgroud)

过时的性能警告

以下问题已于2014年1月在v8中修复,并且与大多数开发人员不再相关:

请注意,将可写入设置为false并使用Object.freeze在v8中都会产生巨大的性能损失 - https://bugs.chromium.org/p/v8/issues/detail?id=1858http://jsperf.com /性能冰冻对象

  • 更新:此性能问题已在v8中修复. (18认同)
  • Object.freeze的好用例! (3认同)
  • 这种方法更好,因为IDE自动完成功能可以使用它. (3认同)
  • 这是一个很好的答案,但它可能会让人们远离这种方法,因为最后有关v8性能的过时警告.请考虑删除警告. (2认同)
  • 谢谢@Krumia!我已经更新了它,但是只留下了原始的警告文本用于历史背景(并且因为如果没有它,其中一些评论就没有意义). (2认同)

Dom*_*nes 160

从技术上讲,const它不是ECMAScript规范的一部分.此外,使用您注意到的"CommonJS模块"模式,您可以更改"常量"的值,因为它现在只是一个对象属性.(不确定是否会将任何更改级联到需要相同模块的其他脚本,但这是可能的)

要获得真正的常数,你也可以分享,看看Object.create,Object.definePropertyObject.defineProperties.如果设置writable: false,则无法修改"常量"中的值.:)

它有点冗长,(但即使可以用一点JS来改变)但你应该只为你的常量模块做一次.使用这些方法,您省略的任何属性都默认为false.(而不是通过赋值定义属性,默认所有属性true)

所以,假设你可以设置,value并且enumerable离开writable,configurable因为他们将默认false,我只是为了清楚而包括它们.

更新 - 我为这个用例创建了一个带有辅助函数的新模块(node-constants).

constants.js - 很好

Object.defineProperty(exports, "PI", {
    value:        3.14,
    enumerable:   true,
    writable:     false,
    configurable: false
});
Run Code Online (Sandbox Code Playgroud)

constants.js - 更好

function define(name, value) {
    Object.defineProperty(exports, name, {
        value:      value,
        enumerable: true
    });
}

define("PI", 3.14);
Run Code Online (Sandbox Code Playgroud)

的script.js

var constants = require("./constants");

console.log(constants.PI); // 3.14
constants.PI = 5;
console.log(constants.PI); // still 3.14
Run Code Online (Sandbox Code Playgroud)

  • 另外值得注意的是,Object.freeze() (6认同)
  • @AntoineHedgecock没有必要,查看[`Object.defineProperty()`](https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/defineProperty)上的文档.在此上下文中,未指定的所有属性都假定为"false". (2认同)

Die*_*llo 84

ES6的方式.

在foo.js中导出

const FOO = 'bar';
module.exports = {
  FOO
}
Run Code Online (Sandbox Code Playgroud)

在bar.js中导入

const {FOO} = require('foo');
Run Code Online (Sandbox Code Playgroud)

  • 是.Stack Overflow需要一种方法来折旧过时的答案. (31认同)
  • 请注意,`bar.js`中的`const`强制执行destructured变量的不变性,而不是`foo.js`中的`const`.也就是说,可以在`bar.js`中使用`let {FOO} =`并改变"常量"变量.AFAIK,为了强制出口的不变性,仍然需要ES模块或`Object.freeze`. (7认同)

Ale*_*yne 83

您可以使用显式将其导出到全局范围global.FOO = 5.然后你只需要要求文件,甚至不保存你的返回值.

但实际上,你不应该这样做.保持正确封装的东西是一件好事.你已经有了正确的想法,所以继续做你正在做的事情.

  • 我很抱歉这样做,但-1知道更好,但没有提供替代(更好)的解决方案; (重新:"但实际上,你不应该这样做.保持正确封装的东西是一件好事.") (44认同)
  • 如果整个软件开发社区以这种方式思考,我们仍然会使用punchards.幸运的是,有一些小牛在那里知道什么时候最好打破我们对自己施加的疯狂规则.如果封装很有用,请使用它.如果这是一个紧张的保姆阻止你做你的工作,解雇紧张的保姆并继续下去. (20认同)
  • @naomik(超级回复时间)我没有提供更好的解决方案的真正原因是因为OP已经知道解决方案.将事物封装在自己的模块中,并在必要时需要它们. (19认同)
  • 那么这不是一个实际的答案,而应该是一个解释性评论,说明“你做得足够好,替代品很糟糕”.. (2认同)

小智 15

我发现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;
Run Code Online (Sandbox Code Playgroud)

通过这种方式,您可以在其他模块中使用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
Run Code Online (Sandbox Code Playgroud)

第二:

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
Run Code Online (Sandbox Code Playgroud)

另外,如果你想只从constants模块调用define()函数(不要膨胀全局对象),你可以在constants.js中定义它:

exports.define = function ( name, value, exportsObject )
Run Code Online (Sandbox Code Playgroud)

并在script.js中使用它:

constants.define( 'SOME_CONSTANT', "const value 1" );
Run Code Online (Sandbox Code Playgroud)


Man*_*ddy 10

根据以前的项目经验,这是一个好方法:

在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
Run Code Online (Sandbox Code Playgroud)

在main.js(或app.js等)中,如下使用它:

// main.js

let constants = require('./constants');

console.log(constants.key1);

console.dir(constants.key3);
Run Code Online (Sandbox Code Playgroud)


atr*_*eon 10

importexport(可能需要像 2018 年的 babel 一样使用导入)

类型.js

export const BLUE = 'BLUE'
export const RED = 'RED'
Run Code Online (Sandbox Code Playgroud)

我的应用程序

import * as types from './types.js'

const MyApp = () => {
  let colour = types.RED
}
Run Code Online (Sandbox Code Playgroud)

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import


Lui*_*ins 6

我认为这const可以解决大多数寻求此问题的人的问题。如果您确实需要一个不变的常数,请查看其他答案。为了使所有内容井井有条,我将所有常量保存在一个文件夹中,然后需要整个文件夹。

src / main.js文件

const constants = require("./consts_folder");
Run Code Online (Sandbox Code Playgroud)

src / consts_folder / index.js

const deal = require("./deal.js")
const note = require("./note.js")


module.exports = {
  deal,
  note
}
Run Code Online (Sandbox Code Playgroud)

附言 在这里,dealand note将是main.js的第一层

src / consts_folder / note.js

exports.obj = {
  type: "object",
  description: "I'm a note object"
}
Run Code Online (Sandbox Code Playgroud)

附言 obj将成为main.js的第二级

src / consts_folder / deal.js

exports.str = "I'm a deal string"
Run Code Online (Sandbox Code Playgroud)

附言 str将成为main.js的第二级

main.js文件的最终结果:

console.log(constants.deal); 输出:

{deal:{str:'I \'ma deal string'},

console.log(constants.note); 输出:

注意:{obj:{类型:“对象”,描述:“ I \'ma note对象”}}


her*_*man 5

作为替代方案,您可以将“常量”值分组到本地对象中,并导出返回该对象的浅克隆的函数。

var constants = { FOO: "foo" }

module.exports = function() {
  return Object.assign({}, constants)
}
Run Code Online (Sandbox Code Playgroud)

那么如果有人重新分配 FOO 也没关系,因为它只会影响他们的本地副本。