diff options
author | EuAndreh <eu@euandre.org> | 2024-11-18 08:21:58 -0300 |
---|---|---|
committer | EuAndreh <eu@euandre.org> | 2024-11-18 08:44:57 -0300 |
commit | 960e4410f76801356ebd42801c914b2910a302a7 (patch) | |
tree | 615d379416f72956d0c1666c63ce062859041fbe /src/content/tils/2021/08/11/js-bigint-reviver.adoc | |
parent | Remove jekyll infrastructure setup (diff) | |
download | euandre.org-960e4410f76801356ebd42801c914b2910a302a7.tar.gz euandre.org-960e4410f76801356ebd42801c914b2910a302a7.tar.xz |
Diffstat (limited to 'src/content/tils/2021/08/11/js-bigint-reviver.adoc')
-rw-r--r-- | src/content/tils/2021/08/11/js-bigint-reviver.adoc | 100 |
1 files changed, 100 insertions, 0 deletions
diff --git a/src/content/tils/2021/08/11/js-bigint-reviver.adoc b/src/content/tils/2021/08/11/js-bigint-reviver.adoc new file mode 100644 index 0000000..d71174d --- /dev/null +++ b/src/content/tils/2021/08/11/js-bigint-reviver.adoc @@ -0,0 +1,100 @@ +--- + +title: Encoding and decoding JavaScript BigInt values with reviver + +date: 2021-08-11 + +updated_at: 2021-08-13 + +layout: post + +lang: en + +ref: encoding-and-decoding-javascript-bigint-values-with-reviver + +--- + +`JSON.parse()` accepts a second parameter: a [`reviver()` function][reviver]. +It is a function that can be used to transform the `JSON` values as they're +being parsed. + +[reviver]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse#using_the_reviver_parameter + +As it turns out, when combined with JavaScript's [`BigInt`] type, you can parse +and encode JavaScript `BigInt` numbers via JSON: + +[`BigInt`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt + +```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: + +```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: + +```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: + +``` +[ + 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`] doesn't include `BigInt` number, encoding and decoding them +as strings is quite trivial on JavaScript. + +[`JSON`]: https://datatracker.ietf.org/doc/html/rfc8259 |