
JSON.stringify 는 일상적인 개발에 자주 사용되는 방법인데 정말 유연하게 사용할 수 있을까요?
이 기사를 공부하기 전에 Xiaobao는 모든 사람이 몇 가지 질문을 받고 stringify 깊이 배우기를 원합니다.
stringify 함수에는 여러 매개변수가 있습니다. 각 매개변수의 용도는 무엇입니까?stringify 직렬화 지침은 무엇입니까? null、undefined、NaN 입니까?ES6 Symbol 유형과 BigInt 의 직렬화 과정에서 특별한 처리가 있습니까?stringify 딥 카피에 적합하지 않은 이유stringify 무엇입니까?전체 기사의 맥락이 아래 마인드 맵과 일치합니다. 먼저 인상을 남길 수 있습니다.

일상적인 프로그래밍에서는 객체를 JSON 문자열 형식으로 변환하기 위해 종종 JSON.stringify 메서드를 사용합니다.
const 스투 = {
이름: 'zcxiaobao',
나이: 18
}
// {"이름":"zcxiaobao","나이":18}
console.log(JSON.stringify(stu)); 그런데 stringify 정말 그렇게 간단할까요? 먼저 MDN 에서 stringify 의 정의를 살펴보겠습니다.
MDN 상태: JSON.stringify() 메서드는 JavaScript 개체 또는 값을 JSON 문자열로 변환합니다. replacer 함수가 지정된 경우 값을 선택적으로 대체할 수 있거나 지정된 replacer 배열로 지정된 속성을 포함합니다. .
정의를 읽은 후 Xiaobao는 stringfy 매개변수가 두 개 이상 있습니까?에 놀랐습니다. 물론 stringify 세 개의 매개변수가 있습니다.
stringify 구문과 매개변수 소개를 살펴보겠습니다.
JSON.stringify(value[, replacement [, space]])
value : JSON 문자열로 시퀀스될 값입니다.replacer (선택 사항) 매개변수가 함수 인 경우 직렬화 프로세스 중에 직렬화된 값의 각 속성이 변환되어
매개변수가 배열 인 경우 이 배열에 포함된 속성만 처리됩니다
이름은 최종 JSON 문자열로 직렬화됩니다.
이 매개변수가 null 이거나 제공되지 않으면 개체의 모든 속성이 직렬화됩니다.
space (선택 사항): 출력을 아름답게 하는 데 사용되는 들여쓰기에 사용되는 공백 문자열을 지정합니다. 매개변수가 숫자인 경우 공백 수를 나타냅니다. 상한은 10입니다.
값이 1보다 작으면 공백이 없다는 의미입니다.
매개변수가 문자열인 경우(문자열의 길이가 10자를 초과하는 경우 처음 10자를 사용함) 문자열은 공백으로 처리됩니다
.
없습니다
. replacer 를 사용해 보겠습니다.
함수로서 replacer
replacer 로서 키( key )와 값( value )이라는 두 개의 매개변수를 가지며 두 매개변수 모두 직렬화됩니다.
처음에는 교체 함수가 빈 문자열을 키 값으로 전달하여 문자열화할 개체를 나타냅니다 . 이를 이해하는 것이 중요합니다. replacer 함수는 객체가 나타날 때 키-값 쌍으로 구문 분석하지 않지만 먼저 직렬화할 객체 를 전달합니다. 그런 다음 각 개체나 배열의 속성이 순차적으로 전달됩니다. 함수 반환 값이 정의되지 않았거나 function인 경우 속성 값은 필터링되고 나머지는 반환 규칙을 따릅니다.
// repalcer는 두 개의 매개변수 키 값을 허용합니다.
// 키 값은 객체의 각 키-값 쌍이므로 // 키 또는 값의 유형을 기준으로 간단히 필터링할 수 있습니다. function replacement(key, value) {
if (값 유형 === "문자열") {
정의되지 않은 반환;
}
반환값;
}
// 함수는 함수 자체를 테스트할 수 있습니다. replacementFunc(key, value) {
if (값 유형 === "문자열") {
반환 () => {};
}
반환값;
}
const foo = {foundation: "Mozilla", 모델: "box", 주: 45, 운송: "car", 월: 7};
const jsonString = JSON.stringify(foo, replacement); JSON 직렬화 결과는 {"week":45,"month":7}
이지만 직렬화가 배열인 경우 replacer 함수가 undefined 또는 function을 반환하는 경우 현재 값 무시되지 않으며 null 로 대체됩니다.
const 목록 = [1, '22', 3] const jsonString = JSON.stringify(list, replacement)
JSON 직렬화의 결과는 '[1,null,3]'입니다.
replacer
배열에 나타나는 키 값을 필터링하여 배열로 이해하기 쉽습니다.
const foo = {foundation: "Mozilla", 모델: "box", 주: 45, 운송: "car", 월: 7};
const jsonString = JSON.stringify(foo, ['week', 'month']); JSON 직렬화 결과는 {"week":45,"month":7} 이고 week 및 month 속성 값만 유지됩니다.
: undefined , 모든 함수 및 Symbol 값은 직렬화 프로세스 중에 무시 됩니다
undefined 및 Symbol 값은 무시됩니다 .
단독으로 null로 변환하면: undefine이 반환됩니다.
// 1. 객체 속성 값에 이 세 가지 값이 있으면 무시됩니다. const obj = {
이름: 'zc',
나이: 18,
// 함수는 무시됩니다. sayHello() {
console.log('안녕하세요')
},
// 정의되지 않은 것은 무시됩니다 wife: undefine,
// 기호 값은 무시됩니다. id: Symbol(111),
// [기호('zc')]: 'zc',
}
// 출력 결과: {"name":"zc","age":18}
console.log(JSON.stringify(obj));
// 2. 배열의 이 세 값은 null로 변환됩니다.
const 목록 = [
'zc',
18,
// null로 변환된 함수
함수 sayHello() {
console.log('안녕하세요')
},
// 정의되지 않음이 null로 변환됨
한정되지 않은,
// null로 변환된 기호
기호(111)
]
// ["zc",18,널,널,널]
console.log(JSON.stringify(목록))
// 3. 이 세 가지 값을 별도로 변환하면 정의되지 않은 값이 반환됩니다.
console.log(JSON.stringify(undefine)) // 정의되지 않음
console.log(JSON.stringify(Symbol(111))) // 정의되지 않음
console.log(JSON.stringify(function sayHello() {
console.log('안녕하세요')
})) // 정의되지 않은 값을 변환합니다. toJSON() 메서드가 있는 경우 toJSON() 메서드가 반환하는 값은 직렬화 결과가 반환하는 값이 되며, 다른 값은 다음과 같습니다. 무시되었습니다.
const 객체 = {
이름: 'zc',
toJSON(){
'JSON으로 돌아가기'를 반환합니다.
}
}
//JSON으로 돌아갑니다.
console.log(JSON.stringify(obj)); 부울 값, 숫자 및 문자열에 대한 패키징 개체. 부울 값, 숫자 및 문자열에 대한 패키징 개체는 직렬화 프로세스 중에 해당 원래 값 JSON으로 자동 변환됩니다.
. stringify([new Number(1), new String("zcxiaobao"), new Boolean(true)]);
// [1,"zcxiaobao",true] 기능 4는 주로 NaN , Infinity 및 Number 유형의 null과 같은 JavaScript 의 특수 값을 목표로 합니다. 이 세 가지 유형의 값은 직렬화 중에 null 로 처리됩니다 .
// [널,널,널,널,널]
JSON.stringify([null, NaN, -NaN, Infinity, -Infinity])
// 기능 3에서는 부울 값, 숫자, 문자열의 패키징 객체가 직렬화 과정에서 해당 원래 값으로 자동 변환된다고 언급했습니다. // 암시적 유형 변환은 패키징 클래스를 호출하므로 Number => NaN이 됩니다. 먼저 전화했다
// 그런 다음 null로 변환합니다.
// 1/0 => 무한대 => null
JSON.stringify([Number('123a'), +'123a', 1/0]) toJSON 메서드( Date.toISOString() 와 동일)는 Date 객체에 배포되어 Date 객체로 변환됩니다. 문자열이므로 JSON.stringify()는 날짜 값을 시간 형식 문자열로 직렬화합니다 .
// "2022-03-06T08:24:56.138Z" JSON.stringify(new Date())
Symbol 기능을 언급할 때 Symbol 유형을 값으로 사용할 때 개체, 배열 및 개별 용도가 무시되고 각각 null 로 변환되고 undefined 으로 변환됩니다.
마찬가지로, 속성 키로 Symbol이 있는 모든 속성은 강제로 replacement 매개변수에 포함되더라도 완전히 무시됩니다 .
const 객체 = {
이름: 'zcxiaobao',
나이: 18,
[Symbol('lyl')]: '고유'
}
함수 대체자(키, 값) {
if (키 유형 === '기호') {
반환값;
}
}
// 한정되지 않은
JSON.stringify(obj, replacement); 위의 경우를 보면, replacer 통해 return Symbol 유형 값을 강제로 지정하더라도 결국 무시되는 것을 알 수 있습니다.
JSON.stringify 다음을 규정합니다. BigInt 유형의 값을 변환하려고 하면 TypeError 발생합니다.
const bigNumber = BigInt(1) // Uncaught TypeError: BigInt를 직렬화하는 방법을 모릅니다. Console.log(JSON.stringify(bigNumber))
기능 8은 다음을 지적합니다. 순환 참조(객체가 서로를 참조하여 무한 루프를 형성함)를 포함하는 객체에서 이 메서드를 실행하면
Daily Development Deep Copy가 발생
합니다.가장 간단하고 가장 폭력적인 방법은 JSON.parse(JSON.stringify(obj)) 사용하는 것이지만 이 방법의 전체 복사에는 큰 함정이 있습니다. 중요한 문제는 stringify 순환 참조 문제를 처리할 수 없다는 것입니다.
const 객체 = {
이름: 'zcxiaobao',
나이: 18,
}
const loopObj = {
객체
}
// 순환 참조 형성 obj.loopObj = loopObj;
JSON.stringify(obj)
/* Uncaught TypeError: 순환 구조를 JSON으로 변환하는 중
--> 생성자 'Object'를 사용하여 객체에서 시작
| 속성 'loopObj' -> 'Object' 생성자가 있는 객체
--- 'obj' 속성이 원을 닫습니다.
JSON.stringify에서 (<anonymous>)
<익명>:10:6
*/ 위에서 언급한 일부 상황 외에도 객체의 열거 가능 속성( Map/Set/WeakMap/WeakSet 포함) 직렬화의 경우 stringify 열거 가능 속성만 직렬화된다는 점을 명확하게 규정합니다.
// 비열거 가능 속성은 기본적으로 무시됩니다. // {"age":18}
JSON.stringify(
객체.생성(
널,
{
이름: { 값: 'zcxiaobao', 열거 가능: false },
나이: { 값: 18, 열거 가능: true }
}
)
); localStorage 객체는 전체 웹사이트의 데이터를 장기간 저장하는 데 사용됩니다. 저장된 데이터는 수동으로 삭제될 때까지 만료 시간이 없습니다. 보통 우리는 그것을 객체 형태로 저장합니다.
간단히 localStorage 객체 메서드를 호출하면 됩니다.
const obj = {
이름: 'zcxiaobao',
나이: 18
}
// 간단히 localStorage.setItem()을 호출합니다.
localStorage.setItem('zc', obj);
//최종 반환 결과는 [object Object]입니다.
// 단순히 localStorage 호출이 실패하는 것을 볼 수 있습니다. console.log(localStorage.getItem('zc')) localStorage JSON.stringify 메소드와 협력합니다.
localStorage.setItem('zc', JSON.stringify(obj));
//최종 반환 결과는 {name: 'zcxiaobao', age: 18}입니다.
Console.log(JSON.parse(localStorage.getItem('zc'))) 이러한 시나리오를 가정합니다. 백엔드는 많은 속성이 포함된 긴 개체를 반환하며 그 중 몇 개만 저장하면 됩니다. localStorage 의 속성.
옵션 1: 구조 분해 할당 + stringify
// a, e, f 속성만 필요합니다 const obj = {
a:1, b:2, c:3, d:4, e:5, f:6, g:7
}
// 구조 분해 할당 const {a,e,f} = obj;
//localStorage에 저장
localStorage.setItem('zc', JSON.stringify({a,e,f}))
// {"a":1,"e":5,"f":6}
console.log(localStorage.getItem('zc'))는 stringify 의 replacer 매개변수를 사용합니다.
// 대체자를 사용하여 배열로 필터링합니다. localStorage.setItem('zc', JSON.stringify(obj, ['a','e') , 'f']))
// {"a":1,"e":5,"f":6}
console.log(localStorage.getItem('zc')) replacer 배열인 경우 필요한 속성을 간단히 필터링할 수 있는데 이는 좋은 트릭입니다.
JSON.parse(JSON.stringify) 사용하는 것은 개체의 전체 복사본을 구현하는 가장 간단하고 폭력적인 방법 중 하나입니다. 그러나 제목에서 알 수 있듯이 이러한 딥 카피 방법을 사용하려면 신중한 고려가 필요합니다.
순환 참조 문제, stringify 오류 함수를 보고합니다
. undefined , Symbol 무시됩니다.
NaN , Infinity 및 -Infinity 는 null 로 직렬화됩니다
.
따라서 JSON.parse(JSON.stringify) 사용하여 전체 복사를 수행하는 경우 다음을 수행해야 합니다. 신중하게 생각해보세요. 위에서 언급한 숨겨진 위험이 없다면 JSON.parse(JSON.stringify) 실행 가능한 전체 복사 솔루션입니다.
배열로 프로그래밍할 때 우리는 종종 map 함수를 사용합니다. replacer 매개변수를 사용하면 이 매개변수를 사용하여 객체의 map 기능을 구현할 수 있습니다.
const ObjectMap = (obj, fn) => {
if (fn 유형 !== "함수") {
throw new TypeError(`${fn}은 함수가 아닙니다!`);
}
// 먼저 JSON.stringify(obj, replacement)를 호출하여 지도 함수를 구현합니다. // 그런 다음 JSON.parse를 호출하여 객체로 다시 변환합니다. return JSON.parse(JSON.stringify(obj, fn));
};
// 예를 들어, 다음은 obj 객체의 속성 값에 2를 곱합니다.
const 객체 = {
답: 1,
비: 2,
ㄷ: 3
}
console.log(ObjectMap(obj, (key, val) => {
if (값 유형 === "숫자") {
반환값 * 2;
}
반환값;
})) 왜 추가 판단이 필요한지 궁금해하는 학생들이 많을 것입니다. 단지 return value * 2 것은 가능하지 않나요?
위에서 언급한 대로 replacer 함수는 먼저 직렬화할 객체를 전달합니다. 객체 * 2 => NaN => toJSON(NaN) => undefine =>은 무시되며 후속 키-값 쌍 분석은 없습니다.
replacer 기능을 사용하면 객체의 특정 속성을 삭제할 수도 있습니다.
const 객체 = {
이름: 'zcxiaobao',
나이: 18
}
// {"나이":18}
JSON.stringify(obj, (key, val) => {
// 반환 값이 정의되지 않은 경우 이 속성은 무시됩니다. if (key === 'name') {
정의되지 않은 반환;
}
가치를 반환;
}) JSON.stringify 객체를 문자열로 직렬화할 수 있으므로 문자열 메서드를 사용하여 간단한 객체 동등 판단을 구현할 수 있습니다.
//배열에 객체가 포함되어 있는지 확인 const names = [
{이름:'zcxiaobao'},
{이름:'txtx'},
{이름:'내내'},
];
const zcxiaobao = {이름:'zcxiaobao'};
// 진실
JSON.stringify(이름).includes(JSON.stringify(zcxiaobao))
// 객체가 동일한지 확인 const d1 = {type: 'div'}
const d2 = {유형: 'div'}
// 진실
JSON.stringify(d1) === JSON.stringify(d2); 위 아이디어의 도움으로 간단한 배열 객체 중복 제거도 달성할 수 있습니다.
하지만 JSON.stringify 직렬화 {x:1, y:1} 과 {y:1, x:1} 의 결과가 다르기 때문에 시작하기 전에 배열의 개체를 처리해야 합니다.
방법 1: 배열의 각 객체의 키를 사전 순서로 정렬합니다.
arr.forEach(item => {
const newItem = {};
Object.keys(item) // 객체 키 가져오기 value.sort() // 키 값 sorting.map(key => { // 새 객체 생성 newItem[key] = item[key];
})
// newItem을 사용하여 중복 제거 작업 수행}) 그러나 방법 1은 약간 번거롭습니다. JSON.stringify 배열을 필터링할 수 있는 replacer 배열 형식 매개변수를 제공합니다.
방법 2: replacer 배열 형식
함수 고유(arr) { 사용
const keySet = 새로운 Set();
const UniqueObj = {}
// 모든 키 추출 arr.forEach(item => {
Object.keys(item).forEach(key => keySet.add(key))
})
const 대체자 = [...keySet];
arr.forEach(항목 => {
// 모든 객체는 지정된 키 값에 따라 필터링됩니다. replacement Unique[JSON.stringify(item, replacement)] = item;
})
return Object.keys(unique).map(u => JSON.parse(u))
}
//고유한 테스트([{}, {},
{x:1},
{x:1},
{a:1},
{x:1,a:1},
{x:1,a:1},
{x:1,a:1,b:1}
])
// 결과 반환 [{},{"x":1},{"a":1},{"x":1,"a":1},{"x":1,"a":1 ,"b":1}]