NodeJS 모듈에서 상수를 어떻게 공유합니까?


240

현재 나는 이것을하고있다 :

foo.js

const FOO = 5;

module.exports = {
    FOO: FOO
};

그리고 그것을 사용 bar.js:

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

더 좋은 방법이 있습니까? 내보내기 개체에서 상수를 선언하는 것이 어색합니다.


6
내보내려면에 넣습니다 exports. 그것에 대해 어색한 것은 무엇입니까?
Alex Wayne

5
저는 C #과 PHP에 익숙합니다. 각 상수를 두 번 정의하는 데 익숙해 져야한다고 생각합니다. 아마 미래에 우리는 가질 것 export const FOO = 5;입니다.
Tower

1
@Tower 미래는 지금입니다 (ES2015)! 2ality.com/2014/09/…
스페인 열차

1
이것이 더 간결한 기능과 다른가 module.exports={FOO:5};?
Joe Lapp

3
어색한 느낌 일뿐 아니라 더 이상 일정하지 않습니다
Ini

답변:


97

을 사용하여 명시 적으로 전역 범위로 내보낼 수 있습니다 global.FOO = 5. 그런 다음 단순히 파일이 필요하고 반환 값을 저장하지 않아도됩니다.

그러나 실제로는 그렇게해서는 안됩니다. 제대로 캡슐화 된 상태를 유지하는 것이 좋습니다. 당신은 이미 올바른 생각을 가지고 있으므로, 당신이하고있는 일을 계속하십시오.


51
죄송하지만이 방법을 잘 알고 있지만 대안 (더 나은) 솔루션을 제공하지 않은 경우 -1입니다. (re : "실제로 그렇게하지 말아야합니다. 올바르게 캡슐화 된 상태를 유지하는 것이 좋습니다.")
감사합니다.

22
전체 소프트웨어 개발 커뮤니티가 이런 식으로 생각했다면 여전히 펀치를 사용하고있을 것입니다. 운 좋게도 우리 자신에게 부과하는 미친 규칙을 어기는 것이 더 나은지 아는 몇 명의 매버릭이 있습니다. 캡슐화가 유용한 경우이를 사용하십시오. 그것이 당신의 일을 멈추게하는 긴장된 보모라면, 긴장된 보모를 해고하고 착수하십시오.
동기화되지 않음

22
@naomik (최근 답변 시간) 내가 더 나은 솔루션을 제공하지 않은 진짜 이유는 OP가 이미 솔루션을 알고 있기 때문입니다. 자체 모듈로 물건을 캡슐화하고 필요한 경우 필요합니다.
Alex Wayne

1
그렇다면 이것은 실제적인 대답이 아니며 오히려 "당신은 충분히 잘하고 있고, 대안은 나쁘다"고 설명하는 설명이되어야합니다 ..
Andrey Popov

1
캡슐화가 잘못 적용되었습니다. 클래스가 특수 값을 지표로 사용하고 이름을 부여하면 해당 클래스를 사용하는 모든 코드와 값을 공유하고 싶습니다.
grantwparks 2016 년

314

내 생각에, 활용 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) 에서 큰 성능 저하가 발생합니다. / 성능 고정 개체


4
Object.freeze의 좋은 사용 사례!
Estus Flask

상수와 함수를 모두 내 보내야하는 경우 어떻게됩니까? 동결 블록에도 기능을 넣어야합니까?
Tom

3
이 방법은 IDE 자동 완성 기능이 작동하기 때문에 더 좋습니다.
David A

3
이것은 훌륭한 답변이지만, 결국 v8의 성능에 대한 오래된 경고 때문에 사람들을이 접근 방식에서 벗어날 수 있습니다. 경고를 제거하십시오.
sampathsris

4
감사합니다 @Krumia! 나는 그것을 업데이트했지만 역사적 맥락을 위해 원래 경고 텍스트를 남겼습니다 (이러한 주석 중 일부는 의미가 없기 때문에).
스페인 열차

163

기술적으로 const ECMAScript 사양의 일부가 아닙니다. 또한 앞서 언급 한 "CommonJS Module"패턴을 사용하여 이제 "일정한"값을 오브젝트 특성으로 변경할 수 있습니다. (동일한 모듈이 필요한 다른 스크립트로 변경 사항을 캐스케이드할지 확실하지 않지만 가능합니다)

공유 할 수있는 상수를 얻으려면 Object.create,Object.defineProperty 등을 Object.defineProperties. 을 설정하면 writable: false"일정한"값을 수정할 수 없습니다. :)

약간 장황하지만 (작은 JS로 변경할 수도 있음) 상수 모듈에 대해 한 번만 수행하면됩니다. 이러한 방법을 사용하면 제외하는 모든 속성의 기본값은 false입니다. (할당을 통해 속성을 정의하는 것과 반대로, 모든 속성의 기본값은 true)

그래서, 가설, 당신은 단지 설정할 수 valueenumerable밖으로 떠나, 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이 컨텍스트 에서는 지정되지 않은 모든 속성이 가정 됩니다.
Dominic Barnes

6
또한 주목할만한 Object.freeze ()
damianb

1
이것이이 질문에 대한 가장 좋은 대답입니다. +1. 내가 더 많이 투표 할 수 있다면.
Ryan

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
예. 스택 오버플로는 오래된 답변을 감가 상각하는 방법이 필요합니다.
Rick Jolly

7
참고는 것을 const에서 bar.js탈구 변수의 수 있는지 확인합니다의 불변성이 아니라 const에서 foo.js. 즉, "constant"변수를 사용 let {FOO} =하고 변경할 수 있습니다 bar.js. AFAIK는 수출의 불변성을 강제하기 위해 여전히 ES 모듈 또는을 필요로합니다 Object.freeze.
스페인 열차

FOO내부 도 변경할 수 있습니다 foo.js.
lima_fil

16

나는 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 상수에 두 가지 방법으로 모듈 상수 선언을 수행 할 수 있습니다.

먼저:

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
}

추신. 여기 deal그리고note main.js에 첫 번째 수준이 될 것입니다

src / consts_folder / note.js

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

추신. objmain.js에서 두 번째 수준이 될 것입니다

src / consts_folder / deal.js

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

추신. strmain.js에서 두 번째 수준이 될 것입니다

main.js 파일의 최종 결과 :

console.log(constants.deal); 출력 :

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

console.log(constants.note); 출력 :

참고 : {obj : {유형 : 'object', 설명 : 'I \'ma note object '}}



4

또는 "일정한"값을 로컬 개체로 그룹화하고이 개체의 얕은 복제본을 반환하는 함수를 내보낼 수 있습니다.

var constants = { FOO: "foo" }

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

FOO는 로컬 사본에만 영향을 미치므로 FOO를 다시 할당해도 문제가되지 않습니다.


또는 그냥 module.exports = () => ({FOO : "foo", BAR : "bar"});
Björn

3

Node.js는 CommonJS 패턴을 사용하므로 module.exports브라우저에서와 같이 전역 변수를 설정하거나 사용하여 모듈간에 변수를 공유 할 수 있지만 window를 사용하는 대신을 사용하십시오 global.your_var = value;.


2

나는 상수 자체가 아닌 익명의 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
});

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.