Actuellement je fais ça:
foo.js
const FOO = 5;
module.exports = {
FOO: FOO
};
Et l'utiliser dans bar.js
:
var foo = require('foo');
foo.FOO; // 5
Y a-t-il une meilleure manière de faire cela? Il est difficile de déclarer la constante dans l'objet exports.
Vous pouvez explicitement l'exporter dans la portée globale avec global.FOO = 5
. Ensuite, vous devez simplement exiger le fichier et ne même pas enregistrer votre valeur de retour.
Mais vraiment, vous ne devriez pas faire ça. Garder les choses correctement encapsulées est une bonne chose. Vous avez déjà la bonne idée, alors continuez à faire ce que vous faites.
À mon avis, utiliser Object.freeze
permet un style plus sec et plus déclaratif. Mon modèle préféré est:
./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'
Le problème suivant a été résolu dans la v8 en janvier 2014 et ne concerne plus la plupart des développeurs:
Sachez que la définition de false en écriture et l’utilisation d’Object.freeze entraînent une pénalité de performances considérable dans la v8 - https://bugs.chromium.org/p/v8/issues/detail?id=1858 et http://jsperf.com/performance-frozen-object
Techniquement, const
ne fait pas partie de la spécification ECMAScript. En outre, en utilisant le modèle "CommonJS Module" que vous avez noté, vous pouvez modifier la valeur de cette "constante" puisqu'il ne s'agit désormais que d'une propriété d'objet. (je ne sais pas si cela va entraîner en cascade des modifications sur d'autres scripts nécessitant le même module, mais c'est possible)
Pour obtenir une vraie constante que vous pouvez également partager, consultez Object.create
, Object.defineProperty
et Object.defineProperties
. Si vous définissez _writable: false
_, la valeur de votre "constante" ne peut pas être modifiée. :)
C'est un peu verbeux (mais même cela peut être changé avec un peu de JS), mais vous ne devriez avoir besoin que de le faire une fois pour votre module de constantes. En utilisant ces méthodes, tout attribut que vous omettez est pris par défaut à false
. (par opposition à la définition de propriétés via une affectation, qui attribue par défaut tous les attributs à true
)
Donc, hypothétiquement, vous pourriez simplement définir value
et enumerable
, en laissant de côté writable
et configurable
car ils utiliseront par défaut false
, je viens d'inclure eux pour plus de clarté.
Mise à jour - J'ai créé un nouveau module ( constantes de nœud ) avec des fonctions d'assistance pour ce même cas d'utilisation.
_Object.defineProperty(exports, "PI", {
value: 3.14,
enumerable: true,
writable: false,
configurable: false
});
_
_function define(name, value) {
Object.defineProperty(exports, name, {
value: value,
enumerable: true
});
}
define("PI", 3.14);
_
_var constants = require("./constants");
console.log(constants.PI); // 3.14
constants.PI = 5;
console.log(constants.PI); // still 3.14
_
ES6 façon.
export dans foo.js
const FOO = 'bar';
module.exports = {
FOO
}
import dans bar.js
const {FOO} = require('foo');
J'ai trouvé la solution suggérée par Dominic comme étant la meilleure, mais il lui manque encore une caractéristique de la déclaration "const". Lorsque vous déclarez une constante dans JS avec le mot-clé "const", l'existence de la constante est vérifiée au moment de l'analyse, pas au moment de l'exécution. Donc, si vous avez mal orthographié le nom de la constante quelque part plus tard dans votre code, vous obtiendrez une erreur lorsque vous essayez de démarrer votre programme node.js. Ce qui est une vérification beaucoup plus efficace.
Si vous définissez la constante avec la fonction define () comme suggéré par Dominic, vous n'obtiendrez pas d'erreur en cas d'orthographe erronée de la constante et la valeur de la constante mal orthographiée sera indéfinie (ce qui peut entraîner des problèmes de débogage).
Mais je suppose que c'est le meilleur que nous puissions avoir.
De plus, voici une sorte d'amélioration de la fonction de Dominic, dans 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;
De cette façon, vous pouvez utiliser la fonction define () dans d'autres modules, ce qui vous permet de définir des constantes à la fois dans le module constants.js et des constantes dans votre module à partir duquel vous avez appelé la fonction. La déclaration des constantes de module peut ensuite être effectuée de deux manières (dans script.js).
Première:
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
Seconde:
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
De même, si vous souhaitez que la fonction define () soit appelée uniquement à partir du module constantes (sans pour autant altérer l'objet global), vous la définissez comme ceci dans constants.js:
exports.define = function ( name, value, exportsObject )
et utilisez-le comme ceci dans script.js:
constants.define( 'SOME_CONSTANT', "const value 1" );
D'après l'expérience du projet précédent, c'est un bon moyen:
Dans les 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
Dans main.js (ou app.js, etc.), utilisez-le comme suit:
// main.js
let constants = require('./constants');
console.log(constants.key1);
console.dir(constants.key3);
Je pense que const
résout le problème pour la plupart des gens à la recherche de cette réponse. Si vous avez vraiment besoin d'une constante immuable, examinez les autres réponses. Pour que tout reste organisé, j'enregistre toutes les constantes d'un dossier, puis le dossier au complet.
fichier src/main.js
const constants = require("./consts_folder");
src/répertoire_configuration/index.js
const deal = require("./deal.js")
const note = require("./note.js")
module.exports = {
deal,
note
}
Ps. ici les deal
et note
seront au premier niveau sur le fichier main.js
src/dossier_configuration/note.js
exports.obj = {
type: "object",
description: "I'm a note object"
}
Ps. obj
sera le deuxième niveau sur le fichier main.js
src/consts_folder/deal.js
exports.str = "I'm a deal string"
Ps. str
sera le deuxième niveau sur le fichier main.js
Résultat final sur le fichier main.js:
console.log(constants.deal);
Ouput:
{deal: {str: 'je suis une chaîne de deal'},
console.log(constants.note);
Ouput:
note: {obj: {type: 'objet', description: 'j’ai un objet note'}}
import
et export
(probablement besoin de quelque chose comme Babel à partir de 2018 pour utiliser l'importation)
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/en-US/docs/Web/JavaScript/Reference/Statements/import
Alternativement, vous pouvez regrouper vos valeurs "constantes" dans un objet local et exporter une fonction qui renvoie un clone superficiel de cet objet.
var constants = { FOO: "foo" }
module.exports = function() {
return Object.assign({}, constants)
}
Dans ce cas, il importe peu que quelqu'un réattribue FOO car cela n'affectera que sa copie locale.
Etant donné que Node.js utilise les modèles CommonJS, vous ne pouvez partager des variables entre modules avec module.exports
ou en définissant une variable globale comme vous le feriez dans le navigateur, mais au lieu d'utiliser window, utilisez global.your_var = value;
.
J'ai fini par exporter un objet gelé avec des fonctions de lecture anonymes, plutôt que les constantes elles-mêmes. Cela réduit le risque de mauvaises erreurs introduites en raison d'une simple faute de frappe du nom de const, car une erreur d'exécution sera renvoyée en cas de faute de frappe. Voici un exemple complet qui utilise également les symboles ES6 pour les constantes, garantissant l'unicité, et les fonctions de flèche ES6. J'apprécierais les commentaires si quelque chose dans cette approche semble problématique.
'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
});
Je ne pense pas que ce soit une bonne pratique d'envahir l'espace GLOBAL à partir de modules, mais dans des scénarios où il pourrait être strictement nécessaire de le mettre en œuvre:
Object.defineProperty(global,'MYCONSTANT',{value:'foo',writable:false,configurable:false});
Il faut prendre en compte l'impact de cette ressource. Sans une désignation correcte de ces constantes, le risque de SUPERVISION des variables globales déjà définies est quelque chose de réel.
Je recommande de le faire avec webpack (en supposant que vous utilisez webpack).
La définition de constantes est aussi simple que de définir le fichier de configuration webpack:
var webpack = require('webpack');
module.exports = {
plugins: [
new webpack.DefinePlugin({
'APP_ENV': '"dev"',
'process.env': {
'NODE_ENV': '"development"'
}
})
],
};
De cette façon, vous les définissez en dehors de votre source et ils seront disponibles dans tous vos fichiers.