web-dev-qa-db-fra.com

Comment créer des constantes Javascript en tant que propriétés d'objets en utilisant le mot-clé const?

Comment se fait-il que les constantes ne puissent pas être définies comme propriétés d'objets qui sont eux-mêmes des variables?

const a  = 'constant' // all is well
// set constant property of variable object
const window.b = 'constant' // throws Exception
// OR
var App = {};  // want to be able to extend
const App.goldenRatio= 1.6180339887  // throws Exception

Et comment se fait-il que les constantes passées par référence deviennent soudainement variables? EDIT: Je sais que l'App ne sera pas (ou plutôt ... NE DEVRAIT PAS) être mutable; ce n'est qu'une observation ...

(function() {
    const App;
    // bunch of code
    window.com_namespace = App;
}());
window.com_namespace; // App
window.com_namespace = 'something else';
window.com_namespace; // 'something else'

Comment créer une bibliothèque bien organisée, extensible, orientée objet et à espace de noms unique contenant des constantes avec ces limitations?

EDIT: je crois zi42, mais je dois juste demander pourquoi

39
danronmoon

Vous ne pouvez pas le faire avec des constantes. La seule façon possible de faire quelque chose qui se comporte comme vous le souhaitez, mais sans utiliser de constantes, est de définir une propriété non accessible en écriture:

var obj = {};
Object.defineProperty( obj, "MY_FAKE_CONSTANT", {
  value: "MY_FAKE_CONSTANT_VALUE",
  writable: false,
  enumerable: true,
  configurable: true
});

En ce qui concerne votre question de savoir pourquoi un const passé à une fonction devient variable, la réponse est parce qu'il est passé par valeur et non par référence. La fonction obtient une nouvelle variable qui a la même valeur que votre constante.

edit : merci à @pst d'avoir noté que les objets littéraux en javascript ne sont pas réellement "passés par référence", mais en utilisant call-by- partage :

Bien que ce terme soit largement utilisé dans la communauté Python, des sémantiques identiques dans d'autres langages tels que Java et Visual Basic sont souvent décrites comme appel par valeur, où la valeur est implicitement une référence à l'objet.

51
ziad-saab
const person = {
    name: "Nicholas"
};

// works
person.name = "Greg";



console.log(person) //Greg 

C'est pourquoi utiliser Object.defineProperty

7
zloctb

Il existe un moyen beaucoup plus simple de procéder. J'aime ce motif. Objets simples.

window.Thingy = (function() {

    const staticthing = "immutable";

    function Thingy() {

        let privateStuff = "something";

        function get() {
            return privateStuff;
        }

        function set(_) {
            privateStuff = _;
        }
        return Object.freeze({
            get,
            set,
            staticthing
        });
    }

    Thingy.staticthing = staticthing;
    return Object.freeze(Thingy);
})();

let myThingy = new Thingy();

Thingy.staticthing = "fluid";

myThingy.staticthing = "fluid";

console.log(Thingy.staticthing); // "immutable"
console.log(myThingy.staticthing); // "immutable"

Object.freeze fait le travail ici

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze

si vous le souhaitez, vous pouvez laisser la propriété statique hors de l'instance en la laissant hors du retour littéral de l'objet sur la fonction constructeur.

const n'en fera qu'une référence en lecture seule. Dès que vous l'assignez, comme ici dans un objet littéral, il devient une propriété de l'objet construit.

5
p0wdr.com
var obj = {};
Object.defineProperty( obj, "MY_FAKE_CONSTANT", {
  value: "MY_FAKE_CONSTANT_VALUE",
  writable: false,
  enumerable: true,
  configurable: false // instead of true
});

Nous devons également définir configurable pour être false afin d'éviter que la propriété ne soit supprimée de l'obj

delete obj.MY_FAKE_CONSTANT;

Avec configurable pour être vrai , après la ligne, nous n'avons plus le MY_FAKE_CONSTANT plus.

Référence

5
Cong Bang DO

Vous ne devez pas oublier que la déclaration const "crée une référence en lecture seule à une valeur. Cela ne signifie pas que la valeur qu'elle contient est immuable, juste que l'identifiant de variable ne peut pas être réaffecté"

Le mot clé const fonctionne de la même manière que "let", vous pouvez donc le redéclarer dans un autre bloc

const MyConst = 5;
console.log('global MyConst =', MyConst); //global MyConst = 5
if(true){
  const MyConst = 99
  console.log('in if block, MyConst =', MyConst); //in if block, MyConst = 99
}
console.log('global MyConst still 5 ?', MyConst===5); //global MyConst still 5 ? true

Tout comme @ ziad-saab, si vous voulez qu'une propriété d'objet agisse comme une constante, vous devez la définir comme une propriété non inscriptible.

si votre constante est un objet et que sa propriété ne doit pas changer, utilisez Object.freeze () pour rendre l'objet immuable.

(function(){
  var App = { };
  // create a "constant" object property for App
  Object.defineProperty(App , "fixedStuff", {
    value: Object.freeze({ prop:6 }),
    writable: false,
    enumerable: true,
    configurable: true
  });

  Object.defineProperty(window, "com_namespace", {
    value: App,
    writable: false,
    enumerable: true,
    configurable: true
  });
})()

com_namespace.newStuff = 'An extension';
com_namespace.fixedStuff.prop = 'new value'; // do nothing!
console.log(com_namespace.fixedStuff.prop); //6
4
Jeffrey Perron

Je pense que vous devez définir une constante dans la propriété rendant configurable: false et writable: false dans Object.defineProperty, si vous laissez configurable: true, vous pouvez toujours apporter des modifications à la propriété

par exemple: lorsque vous définissez configurable: true dans Object.defineProperty

cosnt obj = {name: 'some name'};
Object.defineProperty(obj, 'name', {
  enumerable: true,
  configurable: true,
  writable: false
});

Avec cela, vous faites obj.name 'constant' mais après vous pourriez faire

Object.defineProperty(obj, 'name', {
  enumerable: true,
  configurable: true,
  writable: true // <-- you can set to true because configurable is true
})

Mais si vous définissez configurable sur false, vous ne pourrez jamais modifier la propriété accessible en écriture.

Object.defineProperty(obj, 'name', {
  enumerable: true,
  configurable: false, // <-- with this you never could edit writable property
  writable: false
})

Et pour toutes les propriétés, vous pouvez utiliser Object.freeze

Object.freeze(obj);

Object.freeze itérera uniquement sur les propriétés énumérables

1
oscar dominguez