Как вы делитесь константами в модулях NodeJS?

В настоящее время я делаю это:

foo.js

const FOO = 5;

module.exports = {
    FOO: FOO
};

И используя его в bar.js:

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

Есть ли лучший способ сделать это? Это неудобно объявлять константу в объекте экспорта.

Ответ 1

Вы можете явно экспортировать его в глобальную область с помощью global.FOO = 5. Затем вам просто нужно потребовать файл, и даже не сохранить возвращаемое значение.

Но на самом деле вы не должны этого делать. Хранение вещей правильно инкапсулировано - это хорошо. У вас уже есть правильная идея, поэтому продолжайте делать то, что вы делаете.

Ответ 2

На мой взгляд, использование 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'

Предупреждение об устаревших показателях производительности

Следующая проблема была исправлена в версии 8 в январе 2014 года и больше не относится к большинству разработчиков:

Имейте в виду, что оба параметра для записи в false и использование Object.freeze имеют значительное ограничение производительности в v8 - https://bugs.chromium.org/p/v8/issues/detail?id=1858 и http://jsperf.com/производительность заморозка-объект

Ответ 3

Технически const не входит в спецификацию ECMAScript. Кроме того, используя шаблон "CommonJS Module", который вы отметили, вы можете изменить значение этой "константы", так как теперь это просто свойство объекта. (не уверен, что это каскадирует любые изменения в других сценариях, которые требуют того же модуля, но это возможно)

Чтобы получить реальную константу, которую вы также можете использовать, посмотрите Object.create, Object.defineProperty и Object.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
});

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

Ответ 4

путь ES6.

экспорт в foo.js

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

import в bar.js

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

Ответ 5

Я нашел решение, предложенное Домиником, было лучшим, но оно все еще пропускает одну особенность объявления "const". Когда вы объявляете константу в JS с ключевым словом "const", существование константы проверяется во время разбора, а не во время выполнения. Поэтому, если вы ошибочно написали имя константы где-нибудь позже в своем коде, вы получите сообщение об ошибке при попытке запустить вашу программу node.js. Это гораздо лучше, чем проверка орфографических ошибок.

Если вы определяете константу с помощью функции define(), например, предложенной Dominic, вы не получите ошибку, если вы ошибочно написали константу, а значение константы с ошибкой будет undefined (что может привести к отладке головных болей).

Но я думаю, это лучшее, что мы можем получить.

Кроме того, здесь вид улучшения функции Dominic, в 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

Кроме того, если вы хотите, чтобы функция define() вызывалась только из модуля констант (а не для раздувания глобального объекта), вы определяете его так: constants.js:

exports.define = function ( name, value, exportsObject )

и используйте его как в script.js:

constants.define( 'SOME_CONSTANT', "const value 1" );

Ответ 6

В качестве альтернативы вы можете группировать свои "постоянные" значения в локальном объекте и экспортировать функцию, которая возвращает неглубокий клон этого объекта.

var constants = { FOO: "foo" }

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

Тогда не имеет значения, кто-то переустанавливает FOO, потому что это повлияет только на их локальную копию.

Ответ 7

Так как Node.js использует шаблоны CommonJS, вы можете делиться только переменными между модулями с помощью module.exports или путем установки глобального var, как в браузере, но вместо использования окна вы используете global.your_var = value;.

Ответ 8

Из предыдущего опыта проекта это хороший способ:

В константах .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);

Ответ 9

Я думаю, что 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
}

Ps. здесь deal и note будут первым уровнем на main.js

SRC/consts_folder/note.js

exports.obj = {
  type: "object",
  description: "I'm a note object"
}

Ps. obj будет вторым уровнем на main.js

SRC/consts_folder/deal.js

exports.str = "I'm a deal string"

Ps. str будет вторым уровнем на main.js

Конечный результат в файле main.js:

console.log(constants.deal); Ouput:

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

console.log(constants.note); Ouput:

note: {obj: {type: 'object', description: 'I \' ma note object '}}

Ответ 10

Я закончил это, экспортировав замороженный объект с анонимными функциями getter, а не самими константами. Это уменьшает риск появления неприятных ошибок из-за простой опечатки имени const, так как в случае опечатки будет выбрана ошибка времени выполнения. Здесь приведен полный пример, который также использует символы ES6 для констант, обеспечивая уникальность и функции ES6 arrow. Поблагодарили бы обратную связь, если что-либо в этом подходе кажется проблематичным.

'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

Я рекомендую сделать это с помощью webpack (предполагается, что вы используете webpack).

Определение констант так же просто, как установка файла конфигурации webpack:

var webpack = require('webpack');
module.exports = {
    plugins: [
        new webpack.DefinePlugin({
            'APP_ENV': '"dev"',
            'process.env': {
                'NODE_ENV': '"development"'
            }
        })
    ],    
};

Таким образом вы определяете их вне своего источника, и они будут доступны во всех ваших файлах.

Ответ 12

Я не думаю, что это хорошая практика, чтобы вторгаться в GLOBAL-пространство из модулей, но в сценариях, где это может быть строго необходимо для его реализации:

Object.defineProperty(global,'MYCONSTANT',{value:'foo',writable:false,configurable:false});

Следует учитывать влияние этого ресурса. Без правильного назначения этих констант риск превышения уже определенных глобальных переменных является чем-то реальным.