Implementing an identical JSON.stringify
valentinium at gmail.com
Sun Aug 5 04:47:45 UTC 2018
> I guess what confused me is that it would detect a [[NumberData]]
internal slot, but instead of unboxing to that value it tries to ducktype
call .valueOf on the object. So the presence of [[NumberData]] changes the
behavior even if it does not actually use this value.
This surprised me too initially, but I think we can infer a rationale if we
read between the lines a bit. A similar pattern appears in the JSON
stringify algorithm itself (as opposed to the SerializeJSONProperty
algorithm) when interpreting the "space" argument. So it might seem to be
that it’s a peculiarity of how JSON-related operations are defined — but I
don’t think that’s the pattern. What these two cases have in common is that
either a numeric value or a string value would be valid: neither hint would
be more correct. In the case of SerializeJSONProperty, this is because both
string values and numeric values are valid JSON values; in the case of
stringify’s space argument, it’s because this is overloaded to either
specify a number of spaces or a whitespace string. In the absence of a
reason to weight one to-primitive operation over another, it sniffs for the
singular unambiguous clue about type that’s really available, the slot.
Why doesn’t it then just use the slot value directly? Because this would
depart from expectations about the @@toPrimitive / toValue / toString
contract that is honored everywhere else, I believe.
On Sun, Aug 5, 2018 at 12:30 AM Michael Theriot <
michael.lee.theriot at gmail.com> wrote:
> Regarding cases like Reflect.construct(Number, , String), the reason
>> this throws is because the ToNumber algorithm calls ToPrimitive if its
>> operand is an object. This in turn will call String.prototype.valueOf on
>> the object which does not have [[StringData]]. There’s nothing funny going
>> on, it’s just a weird effect in aggregate. You would just need to implement
>> all the steps here — internal ops like ToNumber, ToPrimitive, etc. It’s not
>> that it "considers type", but rather that these algorithms will call
>> methods by specific names on objects they receive. String.prototype and
>> Object.prototype both implement "valueOf", but only the former will fail
>> the slot check.
> Thanks for demystifying this. I never realized it was just ducktyping
> .valueOf on the object.
> Number.prototype.valueOf = () => 0;
> JSON.stringify(1); // 1
> JSON.stringify(new Number(1)); // 0
> I guess what confused me is that it would detect a [[NumberData]] internal
> slot, but instead of unboxing to that value it tries to ducktype call
> .valueOf on the object. So the presence of [[NumberData]] changes the
> behavior even if it does not actually use this value.
> On Sat, Aug 4, 2018 at 10:14 PM Darien Valentine <valentinium at gmail.com>
>> Is this a question about how/if one could replicate its behavior in
>> theory from ES code, or are you suggesting a change to the existing
>> behavior for these exotic cases?
>> Assuming the former:
>> The relevant steps are [here](
>> https://tc39.github.io/ecma262/#sec-serializejsonproperty). The
>> `instanceof` a value isn’t significant in this algorithm, just its slots
>> (if it is an object) or its primitive type. So one can handle number and
>> string by leveraging branded checks as you’ve shown — nothing more is
>> needed than branded methods and typeof to manage that one.
>> However it is ultimately not possible to replicate because there is no
>> possible brand test for [[BooleanData]].
>> es-discuss mailing list
>> es-discuss at mozilla.org
-------------- next part --------------
An HTML attachment was scrubbed...
More information about the es-discuss