Skip to content

Commit 5b9799b

Browse files
committed
docs: js/04-object-basic/02-object-copy 충돌 해결
1 parent f623a8f commit 5b9799b

1 file changed

Lines changed: 0 additions & 208 deletions

File tree

Lines changed: 0 additions & 208 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,16 @@
1-
<<<<<<< HEAD
21
# 참조에 의한 객체 복사
32

43
객체와 원시 타입의 근본적인 차이 중 하나는 객체는 '참조에 의해(by reference)' 저장되고 복사된다는 것입니다.
54

65
원시값(문자열, 숫자, 불린 값)은 '값 그대로' 저장·할당되고 복사되는 반면에 말이죠.
76

87
예시:
9-
=======
10-
# Object references and copying
11-
12-
One of the fundamental differences of objects versus primitives is that objects are stored and copied "by reference", whereas primitive values: strings, numbers, booleans, etc -- are always copied "as a whole value".
13-
14-
That's easy to understand if we look a bit under the hood of what happens when we copy a value.
15-
16-
Let's start with a primitive, such as a string.
17-
18-
Here we put a copy of `message` into `phrase`:
19-
>>>>>>> upstream/master
208

219
```js
2210
let message = "Hello!";
2311
let phrase = message;
2412
```
2513

26-
<<<<<<< HEAD
2714
예시를 실행하면 두 개의 독립된 변수에 각각 문자열 `"Hello!"`가 저장됩니다.
2815

2916
![](variable-copy-value.svg)
@@ -33,19 +20,6 @@ let phrase = message;
3320
**변수엔 객체가 그대로 저장되는 것이 아니라, 객체가 저장되어있는 '메모리 주소'인 객체에 대한 '참조 값'이 저장됩니다.**
3421

3522
그림을 통해 변수 user에 객체를 할당할 때 무슨 일이 일어나는지 알아봅시다.
36-
=======
37-
As a result we have two independent variables, each one storing the string `"Hello!"`.
38-
39-
![](variable-copy-value.svg)
40-
41-
Quite an obvious result, right?
42-
43-
Objects are not like that.
44-
45-
**A variable assigned to an object stores not the object itself, but its "address in memory" -- in other words "a reference" to it.**
46-
47-
Let's look at an example of such a variable:
48-
>>>>>>> upstream/master
4923

5024
```js
5125
let user = {
@@ -57,21 +31,9 @@ And here's how it's actually stored in memory:
5731

5832
![](variable-contains-reference.svg)
5933

60-
<<<<<<< HEAD
6134
객체는 메모리 내 어딘가에 저장되고, 변수 `user`엔 객체를 '참조'할 수 있는 값이 저장됩니다.
6235

6336
따라서 **객체가 할당된 변수를 복사할 땐 객체의 참조 값이 복사되고 객체는 복사되지 않습니다.**
64-
=======
65-
The object is stored somewhere in memory (at the right of the picture), while the `user` variable (at the left) has a "reference" to it.
66-
67-
We may think of an object variable, such as `user`, like a sheet of paper with the address of the object on it.
68-
69-
When we perform actions with the object, e.g. take a property `user.name`, the JavaScript engine looks at what's at that address and performs the operation on the actual object.
70-
71-
Now here's why it's important.
72-
73-
**When an object variable is copied, the reference is copied, but the object itself is not duplicated.**
74-
>>>>>>> upstream/master
7537

7638
예시:
7739

@@ -81,21 +43,11 @@ let user = { name: "John" };
8143
let admin = user; // 참조값을 복사함
8244
```
8345

84-
<<<<<<< HEAD
8546
변수는 두 개이지만 각 변수엔 동일 객체에 대한 참조 값이 저장되죠.
8647

8748
![](variable-copy-reference.svg)
8849

8950
따라서 객체에 접근하거나 객체를 조작할 땐 여러 변수를 사용할 수 있습니다.
90-
=======
91-
Now we have two variables, each storing a reference to the same object:
92-
93-
![](variable-copy-reference.svg)
94-
95-
As you can see, there's still one object, but now with two variables that reference it.
96-
97-
We can use either variable to access the object and modify its contents:
98-
>>>>>>> upstream/master
9951

10052
```js run
10153
let user = { name: 'John' };
@@ -109,25 +61,15 @@ admin.name = 'Pete'; // 'admin' 참조 값에 의해 변경됨
10961
alert(*!*user.name*/!*); // 'Pete'가 출력됨. 'user' 참조 값을 이용해 변경사항을 확인함
11062
```
11163
112-
<<<<<<< HEAD
11364
객체를 서랍장에 비유하면 변수는 서랍장을 열 수 있는 열쇠라고 할 수 있습니다. 서랍장은 하나, 서랍장을 열 수 있는 열쇠는 두 개인데, 그중 하나(`admin`)를 사용해 서랍장을 열어 정돈한 후, 또 다른 열쇠로 서랍장을 열면 정돈된 내용을 볼 수 있습니다.
114-
=======
115-
It's as if we had a cabinet with two keys and used one of them (`admin`) to get into it and make changes. Then, if we later use another key (`user`), we are still opening the same cabinet and can access the changed contents.
116-
>>>>>>> upstream/master
11765
11866
### 참조에 의한 비교
11967
120-
<<<<<<< HEAD
12168
객체 비교 시 동등 연산자 `==`와 일치 연산자 `===`는 동일하게 동작합니다.
12269
12370
**비교 시 피연산자인 두 객체가 동일한 객체인 경우에 참을 반환하죠.**
12471
12572
두 변수가 같은 객체를 참조하는 예시를 살펴봅시다. 일치·동등 비교 모두에서 참이 반환됩니다.
126-
=======
127-
Two objects are equal only if they are the same object.
128-
129-
For instance, here `a` and `b` reference the same object, thus they are equal:
130-
>>>>>>> upstream/master
13173
13274
```js run
13375
let a = {};
@@ -137,11 +79,7 @@ alert( a == b ); // true, 두 변수는 같은 객체를 참조합니다.
13779
alert( a === b ); // true
13880
```
13981
140-
<<<<<<< HEAD
14182
다른 예시를 살펴봅시다. 두 객체 모두 비어있다는 점에서 같아 보이지만, 독립된 객체이기 때문에 일치·동등 비교하면 거짓이 반환됩니다.
142-
=======
143-
And here two independent objects are not equal, even though they look alike (both are empty):
144-
>>>>>>> upstream/master
14583
14684
```js run
14785
let a = {};
@@ -150,53 +88,17 @@ let b = {}; // 독립된 두 객체
15088
alert( a == b ); // false
15189
```
15290
153-
<<<<<<< HEAD
15491
`obj1 > obj2` 같은 대소 비교나 `obj == 5` 같은 원시값과의 비교에선 객체가 원시형으로 변환됩니다. 객체가 어떻게 원시형으로 변하는지에 대해선 곧 학습할 예정인데, 이러한 비교(객체끼리의 대소 비교나 원시값과 객체를 비교하는 것)가 필요한 경우는 매우 드물긴 합니다. 대개 코딩 실수 때문에 이런 비교가 발생합니다.
15592
15693
## 객체 복사, 병합과 Object.assign
157-
=======
158-
For comparisons like `obj1 > obj2` or for a comparison against a primitive `obj == 5`, objects are converted to primitives. We'll study how object conversions work very soon, but to tell the truth, such comparisons are needed very rarely -- usually they appear as a result of a programming mistake.
159-
160-
````smart header="Const objects can be modified"
161-
An important side effect of storing objects as references is that an object declared as `const` *can* be modified.
162-
163-
For instance:
164-
165-
```js run
166-
const user = {
167-
name: "John"
168-
};
169-
170-
*!*
171-
user.name = "Pete"; // (*)
172-
*/!*
173-
174-
alert(user.name); // Pete
175-
```
176-
177-
It might seem that the line `(*)` would cause an error, but it does not. The value of `user` is constant, it must always reference the same object, but properties of that object are free to change.
178-
179-
In other words, the `const user` gives an error only if we try to set `user=...` as a whole.
180-
181-
That said, if we really need to make constant object properties, it's also possible, but using totally different methods. We'll mention that in the chapter <info:property-descriptors>.
182-
````
183-
184-
## Cloning and merging, Object.assign [#cloning-and-merging-object-assign]
185-
>>>>>>> upstream/master
18694
18795
객체가 할당된 변수를 복사하면 동일한 객체에 대한 참조 값이 하나 더 만들어진다는 걸 배웠습니다.
18896
189-
<<<<<<< HEAD
19097
그런데 객체를 복제하고 싶다면 어떻게 해야 할까요? 기존에 있던 객체와 똑같으면서 독립적인 객체를 만들고 싶다면 말이죠.
19198
19299
방법은 있는데 자바스크립트는 객체 복제 내장 메서드를 지원하지 않기 때문에 조금 어렵습니다. 사실 객체를 복제해야 할 일은 거의 없습니다. 참조에 의한 복사로 해결 가능한 일이 대다수이죠.
193100
194101
정말 복제가 필요한 상황이라면 새로운 객체를 만든 다음 기존 객체의 프로퍼티들을 순회해 원시 수준까지 프로퍼티를 복사하면 됩니다.
195-
=======
196-
But what if we need to duplicate an object?
197-
198-
We can create a new object and replicate the structure of the existing one, by iterating over its properties and copying them on the primitive level.
199-
>>>>>>> upstream/master
200102
201103
아래와 같이 말이죠.
202104
@@ -221,36 +123,21 @@ clone.name = "Pete"; // clone의 데이터를 변경합니다.
221123
alert( user.name ); // 기존 객체에는 여전히 John이 있습니다.
222124
```
223125
224-
<<<<<<< HEAD
225126
[Object.assign](mdn:js/Object/assign)를 사용하는 방법도 있습니다.
226-
=======
227-
We can also use the method [Object.assign](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign).
228-
>>>>>>> upstream/master
229127
230128
문법과 동작 방식은 다음과 같습니다.
231129
232130
```js
233131
Object.assign(dest, ...sources)
234132
```
235133
236-
<<<<<<< HEAD
237134
- 첫 번째 인수 `dest`는 목표로 하는 객체입니다.
238135
- 이어지는 인수 `src1, ..., srcN`는 복사하고자 하는 객체입니다. `...`은 필요에 따라 얼마든지 많은 객체를 인수로 사용할 수 있다는 것을 나타냅니다.
239136
- 객체 `src1, ..., srcN`의 프로퍼티를 `dest`에 복사합니다. `dest`를 제외한 인수(객체)의 프로퍼티 전부가 첫 번째 인수(객체)로 복사됩니다.
240137
- 마지막으로 `dest`를 반환합니다.
241138
242139
`assign` 메서드를 사용해 여러 객체를 하나로 병합하는 예시를 살펴봅시다.
243140
```js
244-
=======
245-
- The first argument `dest` is a target object.
246-
- Further arguments is a list of source objects.
247-
248-
It copies the properties of all source objects into the target `dest`, and then returns it as the result.
249-
250-
For example, we have `user` object, let's add a couple of permissions to it:
251-
252-
```js run
253-
>>>>>>> upstream/master
254141
let user = { name: "John" };
255142

256143
let permissions1 = { canView: true };
@@ -277,11 +164,7 @@ Object.assign(user, { name: "Pete" });
277164
alert(user.name); // user = { name: "Pete" }
278165
```
279166
280-
<<<<<<< HEAD
281167
`Object.assign`을 사용하면 반복문 없이도 간단하게 객체를 복사할 수 있습니다.
282-
=======
283-
We also can use `Object.assign` to perform a simple object cloning:
284-
>>>>>>> upstream/master
285168
286169
```js run
287170
let user = {
@@ -297,21 +180,11 @@ alert(clone.name); // John
297180
alert(clone.age); // 30
298181
```
299182
300-
<<<<<<< HEAD
301183
예시를 실행하면 `user`에 있는 모든 프로퍼티가 빈 배열에 복사되고 변수에 할당됩니다.
302-
=======
303-
Here it copies all properties of `user` into the empty object and returns it.
304-
305-
There are also other methods of cloning an object, e.g. using the [spread syntax](info:rest-parameters-spread) `clone = {...user}`, covered later in the tutorial.
306-
>>>>>>> upstream/master
307184
308185
## 중첩 객체 복사
309186
310-
<<<<<<< HEAD
311187
지금까진 `user`의 모든 프로퍼티가 원시값인 경우만 가정했습니다. 그런데 프로퍼티는 다른 객체에 대한 참조 값일 수도 있습니다. 이 경우는 어떻게 해야 할까요?
312-
=======
313-
Until now we assumed that all properties of `user` are primitive. But properties can be references to other objects.
314-
>>>>>>> upstream/master
315188
316189
아래와 같이 말이죠.
317190
```js run
@@ -326,13 +199,9 @@ let user = {
326199
alert( user.sizes.height ); // 182
327200
```
328201
329-
<<<<<<< HEAD
330202
`clone.sizes = user.sizes`로 프로퍼티를 복사하는 것만으론 객체를 복제할 수 없습니다. `user.sizes`는 객체이기 때문에 참조 값이 복사되기 때문입니다. `clone.sizes = user.sizes`로 프로퍼티를 복사하면 `clone``user`는 같은 sizes를 공유하게 됩니다.
331203
332204
아래와 같이 말이죠.
333-
=======
334-
Now it's not enough to copy `clone.sizes = user.sizes`, because `user.sizes` is an object, and will be copied by reference, so `clone` and `user` will share the same sizes:
335-
>>>>>>> upstream/master
336205
337206
```js run
338207
let user = {
@@ -347,7 +216,6 @@ let clone = Object.assign({}, user);
347216

348217
alert( user.sizes === clone.sizes ); // true, 같은 객체입니다.
349218

350-
<<<<<<< HEAD
351219
// user와 clone는 sizes를 공유합니다.
352220
user.sizes.width++; // 한 객체에서 프로퍼티를 변경합니다.
353221
alert(clone.sizes.width); // 51, 다른 객체에서 변경 사항을 확인할 수 있습니다.
@@ -358,87 +226,11 @@ alert(clone.sizes.width); // 51, 다른 객체에서 변경 사항을 확인할
358226
깊은 복사 시 사용되는 표준 알고리즘인 [Structured cloning algorithm](https://html.spec.whatwg.org/multipage/structured-data.html#safe-passing-of-structured-data)을 사용하면 위 사례를 비롯한 다양한 상황에서 객체를 복제할 수 있습니다.
359227
360228
자바스크립트 라이브러리 [lodash](https://lodash.com)의 메서드인 [_.cloneDeep(obj)](https://lodash.com/docs#cloneDeep)을 사용하면 이 알고리즘을 직접 구현하지 않고도 깊은 복사를 처리할 수 있으므로 참고하시기 바랍니다.
361-
=======
362-
// user and clone share sizes
363-
user.sizes.width = 60; // change a property from one place
364-
alert(clone.sizes.width); // 60, get the result from the other one
365-
```
366-
367-
To fix that and make `user` and `clone` truly separate objects, we should use a cloning loop that examines each value of `user[key]` and, if it's an object, then replicate its structure as well. That is called a "deep cloning" or "structured cloning". There's [structuredClone](https://developer.mozilla.org/en-US/docs/Web/API/structuredClone) method that implements deep cloning.
368-
369-
370-
### structuredClone
371-
372-
The call `structuredClone(object)` clones the `object` with all nested properties.
373-
374-
Here's how we can use it in our example:
375-
376-
```js run
377-
let user = {
378-
name: "John",
379-
sizes: {
380-
height: 182,
381-
width: 50
382-
}
383-
};
384-
385-
*!*
386-
let clone = structuredClone(user);
387-
*/!*
388-
389-
alert( user.sizes === clone.sizes ); // false, different objects
390-
391-
// user and clone are totally unrelated now
392-
user.sizes.width = 60; // change a property from one place
393-
alert(clone.sizes.width); // 50, not related
394-
```
395-
396-
The `structuredClone` method can clone most data types, such as objects, arrays, primitive values.
397-
398-
It also supports circular references, when an object property references the object itself (directly or via a chain or references).
399-
400-
For instance:
401-
402-
```js run
403-
let user = {};
404-
// let's create a circular reference:
405-
// user.me references the user itself
406-
user.me = user;
407-
408-
let clone = structuredClone(user);
409-
alert(clone.me === clone); // true
410-
```
411-
412-
As you can see, `clone.me` references the `clone`, not the `user`! So the circular reference was cloned correctly as well.
413-
414-
Although, there are cases when `structuredClone` fails.
415-
416-
For instance, when an object has a function property:
417-
418-
```js run
419-
// error
420-
structuredClone({
421-
f: function() {}
422-
});
423-
```
424-
425-
Function properties aren't supported.
426-
427-
To handle such complex cases we may need to use a combination of cloning methods, write custom code or, to not reinvent the wheel, take an existing implementation, for instance [_.cloneDeep(obj)](https://lodash.com/docs#cloneDeep) from the JavaScript library [lodash](https://lodash.com).
428-
>>>>>>> upstream/master
429229
430230
## 요약
431231
432-
<<<<<<< HEAD
433232
객체는 참조에 의해 할당되고 복사됩니다. 변수엔 '객체' 자체가 아닌 메모리상의 주소인 '참조'가 저장됩니다. 따라서 객체가 할당된 변수를 복사하거나 함수의 인자로 넘길 땐 객체가 아닌 객체의 참조가 복사됩니다.
434-
=======
435-
Objects are assigned and copied by reference. In other words, a variable stores not the "object value", but a "reference" (address in memory) for the value. So copying such a variable or passing it as a function argument copies that reference, not the object itself.
436-
>>>>>>> upstream/master
437233
438234
그리고 복사된 참조를 이용한 모든 작업(프로퍼티 추가·삭제 등)은 동일한 객체를 대상으로 이뤄집니다.
439235
440-
<<<<<<< HEAD
441236
객체의 '진짜 복사본'을 만들려면 '얕은 복사(shallow copy)'를 가능하게 해주는 `Object.assign`이나 '깊은 복사'를 가능하게 해주는 [_.cloneDeep(obj)](https://lodash.com/docs#cloneDeep)를 사용하면 됩니다. 이때 얕은 복사본은 중첩 객체를 처리하지 못한다는 점을 기억해 두시기 바랍니다.
442-
=======
443-
To make a "real copy" (a clone) we can use `Object.assign` for the so-called "shallow copy" (nested objects are copied by reference) or a "deep cloning" function `structuredClone` or use a custom cloning implementation, such as [_.cloneDeep(obj)](https://lodash.com/docs#cloneDeep).
444-
>>>>>>> upstream/master

0 commit comments

Comments
 (0)