web-dev-qa-db-fra.com

Les propriétés en lecture seule peuvent-elles être implémentées en JavaScript pur?

En regardant la mozilla documentation , en regardant l’exemple d’expression régulière (intitulé "Création d’un tableau en utilisant le résultat d’une correspondance"), nous avons des instructions du type:

input: propriété en lecture seule qui reflète la chaîne d'origine par rapport à laquelle l'expression régulière a été mise en correspondance.

index: propriété en lecture seule qui correspond à l'index de base zéro de la correspondance dans la chaîne.

etc ... est-il possible de créer votre propre objet en JavaScript qui aura des propriétés en lecture seule, ou s'agit-il d'un privilège réservé aux types intégrés implémentés par des navigateurs particuliers?

42
Claudiu

Edit: Depuis que cette réponse a été écrite, une nouvelle méthode plus efficace utilisant Object.defineProperty a été normalisée dans EcmaScript 5, avec une prise en charge dans les nouveaux navigateurs. Voir Réponse de Aidamina . Si vous devez prendre en charge les "anciens" navigateurs, vous pouvez utiliser l'une des méthodes de cette réponse comme solution de secours.


Dans Firefox, Opera 9.5+, Safari 3+, Chrome et IE (testé avec v11), vous pouvez définir les propriétés de lecture et de définition. Si vous définissez uniquement un getter, cela crée effectivement une propriété en lecture seule. Vous pouvez les définir dans un littéral d'objet ou en appelant une méthode sur un objet.

var myObject = {
    get readOnlyProperty() { return 42; }
};

alert(myObject.readOnlyProperty); // 42
myObject.readOnlyProperty = 5;    // Assignment is allowed, but doesn't do anything
alert(myObject.readOnlyProperty); // 42

Si vous avez déjà un objet, vous pouvez appeler __defineGetter__ et __defineSetter__:

var myObject = {};
myObject.__defineGetter__("readOnlyProperty", function() { return 42; });

Bien sûr, cela n’est pas vraiment utile sur le Web car cela ne fonctionne pas dans Internet Explorer.

Vous pouvez en savoir plus à ce sujet sur le blog de John Resig ou le Mozilla Developer Center .

65
Matthew Crumley

Avec tout interpréteur javascript implémentant ECMAScript 5 , vous pouvez utiliser Object.defineProperty pour définir les propriétés en lecture seule. En mode lâche, l'interprète ignore une écriture sur la propriété, en mode strict, il lève une exception.

Exemple de ejohn.org :

var obj = {};
Object.defineProperty( obj, "<yourPropertyNameHere>", {
  value: "<yourPropertyValueHere>",
  writable: false,
  enumerable: true,
  configurable: true
});
62
Aidamina

Il est possible d'avoir des propriétés en lecture seule en JavaScript, disponibles via les méthodes getter. Cela s'appelle généralement le modèle 'Module'.

Le blog de YUI en a une bonne description: http://yuiblog.com/blog/2007/06/12/module-pattern/

Extrait du message:

YAHOO.myProject.myModule = function () {

//"private" variables:
var myPrivateVar = "I can be accessed only from within YAHOO.myProject.myModule.";

//"private" method:
var myPrivateMethod = function () {
    YAHOO.log("I can be accessed only from within YAHOO.myProject.myModule");
}

return  {
    myPublicProperty: "I'm accessible as YAHOO.myProject.myModule.myPublicProperty."
    myPublicMethod: function () {
        YAHOO.log("I'm accessible as YAHOO.myProject.myModule.myPublicMethod.");

        //Within myProject, I can access "private" vars and methods:
        YAHOO.log(myPrivateVar);
        YAHOO.log(myPrivateMethod());

        //The native scope of myPublicMethod is myProject; we can
        //access public members using "this":
        YAHOO.log(this.myPublicProperty);
    }
};

}(); // the parens here cause the anonymous function to execute and return
6
Ryan Doherty

En tant que propriété ou variable en lecture seule, il l’est. 

Comme aidamina a dit , et voici un code court pour tester, soit dit en passant, très utile maintenant que JQuery prétend déprécier la propriété selector.

<script>
Object.defineProperties(window, {
  "selector": { value: 'window', writable: false }
});

alert (window.selector);  // outputs window

selector ='ddd';          // testing because it belong to the global object
alert (window.selector);  // outputs window
alert (selector);         // outputs window

window.selector='abc';
alert (window.selector);   // outputs window
alert (selector);          // outputs window
</script>

Vous avez donc une propriété ou une variable en lecture seule testée.

5
Avenida Gez

Oui, nous pouvons avoir une propriété en lecture seule pour un objet en JavaScript. Il peut être réalisé avec une variable privée et la méthode object.defineProperty(),

Voir l'exemple suivant qui illustre que l'objet possède une propriété en lecture seule,

function Employee(name,age){
    var _name = name;
    var _age = age;

    Object.defineProperty(this,'name',{
        get:function(){
            return _name;
        }
    })
}

var emp = new Employee('safeer',25);
console.log(emp.name); //return 'safeer'
emp.name='abc';
console.log(emp.name); //again return 'safeer', since name is read-only property
3
Mohammed Safeer

Voici un lien vers la page de Douglas Crockford sur "Membres privés en Javascript" .... il me semble que celles-ci ne seraient lues que si seules les méthodes getter sont fournies, et pas de setters:

http://javascript.crockford.com/private.html

2
George Jempty

Vous verrez que j'ai défini un setter et un getter pour la couleur afin de pouvoir la modifier. En revanche, la marque devient en lecture seule une fois que l'objet est défini. Je crois que c'est la fonctionnalité que vous recherchiez.

        function Car(brand, color) {
            brand = brand || 'Porche'; // Private variable - Not accessible directly and cannot be frozen
            color = color || 'Red'; // Private variable - Not accessible directly and cannot be frozen
            this.color = function() { return color; }; // Getter for color
            this.setColor = function(x) { color = x; }; // Setter for color
            this.brand = function() { return brand; }; // Getter for brand
            Object.freeze(this); // Makes your object's public methods and properties read-only
        }

        function w(str) {
            /*************************/
            /*choose a logging method*/
            /*************************/
            console.log(str);
            // document.write(str + "<br>");
        }

        var myCar = new Car;
        var myCar2 = new Car('BMW','White');
        var myCar3 = new Car('Mercedes', 'Black');

        w(myCar.brand()); // returns Porche
        w(myCar.color()); // returns Red

        w(myCar2.brand()); // returns BMW
        w(myCar2.color()); // returns White

        w(myCar3.brand()); // returns Mercedes
        w(myCar3.color()); // returns Black

        // This works even when the Object is frozen
        myCar.setColor('Green');
        w(myCar.color()); // returns Green

        // This will have no effect
        myCar.color = 'Purple';
        w(myCar.color()); // returns Green
        w(myCar.color); // returns the method

        // This following will not work as the object is frozen
        myCar.color = function (x) {
            alert(x);
        };

        myCar.setColor('Black');
        w(
            myCar.color(
                'This will not work. Object is frozen! The method has not been updated'
            )
        ); // returns Black since the method is unchanged

Ce qui précède a été testé sur la version 41.0.2272.76 Ubuntu 14.04 de Chromium et a donné la sortie suivante:

          Porche
          Red
          BMW
          White
          Mercedes
          Black
          Green
          Green
          function () { return color; }
          Black
1
Vincent Charette

bob.js framework fournit un moyen de déclarer des propriétés en lecture seule. Sous le capot, il déclare un champ privé et expose les fonctions de lecture/définition pour celui-ci. bob.js offre plusieurs façons de faire la même chose, en fonction de la commodité et des objectifs spécifiques. Voici une approche qui utilise l'instance orientée objet de la Property (d'autres approches permettent de définir des setters/getters sur l'objet lui-même):

var Person = function(name, age) {  
    this.name = new bob.prop.Property(name, true); 
    var setName = this.name.get_setter(); 
    this.age = new bob.prop.Property(age, true); 
    var setAge = this.age.get_setter();  
    this.parent = new bob.prop.Property(null, false, true);  
};  
var p = new Person('Bob', 20);  
p.parent.set_value(new Person('Martin', 50));  
console.log('name: ' + p.name.get_value());  
console.log('age: ' + p.age.get_value());  
console.log('parent: ' + (p.parent.get_value ? p.parent.get_value().name.get_value() : 'N/A')); 
// Output: 
// name: Bob 
// age: 20 
// parent: N/A 

À la fin, p.name.set_value n'est pas défini car il s'agit d'une propriété en lecture seule.

0
Tengiz