0

I wanted to have an object field that is immutable. I've tried:

const a = 1;
var o = {
   x: 'This is mutable',
   y: a // This should not be mutable.
};
o.y = 'Changed';
console.log(o);

Field y gets re-assigned.
Is there any way to make this work?

Etheryte
  • 24,589
  • 11
  • 71
  • 116
F.Almeida
  • 413
  • 2
  • 12
  • You probably want to check https://stackoverflow.com/questions/9772307/declaring-javascript-object-method-in-constructor-function-vs-in-prototype – versvs Feb 22 '18 at 10:32
  • Have you looked at [Object.freeze()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze)? You'd have to define your object beforehand, and then freeze it which is slightly different from what you have. Or `Object.seal()`? – Andy Feb 22 '18 at 10:33
  • @Andy the thing is that freeze() "locks" all the object properties – F.Almeida Feb 22 '18 at 10:35
  • Question title "Is it possible to have a const object property?" kinda contradicts the question itself. Do you want to freeze object property or set a property that is not configurable (Uncaught SyntaxError: Identifier 'x' has already been declared at :1:1) – Yury Tarabanko Feb 22 '18 at 10:36
  • 1
    Not sure I understand the error message, where in that code snippet has `x` been declared?. When do you get that message? – Keith Feb 22 '18 at 10:36
  • @Keith I've edited, was testing with other variable names – F.Almeida Feb 22 '18 at 10:37
  • @YuryTarabanko I want to set a property that is not configurable, i.e, can't be removed or re-assigned – F.Almeida Feb 22 '18 at 10:38
  • Still not getting any error message, try running your snippet. No error. But anyway `{ "x": "This is mutable"}` here `x` is not a varible, it's a property. So you can use property gettter / setters like @Nit has shown. – Keith Feb 22 '18 at 10:40
  • @Keith I've edited, somehow I got a console error because I named a variable with the same name as the const one. My mistake. – F.Almeida Feb 22 '18 at 10:43
  • Possible duplicate of [Is there any way to prevent replacement of JavaScript object properties?](https://stackoverflow.com/questions/2365318/is-there-any-way-to-prevent-replacement-of-javascript-object-properties) – Dmitry Feb 22 '18 at 16:52

3 Answers3

3

Use Object.defineProperty() and set configurable as false.

var o = {
    x: 'This is mutable'
};
Object.defineProperty(o, "y", { configurable: false, writable: false });

console.log(o);

o.y will behave as if Object.freeze were called on it separately.

hashedram
  • 813
  • 7
  • 14
2

If you want to have a simple object, you can use Object.defineProperty():

const tea = {};
Object.defineProperty(tea, 'bar', {
  value: 'unchanged',
  writable: false,
  configurable: false
});

console.log(tea.bar); // 'unchanged'
tea.bar = 'new value';
console.log(tea.bar); // 'unchanged'
delete tea.bar;
console.log(tea.bar); // 'unchanged'

Alternatively, if you need a class, you can use a getter along with a no-op setter:

class Foo {
  get bar() {
    return 'unchanged';
  }
  set bar(_) {}
};
const tea = new Foo();

console.log(tea.bar); // 'unchanged'
tea.bar = 'new value';
console.log(tea.bar); // 'unchanged'
delete tea.bar;
console.log(tea.bar); // 'unchanged'
Etheryte
  • 24,589
  • 11
  • 71
  • 116
  • 1
    `delete foo.bar;` will actually delete it, though. – str Feb 22 '18 at 10:41
  • You should add `"use strict";` otherwise the set just silently fails. – Aluan Haddad Feb 22 '18 at 10:43
  • @str Thanks for pointing that out, using a class fixes that issue. – Etheryte Feb 22 '18 at 10:44
  • @AluanHaddad Since a strong majority of new code today is either straight ES6 or transpiled, I think manually adding `"use strict";` to SO answers is obsolete. – Etheryte Feb 22 '18 at 20:54
  • 1
    @Nit but there are so many stack snippets and people running code in their browser console. But especially for this question I think it's significant. That it throws is pretty important. – Aluan Haddad Feb 22 '18 at 20:55
  • Since you've stubbed out to the set function it doesn't make much of a difference but that's unusual. – Aluan Haddad Feb 22 '18 at 20:58
2
var obj = {a:1,b:2};

Object.defineProperty(obj,'b',{
    writable:false
});

obj.b = 3;

console.log(obj.b) //output 2
obj.a = 8; 
console.log(obj.a); //output 8