JavaScript 기본 심법 - 깊이 복사
환영 스타.
잘못된 점 이 있 으 면 지적 을 환영 합 니 다.
얕 은 복사 와 깊 은 복사 모두 JS 의 인용 유형 에 있어 얕 은 복사 본 은 복사 대상 의 인용 일 뿐 복사 후의 대상 이 변화 하면 원래 의 대상 도 변화 할 수 있다.깊 은 복사 만 이 진정 으로 대상 에 대한 복사 이다.
머리말
깊이 복사 하면 먼저 JavaScript 의 데이터 형식 을 언급 해 야 합 니 다. 이전의 글 은 JavaScript 기초 심법 인 데이터 형식 을 분명하게 말 했 습 니 다. 여 기 는 더 이상 말 하지 않 겠 습 니 다.
알 아야 할 것 은 자바 스 크 립 트 의 데이터 형식 은 기본 데이터 형식 과 참조 데이터 형식 으로 나 뉜 다 는 것 이다.
기본 데이터 형식의 복사 에 있어 깊이 복사 의 차이 가 없다. 우리 가 말 하 는 깊이 복사 는 모두 데이터 형식 을 인용 하 는 데 있어 서 이다.
얕 은 복사
얕 은 복사 란 인용 만 복사 하고 진짜 값 은 복사 하지 않 는 다 는 뜻 이다.
const originArray = [1,2,3,4,5];
const originObj = {a:'a',b:'b',c:[1,2,3],d:{dd:'dd'}};
const cloneArray = originArray;
const cloneObj = originObj;
console.log(cloneArray); // [1,2,3,4,5]
console.log(originObj); // {a:'a',b:'b',c:Array[3],d:{dd:'dd'}}
cloneArray.push(6);
cloneObj.a = {aa:'aa'};
console.log(cloneArray); // [1,2,3,4,5,6]
console.log(originArray); // [1,2,3,4,5,6]
console.log(cloneObj); // {a:{aa:'aa'},b:'b',c:Array[3],d:{dd:'dd'}}
console.log(originArray); // {a:{aa:'aa'},b:'b',c:Array[3],d:{dd:'dd'}}
위의 코드 는 가장 간단 한 이용
=
할당 연산 자 를 이용 하여 얕 은 복사 본 을 실현 하 였 으 며, cloneArray
과 cloneObj
의 변화 에 따라 originArray
와 originObj
도 이에 따라 변화 하 였 음 을 뚜렷하게 볼 수 있다.딥 카피
깊 은 복사 란 목표 에 대한 완전한 복사 이다. 얕 은 복사 처럼 인용 만 복사 한 것 이 아니 라 값 도 복사 한 것 이다.
깊 은 복사 만 하면 그들 은 죽어도 서로 왕래 하지 않 고 누구 에 게 도 영향 을 주지 않 는 다.
현재 심 복 사 를 실현 하 는 방법 은 많 지 않 으 며 주로 두 가지 이다.
JSON
대상 중 parse
과 stringify
먼저 이 두 가지 방법 을 봅 시다.
The JSON.stringify() method converts a JavaScript value to a JSON string.
JSON.stringify
는 하나의 JavaScript
값 을 하나의 JSON
문자열 로 바 꾸 는 것 이다.The JSON.parse() method parses a JSON string, constructing the JavaScript value or object described by the string.
JSON.parse
은 하나의 JSON
문자열 을 하나의 JavaScript
값 이나 대상 으로 바 꾸 는 것 이다.잘 이해 하 시 죠? 바로
JavaScript
값 과 JSON
문자열 의 상호 전환 입 니 다.그것 은 깊 은 복사 본 을 실현 할 수 있 습 니까?한번 해 보 자.
const originArray = [1,2,3,4,5];
const cloneArray = JSON.parse(JSON.stringify(originArray));
console.log(cloneArray === originArray); // false
const originObj = {a:'a',b:'b',c:[1,2,3],d:{dd:'dd'}};
const cloneObj = JSON.parse(JSON.stringify(originObj));
console.log(cloneObj === originObj); // false
cloneObj.a = 'aa';
cloneObj.c = [1,1,1];
cloneObj.d.dd = 'doubled';
console.log(cloneObj); // {a:'aa',b:'b',c:[1,1,1],d:{dd:'doubled'}};
console.log(originObj); // {a:'a',b:'b',c:[1,2,3],d:{dd:'dd'}};
깊 게 복사 하 는 것 도 편 하고.그러나 이 방법 은 간단 한 상황 에 만 적용 된다.예 를 들 어 아래 와 같은 대상 은 적용 되 지 않 는 다.
const originObj = {
name:'axuebin',
sayHello:function(){
console.log('Hello World');
}
}
console.log(originObj); // {name: "axuebin", sayHello: ƒ}
const cloneObj = JSON.parse(JSON.stringify(originObj));
console.log(cloneObj); // {name: "axuebin"}
cloneObj
에서 속성 을 잃 어 버 린 것 을 발 견 했 습 니 다...그게 왜 죠?MDN
에서 원인 을 찾 았 다.If undefined, a function, or a symbol is encountered during conversion it is either omitted (when it is found in an object) or censored to null (when it is found in an array). JSON.stringify can also just return undefined when passing in "pure" values like JSON.stringify(function(){}) or JSON.stringify(undefined).
undefined
, function
, symbol
전환 과정 에서 무시 된다.아 시 겠 죠? 대상 에 함수 가 하나 있 을 때 (흔 합 니 다) 이 방법 으로 깊이 복사 할 수 없습니다.
재 귀적 방법
재 귀적 인 사상 은 매우 간단 하 다. 즉, 모든 층 의 데이터 에 대해 한 번
->
의 조작 을 실현 하고 간단 하고 거 친 코드 를 사용 하 는 것 이다.function deepClone(source){
const targetObj = source.constructor === Array ? [] : {}; //
for(let keys in source){ //
if(source.hasOwnProperty(keys)){
if(source[keys] && typeof source[keys] === 'object'){ // ,
targetObj[keys] = source[keys].constructor === Array ? [] : {};
targetObj[keys] = deepClone(source[keys]);
}else{ // ,
targetObj[keys] = source[keys];
}
}
}
return targetObj;
}
우리 한번 해 보 자.
const originObj = {a:'a',b:'b',c:[1,2,3],d:{dd:'dd'}};
const cloneObj = deepClone(originObj);
console.log(cloneObj === originObj); // false
cloneObj.a = 'aa';
cloneObj.c = [1,1,1];
cloneObj.d.dd = 'doubled';
console.log(cloneObj); // {a:'aa',b:'b',c:[1,1,1],d:{dd:'doubled'}};
console.log(originObj); // {a:'a',b:'b',c:[1,2,3],d:{dd:'dd'}};
네.그럼 함수 가 있 는 것 을 다시 시도 해 보 세 요.
const originObj = {
name:'axuebin',
sayHello:function(){
console.log('Hello World');
}
}
console.log(originObj); // {name: "axuebin", sayHello: ƒ}
const cloneObj = deepClone(originObj);
console.log(cloneObj); // {name: "axuebin", sayHello: ƒ}
그 럴 수도 있어.해결 하 다.
이게 끝 인 줄 알았지?아니 지.
JavaScript 의 복사 방법
우 리 는
JavaScript
에서 수조 에 두 가지 방법 concat
과 slice
이 원수 조 에 대한 복 사 를 실현 할 수 있다 는 것 을 알 고 있다. 이 두 가지 방법 은 원수 조 를 수정 하지 않 고 수 정 된 새로운 수조 로 되돌아간다.아울러 ES6 에는
Object.assgn
방법 과 ...
연산 자 전개 도 대상 에 대한 복사 가 가능 하도록 도입 됐다.그럼 그것들 은 얕 은 복사 입 니까? 깊 은 복사 입 니까?
concat
The concat() method is used to merge two or more arrays. This method does not change the existing arrays, but instead returns a new array.
이 방법 은 두 개 이상 의 배열 을 연결 할 수 있 지만 존재 하 는 배열 을 수정 하지 않 고 새 배열 로 돌아 갑 니 다.
이 뜻 을 보 니 깊 은 복사 같 군요. 한번 해 보 겠 습 니 다.
const originArray = [1,2,3,4,5];
const cloneArray = originArray.concat();
console.log(cloneArray === originArray); // false
cloneArray.push(6); // [1,2,3,4,5,6]
console.log(originArray); [1,2,3,4,5];
깊 게 복사 한 것 같 습 니 다.
이 대상 이 다 층 이 라면 어떻게 될 지 생각해 보 자.
const originArray = [1,[1,2,3],{a:1}];
const cloneArray = originArray.concat();
console.log(cloneArray === originArray); // false
cloneArray[1].push(4);
cloneArray[2].a = 2;
console.log(originArray); // [1,[1,2,3,4],{a:2}]
originArray
에는 배열 [1,2,3]
과 대상 {a:1}
이 포함 되 어 있 는데 우리 가 배열 과 대상 을 직접 수정 하면 영향 을 주지 않 는 다 originArray
. 그러나 우리 가 배열 [1,2,3]
이나 대상 {a:1}
을 수정 할 때 originArray
도 변화 한 것 으로 나 타 났 다.결론:
concat
배열 의 1 층 을 깊이 복사 할 뿐이다.slice
The slice() method returns a shallow copy of a portion of an array into a new array object selected from begin to end (end not included). The original array will not be modified.
설명 에 다 써 있어 요.
a shallow copy
하지만, 결코!const originArray = [1,2,3,4,5];
const cloneArray = originArray.slice();
console.log(cloneArray === originArray); // false
cloneArray.push(6); // [1,2,3,4,5,6]
console.log(originArray); [1,2,3,4,5];
마찬가지 로, 우 리 는 다 층 의 수 조 를 시험 해 보 자.
const originArray = [1,[1,2,3],{a:1}];
const cloneArray = originArray.slice();
console.log(cloneArray === originArray); // false
cloneArray[1].push(4);
cloneArray[2].a = 2;
console.log(originArray); // [1,[1,2,3,4],{a:2}]
역시 결 과 는
concat
과 같 았 다.결론:
slice
배열 의 1 층 을 깊이 복사 할 뿐이다.Object.assign()
The Object.assign() method is used to copy the values of all enumerable own properties from one or more source objects to a target object. It will return the target object.
복사, 복사, 복사.
그것 은 도대체 얕 은 복사 입 니까? 깊 은 복사 입 니까?
직접 해 보 세 요.
결론:
Object.assign()
복사 한 것 은 속성 값 이다.원본 대상 의 속성 값 이 대상 을 가리 키 는 참조 라면 인용 값 만 복사 합 니 다.연산 자 펼 치기
const originArray = [1,2,3,4,5,[6,7,8]];
const originObj = {a:1,b:{bb:1}};
const cloneArray = [...originArray];
cloneArray[0] = 0;
cloneArray[5].push(9);
console.log(originArray); // [1,2,3,4,5,[6,7,8,9]]
const cloneObj = {...originObj};
cloneObj.a = 2;
cloneObj.b.bb = 2;
console.log(originObj); // {a:1,b:{bb:2}}
결론:
...
대상 1 층 의 깊 은 복사 가 이 루어 졌 다.뒤에 있 는 것 은 복사 한 인용 값 일 뿐 입 니 다.첫 번 째 얕 은 복사
우 리 는 목표 대상 의 1 층 을 깊이 복사 한 다음 에 뒤의 것 은 얕 은 복사 로 '1 층 얕 은 복사' 라 고 할 수 있다 는 것 을 알 게 되 었 다.
우 리 는 스스로 이런 함 수 를 실현 할 수 있다.
function shallowClone(source) {
const targetObj = source.constructor === Array ? [] : {}; //
for (let keys in source) { //
if (source.hasOwnProperty(keys)) {
targetObj[keys] = source[keys];
}
}
return targetObj;
}
테스트 해 보 겠 습 니 다.
const originObj = {a:'a',b:'b',c:[1,2,3],d:{dd:'dd'}};
const cloneObj = shallowClone(originObj);
console.log(cloneObj === originObj); // false
cloneObj.a='aa';
cloneObj.c=[1,1,1];
cloneObj.d.dd='surprise';
위의 수정 을 통 해
cloneObj
말 할 것 도 없 이 {a:'aa',b:'b',c:[1,1,1],d:{dd:'surprise'}}
일 것 이다. 그럼 originObj
은?방금 우 리 는 cloneObj === originObj
이 false
라 는 것 을 검증 했다. 이 두 대상 의 인용 주소 가 다르다 는 것 을 설명 한다. 그것 은 바로 수정 cloneObj
이 영향 을 주지 않 는 다 는 것 이다 originObj
.console.log(cloneObj); // {a:'aa',b:'b',c:[1,1,1],d:{dd:'surprise'}}
console.log(originObj); // {a:'a',b:'b',c:[1,2,3],d:{dd:'surprise'}}
What happend?
originObj
에서 관련 a
, c
은 모두 영향 을 받 지 않 았 으 나 d
중의 한 대상 이 수정 되 었 다.깊 게 복사 하기 로 했 는데?인용 주소 가 다 르 잖 아 요.그 렇 군요.
shallowClone
의 코드 에서 알 수 있 듯 이 우 리 는 1 층 의 목표
만 실 시 했 고 2 층 에서 시 작 된 목 표 는 =
할당 연산 자 를 직접 이용 하여 복사 한 것 이다.총결산
=
는 얕 은 복사 로 대상 의 인용 값 만 복사 합 니 다.JSON.stringify
은 깊 은 복사 본 을 실현 하지만 목표 대상 에 대한 요구 가 있다.이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
React의 이벤트 핸들러에서 "Cannot read property '〇〇' of undefined"라고 나온다ES6 기법으로 React 코드를 쓰고 있을 때 이벤트 핸들러 내에서 this 를 사용할 수 없게 되었기 때문에 그 원인을 공유합니다. App.jsx 이 경우 브라우저에서 실행해 보면 다음과 같이 표시됩니다. 이 버...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.