58

Looking at the mozilla documentation, looking at the regular expression example (headed "Creating an array using the result of a match"), we have statements like:

input: A read-only property that reflects the original string against which the regular expression was matched.

index: A read-only property that is the zero-based index of the match in the string.

etc... is it possible to create your own object in JavaScript which will have read-only properties, or is this a privilege reserved to built-in types implemented by particular browsers?

Community
  • 1
  • 1
Claudiu
  • 224,032
  • 165
  • 485
  • 680
  • I've asked a similar question here: http://stackoverflow.com/questions/7757337/defining-read-only-properties-in-javascript – Šime Vidas Oct 13 '11 at 17:05
  • If one is trying to create a completely immutable copy of an existing object (i.e. one which has deeply read-only/immutable properties), this could help: http://stackoverflow.com/questions/16064136/create-a-read-only-immutable-copy-of-any-object-including-deep-properties/16064137 – Himanshu P Apr 18 '13 at 10:53
  • [`Object.seal`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/seal) prevents new properties from being added to an object (although existing properties can be changed) and [`Object.freeze`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze) prevents all changes to an object. Both [`Object.seal`](https://caniuse.com/#feat=mdn-javascript_builtins_object_seal) and [`Object.freeze`](https://caniuse.com/#feat=mdn-javascript_builtins_object_freeze) are well supported. – Dave F Apr 17 '20 at 21:50

10 Answers10

73

With any javascript interpreter that implements ECMAScript 5 you can use Object.defineProperty to define readonly properties. In loose mode the interpreter will ignore a write on the property, in strict mode it will throw an exception.

Example from ejohn.org:

var obj = {};
Object.defineProperty( obj, "<yourPropertyNameHere>", {
  value: "<yourPropertyValueHere>",
  writable: false,
  enumerable: true,
  configurable: true
});
Aidamina
  • 1,894
  • 20
  • 14
  • 2
    Note: this is compatible with IE9+, so rather [well supported](http://kangax.github.io/compat-table/es5/) today. – BenMorel Jan 31 '15 at 14:18
70

Edit: Since this answer was written, a new, better way using Object.defineProperty has been standardized in EcmaScript 5, with support in newer browsers. See Aidamina's answer. If you need to support "older" browsers, you could use one of the methods in this answer as a fallback.


In Firefox, Opera 9.5+, and Safari 3+, Chrome and IE (tested with v11) you can define getter and setter properties. If you only define a getter, it effectively creates a read-only property. You can define them in an object literal or by calling a method on an object.

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

If you already have an object, you can call __defineGetter__ and __defineSetter__:

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

Of course, this isn't really useful on the web because it doesn't work in Internet Explorer.

You can read more about it from John Resig's blog or the Mozilla Developer Center.

Community
  • 1
  • 1
Matthew Crumley
  • 101,441
  • 24
  • 103
  • 129
  • Good one! I tested and it works in Firefox, Opera and Chrome but not IE. – some Dec 14 '08 at 02:39
  • an additional note - is this part of any javascript specification? – Claudiu Dec 14 '08 at 03:46
  • It's not part of a current spec. I believe it is planned for the next version of ECMAScript, but right now, it's just a Mozilla extension that's supported in a few other browsers. – Matthew Crumley Dec 14 '08 at 03:49
  • and now 2 years later it's in the next spec =) – Claudiu Jun 03 '10 at 13:54
  • 2
    and still is not supported by IE ;) – Sergiy Belozorov Aug 06 '10 at 13:26
  • @SergiyByelozyorov I've tested the above code with IE 11 and it works fine ;) – ComFreek Nov 02 '13 at 17:32
  • 1
    For your utility, this technique is supported by IE since the 9th version. Here's a good compatibility table: http://kangax.github.io/es5-compat-table/ – yodabar Feb 17 '14 at 11:39
  • `__defineGetter__` and `__defineSetter__` are deprecated as of 2023. [`Object.defineProperty()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty) should be used instead. – InSync May 02 '23 at 22:25
6

It is possible to have read-only properties in JavaScript which are available via getter methods. This is usually called the 'Module' pattern.

The YUI blog has a good writeup of it: http://yuiblog.com/blog/2007/06/12/module-pattern/

Snippet from the post:

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
Ryan Doherty
  • 38,580
  • 4
  • 56
  • 63
5

As readonly property or variable here it is.

As aidamina said, and here is a short code for testing, by the way, very usefull now that JQuery pretends deprecate the selector property.

<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>

So there you have a readonly property or variable tested.

Community
  • 1
  • 1
Avenida Gez
  • 409
  • 5
  • 5
3

Yes we can have read only property for an object in JavaScript. It can be achieved with private variable and object.defineProperty() method,

See the following example which illustrates object having read only property,

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
nstCactus
  • 5,141
  • 2
  • 30
  • 41
Mohammed Safeer
  • 20,751
  • 8
  • 75
  • 78
  • Was a good option when given 5+ years ago, but JavaScript has since added private fields, i.e. `_name` => `#name` and it's truly private. See answer below. – jordanfb Aug 21 '23 at 17:11
2

Here's a link to Douglas Crockford's page on "Private Members in Javascript"....it would seem to me these would be read only if only getter methods are supplied, and no setters:

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

Dexygen
  • 12,287
  • 13
  • 80
  • 147
  • There's a difference between *private* and *readonly*. Private variables (and the way Crockford implements it in JavaScript) are just _private_, that means accessible inside the class (the constructor) but not exposed externally, so obviously you cannot change what you cannot access. Readonly properties may be exposed externally but not changed. – yodabar Feb 14 '14 at 13:47
  • 4
    Is it really necessary to downvote link only answers from *five and a half years* ago? The current strictures weren't in place then – Dexygen Aug 18 '14 at 14:52
1

You will see that I have defined a setter and getter for color so it can be modified. The brand on the other hand becomes read-only once the object is defined. I believe this is the functionality you were looking for.

        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

The above has been tested on Chromium Version 41.0.2272.76 Ubuntu 14.04 and yielded the following output:

          Porche
          Red
          BMW
          White
          Mercedes
          Black
          Green
          Green
          function () { return color; }
          Black
  • +1. This answer hints using `Object.freeze()`. ECMAScript 5 adds the `Object.seal` and `Object.freeze` methods. The seal method will prevent property additions but allow to write/edit properties. The `Object.freeze` method will completely lock an object, they will stay exactly as they were when you freeze them – S.Serpooshan Oct 01 '18 at 06:34
  • +1 for the red Porsche - somebody knows what a real sports car is. Anyway, private class fields were added to JavaScript a few years ago, see answer below. – jordanfb Aug 21 '23 at 17:13
1

If you want a read-only property at runtime without having to enable "strict mode", one way is to define a "throwing setter". Example:

Object.defineProperty(Fake.prototype, 'props', {
  set: function() {
    // We use a throwing setter instead of frozen or non-writable props
    // because that won't throw in a non-strict mode function.
    throw Error();
  },
});

Referenced from React

JBaczuk
  • 13,886
  • 10
  • 58
  • 86
  • in that link you referenced, its a module file and is't strict mode enabled in modules by default? why would they need throw for? – some_groceries Jun 24 '23 at 00:02
0

bob.js framework provides a way to declare read-only properties. Under the hood, it declares a private field and exposes the getter/setter functions for it. bob.js provides multiple ways of doing this same thing, depending on the convenience and specific goals. Here's one approach that uses object-oriented instance of the Property (other approaches allow defining setters/getters on the object itself):

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 

At the end, p.name.set_value is not defined because that's a read-only property.

Tengiz
  • 8,011
  • 30
  • 39
0

Other answers are correct, but no one has mentioned private class fields, which are another option for defining a readonly property (assuming a class makes sense for your use case):

class Car {
  color = ''; // public field
  #serialNumber = ''; // # is a private field

  constructor(color, serialNumber) {
    this.color = color;
    this.#serialNumber = serialNumber;
  }

  // Public read-only access to serial number
  get serialNumber() {
    return this.#serialNumber;
  }
}

const car = new Car('black', '123XYZ');
car.color = 'red'; // Changes color
car.serialNumber; // Returns private value
car.serialNumber = 'other'; // Does nothing
car.serialNumber; // Returns private value as before
jordanfb
  • 539
  • 5
  • 9