NodeJS modüllerinde sabitleri nasıl paylaşıyorsunuz?


240

Şu anda bunu yapıyorum:

foo.js

const FOO = 5;

module.exports = {
    FOO: FOO
};

Ve içinde kullanmak bar.js:

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

Bunu yapmanın daha iyi bir yolu var mı? İhracat nesnesindeki sabiti ilan etmek garip geliyor.


6
Dışa aktarmak isterseniz, içine koyun exports. Bu konuda garip olan ne?
Alex Wayne

5
C # ve PHP için alışkınım. Sanırım her sabiti iki kez tanımlamaya alışmak zorundayım. Belki gelecekte sahip olacağız export const FOO = 5;.
Kule

1
@Güç Gelecek şimdi (ES2015)! 2ality.com/2014/09/…
İspanya Tren

1
İşlevsel olarak daha özlü olandan farklı mı module.exports={FOO:5};?
Joe Lapp

3
Sadece akward hissetmiyor, artık sabit değil
Ini

Yanıtlar:


97

İle açıkça global kapsama dışa aktarabilirsiniz global.FOO = 5. O zaman sadece dosyayı istemeniz ve hatta dönüş değerinizi kaydetmemeniz gerekir.

Ama gerçekten, bunu yapmamalısın. İşleri düzgün bir şekilde kapsüllemek iyi bir şeydir. Şimdiden doğru fikre sahipsiniz, bu yüzden ne yaptığınızı yapmaya devam edin.


51
Bunu yaptığım için üzgünüm ama -1 daha iyi bilmek ama alternatif (daha iyi) bir çözüm sunmamak için; (yeniden: "Ama gerçekten, bunu yapmamalısın. Düzgün bir şekilde kapsüllenmiş tutmak iyi bir şeydir.")
Teşekkürler

22
Tüm yazılım geliştirme topluluğu bu şekilde düşünseydi, hala punkhard'lar kullanıyorduk. Neyse ki, kendimize dayattığımız çılgın kuralları kırmanın daha iyi olduğunu bilen birkaç mavericks var. Kapsülleme faydalıysa kullanın. Eğer işinizi yapmayı durduran gergin bir dadıysanız, gergin dadı ateş edin ve onunla geçin.
senkronize olmayan

22
@naomik (süper geç cevap süresi) Daha iyi bir çözüm sunmamamın gerçek nedeni OP'nin çözümü zaten bilmesidir. Kendi modüllerindeki şeyleri kapsülleyin ve gerektiğinde bunları isteyin.
Alex Wayne

1
O zaman bu gerçek bir cevap değil ve "yeterince iyi yapıyorsun, alternatifler kötü" diyen bir açıklama yorumu olmalı ..
Andrey Popov

1
Yanlış kapsülleme uygulaması. Bir sınıf göstergeler olarak özel değerler kullandığında ve onlara bir ad verdiğinde, bunu o sınıfı kullanan herhangi bir kodla paylaşmak istersiniz.
grantwparks

314

Benim düşünceme göre, kullanmak Object.freezeDRYer ve daha bildirimsel bir stil sağlar. Tercih ettiğim desen:

./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'

Eski Performans Uyarısı

Aşağıdaki sorun, Ocak 2014'te v8'de düzeltildi ve artık çoğu geliştiriciyle ilgili değil:

Hem yanlış yazılabilir ayarın hem de Object.freeze kullanmanın v8'de büyük bir performans cezasına sahip olduğunu unutmayın - https://bugs.chromium.org/p/v8/issues/detail?id=1858 ve http://jsperf.com / performans dondurulmuş nesne


4
Object.freeze için iyi kullanım!
Estus Flask

Hem sabitleri hem de işlevleri dışa aktarmam gerekirse neye benzemeli? Fonksiyonları dondurma bloğuna da koymalı mıyım?
Tom

3
IDE otomatik tamamlama onunla çalıştığı için bu yaklaşım daha iyidir.
David A

3
Bu harika bir cevap, ancak sonunda v8'in performansı hakkında eski moda uyarı nedeniyle insanları bu yaklaşımdan uzaklaştırabilir. Lütfen uyarıyı kaldırmayı düşünün.
sampathsris

4
Teşekkürler @Krumia! Güncelledim, ancak orijinal uyarı metnini sadece tarihsel bağlam için bıraktım (ve bu yorumların bazıları onsuz mantıklı olmadığından).
İspanya Tren

163

Teknik olarak, constECMAScript spesifikasyonunun bir parçası değildir. Ayrıca, not ettiğiniz "CommonJS Module" kalıbını kullanarak, o "sabit" in değerini artık sadece bir nesne özelliği olduğu için değiştirebilirsiniz. (bunun, aynı modülü gerektiren diğer komut dosyalarında yapılacak değişiklikleri basamaklandırıp basamaklandıracağından emin değilim, ancak bu mümkün)

Ayrıca, paylaşmak kontrol edebilirsiniz gerçek bir sabit almak için Object.create, Object.definePropertyve Object.defineProperties. Ayarladıysanız writable: false, "sabit" inizdeki değer değiştirilemez. :)

Bu biraz ayrıntılı, (ancak bu bile küçük bir JS ile değiştirilebilir), ancak sabit modülünüz için sadece bir kez yapmanız gerekir. Bu yöntemleri kullanarak, dışarıda bıraktığınız herhangi bir özellik varsayılan olarak kullanılır false. (özellikleri tüm özellikleri varsayılan olarak atama yoluyla tanımlamak yerine true)

Yani, varsayımsal olarak, sadece ayarlayabilir valueve enumerabledışarıda bırakabilirsiniz writableve configurablevarsayılan olarak olacağı için false, onları netlik için ekledim.

Güncelleme - Bu kullanım örneği için yardımcı işlevlere sahip yeni bir modül ( düğüm sabitleri ) oluşturdum.

constants.js - İyi

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

constants.js - Daha iyi

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 Gerekli değil, üzerindeki belgelere bakın Object.defineProperty(). Belirtilmeyen tüm özellikler falsebu bağlamda kabul edilir .
Dominic Barnes

6
Ayrıca dikkat çekici, Object.freeze ()
damianb

1
Bu sorunun en iyi cevabı bu. +1. Eđer yapabilseydim daha fazla oy verirdim.
Ryan

1
Harika cevap, çok zarif ve güvenli bir çözüm.
Alex


100

ES6 yolu.

foo.js'de dışa aktar

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

bar.js dosyasına aktar

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

40
Evet. Yığın Taşması, eski yanıtları amorti etmek için bir yola ihtiyaç duyar.
Rick Jolly

7
Not o olduğunu constiçinde bar.jstahrip edilen değişkenin o onu yürütmelidir değişmezlik değil constde foo.js. İşte o, insanın kullanabilir let {FOO} =içinde bar.jsve "sabit" değişkeni mutasyona. AFAIK, ihracatın değişmezliğini güçlendirmek için hala ES modüllerine veya Object.freeze.
İspanya Treni

FOOİçeride de değişebilir foo.js.
lima_fil

16

Dominic'in en iyisi olduğunu önerdiği çözümü buldum, ancak yine de "const" bildiriminin bir özelliğini kaçırıyor. JS'de "const" anahtar sözcüğüyle bir sabit bildirdiğinizde, sabitin varlığı çalışma zamanında değil ayrıştırma zamanında denetlenir. Dolayısıyla, sabitin adını daha sonra kodunuzda bir yere yazdıysanız, node.js programınızı başlatmaya çalıştığınızda bir hata alırsınız. Bu çok daha iyi bir yazım denetimi.

Sabiti Dominic'in önerdiği gibi define () işleviyle tanımlarsanız, sabiti yanlış yazdıysanız bir hata almazsınız ve yanlış yazılmış sabite değeri tanımlanmamış olur (bu da hata ayıklama baş ağrılarına yol açabilir).

Ama sanırım bu alabileceğimiz en iyisi.

Ayrıca, constans.js'de Dominic'in işlevinde bir tür iyileştirme var:

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;

Bu şekilde başka modüllerde define () işlevini kullanabilirsiniz ve hem constants.js modülünün içindeki sabitleri hem de işlevi çağırdığınız modülün içindeki sabitleri tanımlamanızı sağlar. Bildirilen modül sabitleri daha sonra iki şekilde yapılabilir (script.js içinde).

İlk:

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

İkinci:

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

Ayrıca, define () işlevinin yalnızca sabitler modülünden çağrılmasını istiyorsanız (genel nesneyi şişirmek için değil), constants.js'de şu şekilde tanımlarsınız:

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

ve script.js'de şu şekilde kullanın:

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

11

Önceki proje deneyiminden, bu iyi bir yoldur:

Constants.js'de:

// 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'de (veya app.js vb.) Aşağıdaki gibi kullanın:

// main.js

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

console.log(constants.key1);

console.dir(constants.key3);

8

Bence bu constdaha çok insanı arayan problemi çözüyor. Gerçekten değişmez bir sabite ihtiyacınız varsa, diğer cevaplara bakın. Her şeyi düzenli tutmak için tüm sabitleri bir klasöre kaydeder ve ardından tüm klasörü gerektirir.

src / main.js dosyası

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. burada dealve notemain.js'de ilk seviye olacak

src / consts_folder / note.js

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

Ps. objmain.js'de ikinci seviye olacak

src / consts_folder / deal.js

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

Ps. strmain.js'de ikinci seviye olacak

Main.js dosyasındaki nihai sonuç:

console.log(constants.deal); Çıkışı:

{deal: {str: 'Ben bir anlaşma dizesiyim'},

console.log(constants.note); Çıkışı:

not: {obj: {type: 'object', açıklama: 'Not nesnesiyim'}}



4

Alternatif olarak, "sabit" değerlerinizi yerel bir nesnede gruplayabilir ve bu nesnenin sığ bir klonunu döndüren bir işlevi dışa aktarabilirsiniz.

var constants = { FOO: "foo" }

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

O zaman birisinin FOO'yu yeniden ataması önemli değildir, çünkü sadece yerel kopyasını etkiler.


veya sadece module.exports = () => ({FOO: "foo", BAR: "bar"});
Björn Grambow

3

Node.js, CommonJS kalıplarını kullandığından, yalnızca modüller arasında module.exportsveya tarayıcıda yaptığınız gibi global bir değişken ayarlayarak veya kullandığınız pencereyi kullanmak yerine değişkenleri paylaşabilirsiniz global.your_var = value;.


2

Bunu, sabitlerin kendisinden ziyade anonim alıcı işlevleriyle donmuş bir nesneyi dışa aktararak yaptım. Bu, const adının basit bir yazım hatası nedeniyle ortaya çıkan kötü hata riskini azaltır, çünkü yazım hatası durumunda bir çalışma zamanı hatası atılır. Sabitler için ES6 Sembollerini kullanan, benzersizliği ve ES6 ok işlevlerini de içeren tam bir örnek. Bu yaklaşımdaki herhangi bir şey sorunlu görünüyorsa geri bildirim için teşekkür ederiz.

'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

Bunu webpack ile yapmanızı öneririm (webpack kullandığınızı varsayar).

Sabitleri tanımlamak, webpack yapılandırma dosyasını ayarlamak kadar basittir:

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

Bu şekilde onları kaynağınızın dışında tanımlarsınız ve bunlar tüm dosyalarınızda kullanılabilir olur.


0

GLOBAL alanını modüllerden istila etmek için iyi bir uygulama olduğunu düşünmüyorum, ancak bunu uygulamak için kesinlikle gerekli olabilecek senaryolarda:

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

Bu kaynağın etkisi olarak düşünülmelidir. Bu sabitleri uygun şekilde adlandırmaksızın, önceden tanımlanmış global değişkenleri AŞIRI yazma riski gerçek bir şeydir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.