Open chris-morgan opened 2 years ago
Sorry for replying late, I have read you issue days before.
What's counter-intuitive, object without any proto is slower than object with a proto for tenfold. I can't give you ready-made https://jsperf.com link because the site is down... You can try below in https://jsbench.me/:
// setup
window.plain = {};
window.null = Object.create(null);
window.Null = Object.create(Object.create(null));
// test case 1: x10
'use strict';
const object = window.plain;
for ( let i = 1e6; --i; ) { object.key ??= null; }
// test case 2: x1
'use strict';
const object = window.null;
for ( let i = 1e6; --i; ) { object.key ??= null; }
// test case 3: x10
'use strict';
const object = window.Null;
for ( let i = 1e6; --i; ) { object.key ??= null; }
Object.create(null)
will make more than tenfold slower, while Object.create(NULL)
can regain to {}
with proto properties safe.
But what you said is also important, which I didn't meet before. I want to know that, what bad thing will actually happen, when an object is not simple? (What do you mean of "uses the iteration prototcol"?)
I searched a popular lib merge-options
and it's dep is-plain-obj
, it seems thing should work right:
How could you got a T00:00:00Z
? I can't reproduce it or find any trace of it by the source code. Would you please give a use case to help to figure out that? If it exists, it's definitely not expected behaviour.
@chris-morgan
The
parse
method produces objects with a strange prototype. Rather than leaving it atObject.prototype
(the default) or usingnull
(mostly better), the objects get an indirect prototype, an object that itself has a null prototype, and is also sealed. I cannot imagine any valid reason for this: it’s purely inefficiency. But it also thwarts detection of a null prototype, which is a bad thing, because “is its prototypeObject.prototype
ornull
” is a customary “simple object” check. For a concrete example of what this breaks, trying to userequire("@ltd/j-toml").parse
in Eleventy data or front matter ends up ignoring everything if deep data merging is enabled (which it is by default), because it does this kind of “simple object” check, or uses the iteration prototcol if it isn’t simple—and this gets erroneously detected as not simple.I propose removing this:
And replacing all occurrences of
NULL
withnull
. Simpler, faster, more efficient, less troublesome. There may be more related stuff to it, but I’ve decided not to use this library because of this and other troublesome prototype shenanigans (e.g. howDatetime
effectively deletes methods, which is a bad thing to do and almost always worse than just not doing that—yeah, if you try accessing the “wrong” methods onLocalDate
you’ll effectively get a T00:00:00Z, but that’s not so bad), so I haven’t delved particularly deeply.Sample Node transcript showing the problem and a hacky postprocessing fix for the prototype (though you’d need to do this recursively):