The gist of the idea is to allow specifying the class/prototype of the object created via object literal syntax. Currently, any object created via object literal is an instance of built-in Object class:
const example = {
foo: 'bar'
};
so when you want to create a lightweight object, you write something like this:
const example = Object.create(null);
example.foo = 'bar';
I can't tell how this affects the property access optimization, I believe either very minorly or it doesn't affect it at all. The idea is to use syntax like this to specify the class and properties of the object, created via object literal:
This is actually possible since the early days of Javascript. It's just not a well-known feature and is a little unintuitive (so it could be nice to have better syntax for it)
But, you just have to set the special "__proto__" property as you're creating the object, and that value will be set to the object's prototype.
For example:
//lightweight object
const example = {
__proto__: null,
foo: 'bar'
};
//User-defined class
const example = {
__proto__: MyClass.prototype,
foo: 'bar'
};
Yep. The gist of this post is all about the syntax. As far as I remember, the __proto__ property is not a part of the spec, so maybe it would make sense to come up with some standard syntax for this, with fewer magic properties?
Itβs absolutely part of the spec, since ES2015. Itβs in the process of being moved out of Annex B, as well, so all implementations would be required to implement it (all do anyways).
It might be hard to justify new syntax for it, since syntax already exists, and there's a high bar for adding new syntax to the language (to prevent it from becoming overly complicated). The current syntax doesn't really create any footguns either, it's just odd to use, especially since any google search about the __proto__ property will bring you with results talking about how getting or setting __proto__ on a property is deprecated (though they usually don't mention that __proto__ in an object literal isn't depracated).
I usually avoid __proto__ for that reason, and do one of these two solutions to create an object with a prototype.
These are a little more verbose, but I'm ok with that verbosity considering I don't do this kind of thing a ton. But I know some other Javascript coding styles make use of this kind of thing a lot more.
The only justifications that come to my mind are neater syntax and subtle (if any) improvements to object property access speeds, assuming that @ theScottyJam's example doesn't solve this problem.
Current ways to achieve the same look quite ugly, but I'm an artist, that's how I see it .
I much prefer null prototypes, as there's much better support for working with objects than maps (both with syntax and with helper functions). Compare
map[key] ??= 0
may[key]++
with
if (!map.has(key)) {
map.set(key, 0)
}
map.set(key, map.get(key) + 1)
I do, however, understand the hesitance with them, and understand when people choose to avoid them. But, I don't necessarily think the missing .toString() is a big enough reason to have everyone shun them (though you may disagree, which is fine).
I suggest a new method Object.from(obj), which returns a new object having same keys and prototype of input object.
const example = Object.create(null);
example.foo = 'bar';
const example1 = Object.from(example); // example1 and example having same 'Shape'
example1.foo = 'bar1';
Another reason of introducing Object.from(obj) is to provide a better way to maintain the 'Shape' (as mentioned at the property access optimization)of objects.
e.g.
const example1 = {
foo: 'bar1'
};
const example2 = {
foo: 'bar2'
};
// example1 and example2 are optimized
but later, you change one object
const example1 = {
foo: 'bar1',
baz: 'baz'
};
const example2 = {
foo: 'bar2'
};
// example1 and example2 are now not optimized
What about the performance of __proto__? I tried to check the performance vs Object.create(), but I struggle interpreting results (uncomment commented lines and __proto__ will show the best result).
It may be an off topic, but I'm curious why and when construction functions and new operator were preferred to syntax like this.
I think, exactly because of this, there should be a proper syntax for it... Almost no one knows about this and if you try to explain it to people they think it will make their code run slower and is deprecated.
Another thing is that { __proto__: MyOtherObject } is not recognized by any type inference engine out there except TernJS. Having a proper syntax that doesn't look like a hack, hopefully would improve this and get these sorts of tools to properly adopt it.
I was pondering different ways to replace the __proto__ quirk before finding this thread. So far I haven't been able to come up with a syntax I'd immediately like, but here are some alternatives for consideration:
n = { null, ... };
// very concise, but has issues:
// 1) someone might read it as { "null": null }
// 2) only works for null
n = { (null), ... };
o = { (Klas.prototype), ... };
n = new null { ... }; // no line break before {
o = new Object.prototype { ... };
We could reuse the extends keyword:
n = { extends null, ... };
o = { extends Klas.prototype, ... };
// or
o = { ... } extends Klas.prototype;
n = { ... } extends null;
// although I don't like the latter, because I want the prototype in front;
// otherwise there's little benefit over Object.setPrototypeOf({ ... }, P);
> Object.getPrototypeOf(n) === null
true
> Object.getPrototypeOf(o) === Klas.prototype
true
What I find unsatisfactory about these is that using .prototype after extends feels weird, and only starts making sense after you consider what extends does with classes:
class A {};
class B extends A {};
> Object.getPrototypeOf(B) === A
true