Author: BlackLivesMatter
Translator: Frontend Xiaozhi
Source: devinduct
There are dreams, dry goods, WeChat search [Da Qian World] Pay attention to this Shuawanzhi who is still doing dishes in the early morning.
This article GitHub https://github.com/qq449245884/xiaozhi has been included, the first-line interview complete test site, information and my series of articles.
JSON.stringify
is a method we often use. Its main function is to convert JavaScript values and objects into strings. like:
JSON.stringify({ foo: "bar" });
// => '{"foo":"bar"}'
JSON.stringify(123);
// => '123'
But JS has problems in many places, and this function is no exception. We might imagine a function called "stringify" always returns a string... but it doesn't!
For example, if you try to stringify undefined
, it returns undefined
instead of a string.
JSON.stringify(undefined);
// => undefined
Next, I will talk about it in two parts:
- List
JSON.stringify
does not return a string - How will we avoid these pitfalls
When does JSON.stringify
not return a string?
undefined
, any function, and the symbol
will be ignored during serialization (when it appears in the property value of a non-array object) or converted to null
(when it appears in an array). When the function, undefined
is converted separately, it will return undefined
.
Executing this method on objects that contain circular references (referring to each other to form an infinite loop) will throw an error
I think JSON.stringify
can return something other than a string is quite surprised. But in 6 cases, it can return undefined
:
- Attempting to serialize
undefined
at the top levelundefined
.
JSON.stringify(undefined);
// => undefined
- Trying to serialize the function will 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
- Trying to serialize the symbol will also return
undefined
.
JSON.stringify(Symbol("computers were a mistake"));
// => undefined
- In the browser, trying to serialize the obsolete
document.all
will also returnundefined
.
// => undefined
This only affects the browser, because document.all is not available in other environments, such as Node.
- Objects with the
toJSON
will be run instead of trying to serialize them normally. But iftoJSON
returns one of the above values, trying to serialize at the top level will causeJSON.stringify
to returnundefined
.
JSON.stringify({ toJSON: () => undefined });
// => undefined
JSON.stringify({ ignored: true, toJSON: () => undefined });
// => undefined
JSON.stringify({ toJSON: () => Symbol("heya") });
// => undefined
- You can pass the second parameter, called "replacer", which can change the logic of serialization. If this function returns one of the above values for the top level,
JSON.stringify
will returnundefined
.
JSON.stringify({ ignored: true }, () => undefined);
// => undefined
JSON.stringify(["ignored"], () => Symbol("hello"));
// => undefined
It should be noted that many of these things actually only affect the serialization of the top level. For example, JSON.stringify({foo: undefined})
returns the string "{}"
, which is not surprising.
I also want to mention that the type definition of TypeScript is incorrect here. For example, the following code type verification can pass:
const result: string = JSON.stringify(undefined);
In Part 2, we will discuss how to update the TypeScript definition to ensure its correctness.
JSON.stringify
may also encounter a problem, causing it to throw an error. Under normal circumstances, four situations will occur:
- Circular references will cause a type error to be thrown.
const b = { a };
a.b = b;
JSON.stringify(a);
// => TypeError: cyclic object value
Note that these error messages may be different in different browsers. For example, the error message of Firefox is different from that of Chrome.
- BigInts cannot
JSON.stringify
, these will also cause 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
- The object with the
toJSON
will be run. If these functions throw errors, it will bubble up to the caller.
const obj = {
foo: "ignored",
toJSON() {
throw new Error("Oh no!");
},
};
JSON.stringify(obj);
// => Error: Oh no!
- You can pass the second parameter, called
replacer
. If this function throws an error, it will bubble up.
JSON.stringify({}, () => {
throw new Error("Uh oh!");
});
// => Error: Uh oh!
Now that we have seen that JSON.stringify
does not return a string, let's take a look at how to avoid these problems.
How to avoid these problems
There is no general method on how to solve these deficiencies, so here are only some common situations.
Handling circular references
According to personal experience, JSON.stringify
is most prone to errors when passing circular references. If this is a common problem for you, I recommend the json-stringify-safe package, which can handle 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 ~]"}}'
Encapsulation
You may want to encapsulate JSON.stringify
with your own custom function. You can decide what you want it to do. Should the error come up? What should I do JSON.stringify
returns undefined
For example, Signal Desktop has a , 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);
}
}
A note about TypeScript types
If you are already using TypeScript, you may be surprised to find that TypeScript JSON.stringify
is incorrect here. They actually look like this:
// Note: 这里面简化过
interface JSON {
// ...
stringify(value: any): string;
}
Unfortunately, this is a long-standing problem , not a perfect solution.
You can try to fix JSON.stringify
, but each solution has certain disadvantages. I recommend using a custom type to define your own wrapper and. For example, the template of reallyJsonStringify
function reallyJsonStringify(value: unknown): string {
// ...
Summarize
JSON.stringify
sometimes returnsundefined
instead of a stringJSON.stringify
sometimes throws an error- We can solve this problem by wrapping the function in different ways
Hope this article gives you a more comprehensive understanding JSON.stringify
I'm the wise man who encourages me to go home and set up a street stall after retirement. See you next time.
code is deployed, the possible bugs cannot be known in real time. In order to solve these bugs afterwards, a lot of time was spent on log debugging. By the way, I would like to recommend a useful BUG monitoring tool Fundebug .
Original: https://evanhahn.com/when-stringify-doesnt-return-a-string
comminicate
If you have dreams and dry goods, search for [Moving to the World] Follow this brushing wit who is still doing dishes in the early morning.
This article GitHub https://github.com/qq449245884/xiaozhi has been included, the first-line interview complete test site, information and my series of articles.
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。