By BlackLivesMatter translator: DevInduct
Have a dream, have dry goods, wechat search [big Move the world] pay attention to this in the early morning is still in the bowl washing wisdom. In this paper, making github.com/qq449245884… Has been included, a line of large factory interview complete test sites, information and my series of articles.
Json.stringify is a frequently used method that converts JavaScript values and objects into strings. Such as:
JSON.stringify({ foo: "bar" }); // => '{"foo":"bar"}' JSON.stringify(123); / / = > '123'Copy the code
But there are many things wrong with JS, and this function is no exception. We might imagine that a function called “stringify “always returns a string…… But it didn’t!
For example, if you try stringify undefined, it returns undefined instead of a string.
JSON.stringify(undefined);
// => undefined
Copy the code
Next, I will talk about it in two parts:
- list
JSON.stringify
The case where no string is returned - How can we avoid these pitfalls
What timeJSON.stringify
Does not return a string?
Undefined, arbitrary functions, and symbol values are ignored during serialization (when appearing in an attribute value of a non-array object) or converted to NULL (when appearing in an array). Function undefined returns undefined when converted separately.
Executing this method on objects that contain circular references (objects that refer to each other in an infinite loop) throws an error
I think it’s surprising that json.stringify can return something other than a string. But there are six cases in which it can return undefined:
- Try to pair at the top
undefined
Serialization, returnsundefined
.
JSON.stringify(undefined);
// => undefined
Copy the code
- Attempts to serialize the function also return
undefined
. This is true for regular functions, arrow functions, asynchronous functions, and generator functions.
JSON.stringify(function foo() {});
// => undefined
JSON.stringify(() => {});
// => undefined
function bar() {}
bar.someProperty = 123;
JSON.stringify(bar);
// => undefined
Copy the code
- Attempts to serialize symbol are also returned
undefined
.
JSON.stringify(Symbol("computers were a mistake"));
// => undefined
Copy the code
- In the browser, attempts to serialize are deprecated
document.all
Also returnsundefined
.
// => undefined
Copy the code
This only affects browsers, because document.all is not available in other environments, such as Node.
- with
toJSON
The objects of the function will be run instead of trying to serialize them normally. But if thetoJSON
Return one of the above values and attempting to serialize it at the top level will resultJSON.stringify
returnundefined
.
JSON.stringify({ toJSON: () => undefined });
// => undefined
JSON.stringify({ ignored: true, toJSON: () => undefined });
// => undefined
JSON.stringify({ toJSON: () => Symbol("heya") });
// => undefined
Copy the code
- You can pass a second argument, called “replacer”, which changes the serialization logic. If this function returns one of these values for the top level,
JSON.stringify
Will returnundefined
.
JSON.stringify({ ignored: true }, () => undefined);
// => undefined
JSON.stringify(["ignored"], () => Symbol("hello"));
// => undefined
Copy the code
It’s important to note that many of these things really only affect top-level serialization. For example, json.stringify ({foo: undefined}), which returns the string “{}”, is not surprising.
I also want to mention that TypeScript type definitions are incorrect here. For example, the following code types can be verified by:
const result: string = JSON.stringify(undefined);
Copy the code
In Part 2, we’ll discuss how to update TypeScript definitions to ensure they are correct.
Json.stringify may also encounter problems that cause it to throw an error. Under normal circumstances, four things happen:
- A circular reference causes a type error to be thrown.
const b = { a };
a.b = b;
JSON.stringify(a);
// => TypeError: cyclic object value
Copy the code
Note that these error messages may differ from browser to browser; for example, Firefox’s error message is different from Chrome’s.
- BigInts can’t use
JSON.stringify
Serialization, which also results in a TypeError.
JSON.stringify(12345678987654321n);
// => TypeError: BigInt value can't be serialized in JSON
JSON.stringify({ foo: 456n });
// => TypeError: BigInt value can't be serialized in JSON
Copy the code
- with
toJSON
The object of the function will be run. If these functions throw an error, it will bubble up to the caller.
const obj = { foo: "ignored", toJSON() { throw new Error("Oh no!" ); }}; JSON.stringify(obj); // => Error: Oh no!Copy the code
- You can pass a second argument called
replacer
. If this function throws an error, it will bubble.
JSON.stringify({}, () => { throw new Error("Uh oh!" ); }); // => Error: Uh oh!Copy the code
Now that we’ve seen that json.stringify doesn’t return a string, let’s look at how to avoid these problems.
How to avoid these problems
There is no general approach to how to resolve these defects, so here are some common ones.
Handling circular references
From personal experience, json.stringify is the most error-prone when passing circular references. If this is a common problem for you, I recommend the JSON-stringify-safe package, which handles this situation well.
const stringifySafe = require("json-stringify-safe");
const a = {};
const b = { a };
a.b = b;
JSON.stringify(a);
// => TypeError: cyclic object value
stringifySafe(a);
// => '{"b":{"a":"[Circular ~]"}}'
Copy the code
encapsulation
You may want to wrap json.stringify with your own custom functions. You can decide what you want it to do. Should mistakes come up? What if json. stringify returns undefined?
For example, Signal Desktop has a function called reallyJsonStringify, which always returns a string for debugging. Like this
function reallyJsonStringify(value) { let result; try { result = JSON.stringify(value); } catch (_err) { // If there's any error, treat it like `undefined`. result = undefined; } if (typeof result === "string") { // It's a string, so we're good. return result; } else { // Convert it to a string. return Object.prototype.toString.call(value); }}Copy the code
A description of TypeScript types
If you already use TypeScript, you may be surprised to learn that TypeScript’s official definition of json.stringify is incorrect here. They actually look like this:
// JSON {//... stringify(value: any): string; }Copy the code
Unfortunately, this is a long-standing problem and there is no perfect solution.
You can try tinkering with json.stringify’s type, but each solution has certain drawbacks. I recommend defining your own wrappers with custom types and. For example, the template for Signal Desktop’s reallyJsonStringify:
function reallyJsonStringify(value: unknown): string {
// ...
Copy the code
conclusion
JSON.stringify
Sometimes it comes backundefined
Instead of a stringJSON.stringify
Sometimes an error is thrown- We can solve this problem by wrapping functions in different ways
Hopefully this article has given you a more complete understanding of json.stringify.
I’m a dishwasher, and I’ll see you next time.
The bugs that may exist after code deployment cannot be known in real time. In order to solve these bugs, I spent a lot of time on log debugging. Incidentally, I recommend a good BUG monitoring tool for youFundebug.
Original text: evanhahn.com/when-string…
communication
Have a dream, have dry goods, wechat search [big Move the world] pay attention to this in the early morning is still in the bowl washing wisdom.
In this paper, making github.com/qq449245884… Has been included, a line of large factory interview complete test sites, information and my series of articles.