From 020c1e77489b772f854bb3288b9c8d2818a6bf9d Mon Sep 17 00:00:00 2001 From: EuAndreh Date: Fri, 18 Apr 2025 02:17:12 -0300 Subject: git mv src/content/* src/content/en/ --- .../en/tils/2021/08/11/js-bigint-reviver.adoc | 89 ++++++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100644 src/content/en/tils/2021/08/11/js-bigint-reviver.adoc (limited to 'src/content/en/tils/2021/08/11/js-bigint-reviver.adoc') diff --git a/src/content/en/tils/2021/08/11/js-bigint-reviver.adoc b/src/content/en/tils/2021/08/11/js-bigint-reviver.adoc new file mode 100644 index 0000000..98ee79b --- /dev/null +++ b/src/content/en/tils/2021/08/11/js-bigint-reviver.adoc @@ -0,0 +1,89 @@ += Encoding and decoding JavaScript BigInt values with reviver +:updatedat: 2021-08-13 + +:reviver-fn: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse#using_the_reviver_parameter +:bigint: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt +:json-rfc: https://datatracker.ietf.org/doc/html/rfc8259 + +`JSON.parse()` accepts a second parameter: a {reviver-fn}[`reviver()` function]. +It is a function that can be used to transform the `JSON` values as they're +being parsed. + +As it turns out, when combined with JavaScript's {bigint}[`BigInt`] type, you +can parse and encode JavaScript `BigInt` numbers via JSON: + +[source,javascript] +---- +const bigIntReviver = (_, value) => + typeof value === "string" && value.match(/^-?[0-9]+n$/) + ? BigInt(value.slice(0, value.length - 1)) + : value; +---- + +I chose to interpret strings that contains only numbers and an ending `n` +suffix as `BigInt` values, similar to how JavaScript interprets `123` (a number) +differently from `123n` (a `bigint`); + +We do those checks before constructing the `BigInt` to avoid throwing needless +exceptions and catching them on the parsing function, as this could easily +become a bottleneck when parsing large JSON values. + +In order to do the full roundtrip, we now only need the `toJSON()` counterpart: + +[source,javascript] +---- +BigInt.prototype.toJSON = function() { + return this.toString() + "n"; +}; +---- + +With both `bigIntReviver` and `toJSON` defined, we can now successfully parse +and encode JavaScript objects with `BigInt` values transparently: + +[source,javascript] +---- +const s = `[ + null, + true, + false, + -1, + 3.14, + "a string", + { "a-number": "-123" }, + { "a-bigint": "-123n" } +]`; + +const parsed = JSON.parse(s, bigIntReviver); +const s2 = JSON.stringify(parsed); + +console.log(parsed); +console.log(s2); + +console.log(typeof parsed[6]["a-number"]) +console.log(typeof parsed[7]["a-bigint"]) +---- + +The output of the above is: + +[source,javascript] +---- +[ + null, + true, + false, + -1, + 3.14, + 'a string', + { 'a-number': '-123' }, + { 'a-bigint': -123n } +] +[null,true,false,-1,3.14,"a string",{"a-number":"-123"},{"a-bigint":"-123n"}] +string +bigint +---- + +If you're on a web browser, you can probably try copying and pasting the above +code on the console right now, as is. + +Even though {json-rfc}[`JSON`] doesn't include `BigInt` number, encoding and +decoding them as strings is quite trivial on JavaScript. -- cgit v1.2.3