NodeJSモジュールで定数をどのように共有しますか?


238

現在私はこれをやっています:

foo.js

const FOO = 5;

module.exports = {
    FOO: FOO
};

そしてそれを使ってbar.js

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

これを行うより良い方法はありますか?exportsオブジェクトで定数を宣言するのは面倒です。


6
エクスポートする場合は、に配置しますexports。それについて何が厄介ですか?
Alex Wayne、

5
私はC#とPHPに慣れています。それぞれの定数を2回定義することに慣れる必要があると思います。たぶん将来的にはありexport const FOO = 5;ます。
タワー

1
@タワー未来は今(ES2015)です!2ality.com/2014/09/…–
スペイン列車、

1
これはより簡潔な機能とは機能的に異なりmodule.exports={FOO:5};ますか?
Joe Lapp、2015

3
それは気まずいだけでなく、もはや一定ではありません
Ini

回答:


95

で明示的にグローバルスコープにエクスポートできglobal.FOO = 5ます。次に、ファイルを要求するだけでよく、戻り値を保存する必要もありません。

しかし、実際にはそうすべきではありません。物事を適切にカプセル化しておくことは良いことです。あなたはすでに正しい考えを持っているので、今していることを続けてください。


51
これを実行して申し訳ありませんが、-1は知っているが代替(より良い)ソリューションを提供していないことを意味します。(再:「しかし、実際にはそうすべきではありません。適切にカプセル化された状態を維持することは良いことです。」)
ありがとう

22
ソフトウェア開発コミュニティ全体がこのように考えていたとしても、私たちはまだパンチャードを使用しています。幸いなことに、私たちが自分に課している非常識なルールを破るほうがいいときを知っている異端者が何人かいます。カプセル化が役立つ場合は、それを使用してください。それがあなたの仕事をやめさせる神経質な乳母であるならば、神経質な乳母を解雇して、それで進んでください。
同期さ

22
@naomik(超遅い応答時間)私がより良い解決策を提供しなかった本当の理由は、OPがすでに解決策を知っているためです。独自のものにカプセル化し、必要に応じてそれらを要求します。
Alex Wayne 14

1
そして、これは、実際の答えではなく、むしろ旨説明コメント..「あなたが良いと十分にやっている、選択肢が悪い」でなければなりません
アンドレイ・ポポフ

1
カプセル化の間違ったアプリケーション。クラスが特別な値をインジケーターとして使用し、それらに名前を付ける場合、そのクラスを使用するすべてのコードとそれを共有する必要があります。
grantwparks 2016年

313

私の意見では、利用する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 / performance-frozen-object


4
Object.freezeの良い使用例!
Estus Flask 2015

定数と関数の両方をエクスポートする必要がある場合、どのように見えるべきですか?関数も凍結ブロックに入れるべきですか?
トム・

3
IDEオートコンプリートが機能するため、このアプローチの方が適しています。
David A

3
これは素晴らしい答えですが、最後のv8のパフォーマンスに関する古い警告のために、このアプローチから人々を遠ざける可能性があります。警告の削除を検討してください。
sampathsris

4
@Krumiaに感謝!私はそれを更新しましたが、元の警告テキストは歴史的な文脈のためだけに残しました(そしてこれらのコメントのいくつかはそれなしでは意味をなさないためです)。
スペイン列車、

163

技術的にconstは、ECMAScript仕様の一部ではありません。また、メモした「CommonJS Module」パターンを使用すると、その「定数」の値を変更できます。これは、オブジェクトプロパティにすぎないためです。(同じモジュールを必要とする他のスクリプトへの変更がカスケードされるかどうかはわかりませんが、可能です)

あなたも共有できることを実定数を取得するには、チェックアウトObject.createObject.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
});

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

2
@AntoineHedgecock必要はありませんObject.defineProperty()。上のドキュメントを確認してください。falseこのコンテキストでは、指定されていないすべてのプロパティが想定されます。
ドミニクバーンズ2013年

6
また注目に値する、Object.freeze()
damianb

1
これがこの質問の最良の答えです。+1。できればもっと賛成します。
ライアン、

1
素晴らしい答え、非常にエレガントで安全なソリューション。
Alex

1
@SpainTrainこれはによって修正されているようcodereview.chromium.org/135903014
Grinde

100

ES6の方法。

foo.jsにエクスポート

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

bar.jsにインポート

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

40
はい。スタックオーバーフローには、古い回答を減価償却する方法が必要です。
リックジョリー

7
それがあることに注意してくださいconstではbar.js破壊さ変数、ではないのように強制する不変constfoo.js。つまり、「定数」変数を使用let {FOO} =して変更できbar.jsます。AFAIKは、エクスポートの不変性を強制するために、ESモジュールまたはのいずれかが依然として必要Object.freezeです。
スペイン列車

FOO内部も変更できfoo.jsます。
lima_fil 2017

16

Dominicが最適なソリューションを提案しましたが、「const」宣言の1つの機能がまだありません。JSで「const」キーワードを使用して定数を宣言すると、定数の存在は実行時ではなく解析時にチェックされます。したがって、コードの後半で定数の名前のスペルを間違えた場合、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で)2つの方法で実行できます。

最初:

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

11

以前のプロジェクト経験から、これは良い方法です:

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

8

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。ここdealnotemain.js上の最初のレベルになります

src / consts_folder / note.js

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

Ps。objmain.jsの第2レベルになります

src / consts_folder / deal.js

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

Ps。strmain.jsの第2レベルになります

main.jsファイルの最終結果:

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

{Deal:{str: 'I \' ma deal string '}、

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

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



4

別の方法として、ローカルオブジェクトの「定数」値をグループ化し、このオブジェクトの浅いクローンを返す関数をエクスポートできます。

var constants = { FOO: "foo" }

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

次に、誰かがFOOを再割り当てしても、ローカルコピーにのみ影響するため、問題ではありません。


または単にmodule.exports =()=>({FOO: "foo"、BAR: "bar"});
ビョルンGrambow

3

Node.jsはCommonJSパターンを使用しているためmodule.exports、ブラウザーで行うようにグローバル変数を設定するか、グローバル変数を設定することによってのみモジュール間で変数を共有できますが、ウィンドウを使用する代わりにを使用しますglobal.your_var = value;


2

定数そのものではなく、匿名のゲッター関数を使用してフリーズしたオブジェクトをエクスポートすることで、これを実現しました。これは、タイプミスの場合に実行時エラーがスローされるため、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
});

0

私は、webpackを使用することをお勧めします(webpackを使用していると想定しています)。

定数の定義は、webpack設定ファイルを設定するのと同じくらい簡単です:

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

このようにして、ソースの外でそれらを定義すると、それらはすべてのファイルで使用可能になります。


0

モジュールからGLOBALスペースに侵入するのは良い習慣ではないと思いますが、それを実装するために厳密に必要となるシナリオでは:

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

このリソースの影響を考慮する必要があります。これらの定数に適切な名前を付けないと、すでに定義されているグローバル変数を上書きするリスクが現実になります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.