5

I was reading this question about read-only properties, and I came upon this snippet:

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

Now, I know to hide the scope, you can use an IIFE, to also make a variable or property "private", but what I don't understand is:

Why is assignment allowed, and if it's allowed, how can nothing happen? In this snippet there is no inferred scope, so I don't understand how something in JS can infer a private property.

Community
  • 1
  • 1
Sterling Archer
  • 22,070
  • 18
  • 81
  • 118
  • It's not "private", it's using the "get" keyword to run a function that returns the value whenever you reference the property. – Patrick Roberts Jun 17 '15 at 20:03
  • Add a `set readOnlyProperty()` function that throws an error to prevent assignment. – Barmar Jun 17 '15 at 20:04
  • Couldn't the user just define a setter method and override this read-only aspect? – Sterling Archer Jun 17 '15 at 20:05
  • 1
    @SterlingArcher not if you `Object.freeze` it. If you do it with `.definePropety` it's also safe (see configurable and writable) – Benjamin Gruenbaum Jun 17 '15 at 20:09
  • @SterlingArcher You can only use `set`/`get` in literal object definitions, so you can't create a setter (using this `set`/`get` literal syntax) without making a new object. You can redefine the property using `Object.defineProperty`, though (unless the property has `configurable: false`, or the object is frozen). – apsillers Jun 17 '15 at 20:12

2 Answers2

6

Why is assignment allowed, and if it's allowed, how can nothing happen? In this snippet there is no inferred scope, so I don't understand how something in JS can infer a private property.

Because assignments (before strict mode) never throw and making it throw would violate that invariant that people expect. While you can still override it (by making a setter and making that throw) this is the default behavior in JavaScript for properties. We don't like it but it is what it is.

If you use strict mode - you should get:

TypeError: setting a property that has only a getter

Benjamin Gruenbaum
  • 270,886
  • 87
  • 504
  • 504
2

Getters and setters within object literal expressions are pure sugar over the Object.defineProperty() used in ES5.

What a getter does is that it returns a certain value, when a property of a certain object is requested.

let obj = {};
obj.foo = 3; // I am SETTING a property value
obj.foo; // I am GETTING the property value

So whenever you define a getter, every time you request a property, you get the value that that getter returns.

So if you have

let obj = {};

Object.defineProperty(obj, 'readOnly', {
    'get': function() { return 42; }
});

Or

let obj = {
    get readOnly() { return 42; }
};

Your variable will always be 42, because it can only return that value. You can try to set that property to any value, but in the end it will always return 42.

To forbidden assignment, you can add a setter and make it throw Error

Afonso Matos
  • 2,406
  • 1
  • 20
  • 30