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

2020/10/10 07:01 · javascript ·  · 0评论

目前,我正在这样做:

foo.js

const FOO = 5;

module.exports = {
    FOO: FOO
};

并在中使用它bar.js

var foo = require('foo');
foo.FOO; // 5

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

您可以使用将其显式导出到全局范围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=1858http://jsperf.com /性能冻结对象

从技术上讲,const它不是ECMAScript规范的一部分。同样,使用您注意到的“ CommonJS Module”模式,您可以更改该“ constant”的值,因为它现在只是一个对象属性。(不确定是否会将对同一脚本的其他更改进行级联,但是有可能)

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

这有点冗长(但即使使用一点JS也可以更改),但是您只需为常量模块执行一次即可。使用这些方法,您遗漏的任何属性都默认为false(与通过赋值定义属性相反,后者将所有属性默认为true

因此,假设地,您可以设置valueenumerable,省去writableconfigurable由于它们将默认设置为false,为了清楚起见,我仅将它们包括在内。

更新-针对这个用例,我已经创建了一个带有辅助功能的新模块(node-constants)。

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

ES6方式。

在foo.js中导出

const FOO = 'bar';
module.exports = {
  FOO
}

导入bar.js

const {FOO} = require('foo');

我发现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
}

附言 dealnote将是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对象”}}

importexport(自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

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

var constants = { FOO: "foo" }

module.exports = function() {
  return Object.assign({}, constants)
}

那么,是否有人重新分配FOO无关紧要,因为这只会影响其本地副本。

由于Node.js使用的是CommonJS模式,因此只能module.exports像在浏览器中那样使用或通过设置全局变量来在模块之间共享变量,而不能使用窗口global.your_var = value;

最后,我导出了一个带有匿名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
});

我建议使用webpack进行此操作(假设您正在使用webpack)。

定义常量就像设置webpack配置文件一样简单:

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});

必须考虑该资源的影响。如果没有正确命名这些常量,那么覆盖已定义的全局变量的风险确实存在。

本文地址:http://javascript.askforanswer.com/ruhezainodejsmokuaizhonggongxiangchangliang.html
文章标签: ,  
版权声明:本文为原创文章,版权归 javascript 所有,欢迎分享本文,转载请保留出处!

文件下载

老薛主机终身7折优惠码boke112

上一篇:
下一篇:

评论已关闭!