Looking for swedish speaking members. I hope that we are more than 15 😉 @Swedish-Members
15 000+ members and only 15 that can write in swedish ;( Maybe when we are 16 000+ we get 16 members 😛 Nice ratio indeed!
I propose to either add a new ability for
the const
keyword or use the reserved word final
to make
non-writable object and class members.
Note: The TypeError
s are thrown following the behavior of Object.freeze
or
a { configurable: false, writable: false }
property descriptor. They
will be thrown in a "use strict";
environment, but usually not
otherwise.
Use final
, since it is an unused reserved word, or possibly const
to define constant Class or Object members:
class X {
// const / final now makes static class properties
// non-writable, and non-configurable
static const abc = 123;
static final abc = 123;
// also works to make constant private properties
const #def = 456;
final #def = 456;
// as well as constant normal class fields, if you're into that
const ghi = 789;
final ghi = 789;
// and constant private / static / normal methods
static const doSomething() { }
static final doSomething() { }
const #somethingPrivate() { }
final #somethingPrivate() { }
const cantChangeMe() { }
final cantChangeMe() { }
constructor(a = 3) {
const somethingPrivate = this.#somethingPrivate;
// throws new TypeError('Assignment to constant property.')
this.#somethingPrivate = function () { return a; }
this.#somethingPrivate === somethingPrivate // true
const def = this.#def;
// throws new TypeError('Assignment to constant property.')
this.#def = 1000;
this.#def === def // true
}
}
const x = new X();
const ghi = x.ghi;
// throws new TypeError('Assignment to constant property.')
x.ghi = 2000;
x.ghi === ghi // true
const doSomething = X.doSomething;
// throws new TypeError('Assignment to constant property.')
X.doSomething = function doSomethingElse() { };
X.doSomething === doSomething // true
const cantChangeMe = X.prototype.cantChangeMe;
// throws new TypeError('Assignment to constant property.')
X.prototype.cantChangeMe = function yesICan() { };
X.prototype.cantChangeMe === cantChangeMe // true
const o = {
// const / final can be used in normal object literals, too
const things() { },
final things() { },
const prop: 5,
final prop: 5,
};
const things = o.things;
// throws new TypeError('Assignment to constant property.')
o.things = function stuff() { };
o.things === things // true
const prop = o.prop;
// throws new TypeError('Assignment to constant property.')
o.prop = 11;
o.prop === prop // true
This could be transpiled by simply using Object.defineProperty
like so,
at least on public members:
class X {
static abc = 123;
static doSomething() { }
cantChangeMe() { }
constructor() { }
}
['abc', 'doSomething', 'cantChangeMe'].forEach(key =>
Object.defineProperty(X, key, { configurable: false, writable: false })
);
const o = {
things() { },
prop: 5,
};
['things', 'prop'].forEach(key =>
Object.defineProperty(o, key, { configurable: false, writable: false })
);
Defining everything as final
or const
in a Class or Object doesn't quiet
do the job. What if we want true immutability?
I've also looked into some kind of special syntax for creating immutable
objects and making classes return immutable objects. Maybe we could use
final
for that, as well?
// The static members and prototype of this class are shallow immutable.
// Any object it returns is also shallow immutable,
// similar to `return Object.freeze(this)` as the last line in the constructor,
// though since it uses a keyword, it could throw an error on an attempt to override
final class ConstantObject {
static abc = 123;
static doSomething() { }
cantChangeMe() { }
constructor() {
this.d = 8;
}
}
const constantObject = new ConstantObject();
const c = constantObject.c;
// throws new TypeError('Assignment to constant property.')
constantObject.c = 321;
constantObject.c = c // true
const doSomething = ConstantObject.doSomething;
// throws new TypeError('Assignment to constant property.')
ConstantObject.doSomething = function doSomethingElse() { };
ConstantObject.doSomething === doSomething // true
const cantChangeMe = ConstantObject.prototype.cantChangeMe;
// throws new TypeError('Assignment to constant property.')
ConstantObject.prototype.cantChangeMe = function yesICan() { };
ConstantObject.prototype.cantChangeMe === cantChangeMe // true
// No members can be added / modified / deleted from this shallow immutable object.
const finalObject = final {
prop: 5,
things() { },
};
const things = finalObject.things;
// throws new TypeError('Assignment to constant property.')
finalObject.things = function stuff() { };
finalObject.things === things // true
const prop = finalObject.prop;
// throws new TypeError('Assignment to constant property.')
finalObject.prop = 11;
finalObject.prop === prop // true
This could be transpiled essentially by just using Object.freeze
and Object.defineProperty
:
const ConstantObject = (() => {
class ConstantObject {
static abc = 123;
static doSomething() { }
cantChangeMe() { }
constructor() {
this.d = 8;
return Object.freeze(this);
}
}
Object.defineProperty(ConstantObject, 'prototype', {
value: Object.freeze(ConstantObject.prototype),
});
return Object.freeze(ConstantObject);
})();
const finalObject = Object.freeze({
prop: 5,
things() { },
});
What do you think? I'm currently leaning towards using the final
keyword for everything.
Both sides have pros and cons.
const | final | |
---|---|---|
Pros | • Meaningful word | • Unused |
• Fits existing syntax; AKA const x = 5 -> const x: 5 |
• Meaning could be closer if devs want to initialize after definition | |
• Familiar to Java devs | ||
Cons | • Could be overloaded in usage | • Less meaningful to C / JS devs, could be confusing |