diff options
author | EuAndreh <eu@euandre.org> | 2025-04-18 02:17:12 -0300 |
---|---|---|
committer | EuAndreh <eu@euandre.org> | 2025-04-18 02:48:42 -0300 |
commit | 020c1e77489b772f854bb3288b9c8d2818a6bf9d (patch) | |
tree | 142aec725a52162a446ea7d947cb4347c9d573c9 /src/content/en/tils/2021/08/11/js-bigint-reviver.adoc | |
parent | Makefile: Remove security.txt.gz (diff) | |
download | euandre.org-020c1e77489b772f854bb3288b9c8d2818a6bf9d.tar.gz euandre.org-020c1e77489b772f854bb3288b9c8d2818a6bf9d.tar.xz |
git mv src/content/* src/content/en/
Diffstat (limited to 'src/content/en/tils/2021/08/11/js-bigint-reviver.adoc')
-rw-r--r-- | src/content/en/tils/2021/08/11/js-bigint-reviver.adoc | 89 |
1 files changed, 89 insertions, 0 deletions
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. |