Skip to content

Commit 57d008f

Browse files
[네이티브 프로토타입] 리뷰
1 parent 1f166ea commit 57d008f

File tree

1 file changed

+54
-54
lines changed

1 file changed

+54
-54
lines changed
Lines changed: 54 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,33 @@
11
# 네이티브 프로토타입
22

3-
`prototype` 프로퍼티는 자바스크립트 내에서 널리 이용됩니다. 모든 내장 생성자 함수에서 사용됩니다.
3+
`prototype` 프로퍼티는 자바스크립트 내부에서도 광범위하게 사용됩니다. 모든 내장 생성자 함수에서 `prototype` 프로퍼티를 사용하죠.
44

55
첫 번째로 자세히 살펴본 다음 어떻게 내장 객체에 새 기능을 추가하여 프로토타입 프로퍼티를 사용하는지 알아보겠습니다.
66

77
## Object.prototype
88

9-
빈 객체를 표현한다고 생각해 봅시다.
9+
빈 객체를 표현한다고 봅시다.
1010

1111
```js run
1212
let obj = {};
1313
alert( obj ); // "[object Object]" ?
1414
```
1515

16-
`"[object Object]"` 문자열을 생성하는 코드는 어디에 있나요? 이는 내장 `toString` 메서드 입니다. 하지만 어디에 있을까요? `obj`는 비어 있습니다!
16+
`"[object Object]"` 문자열을 생성하는 코드는 어디에 있을까요? `toString` 메서드에서 이 문자열을 생성한다는 것을 앞서 배워서 알고 있지만 도대체 코드는 어디에 있는 걸까요? `obj`는 비어 있는데 말이죠.
1717

18-
`obj = {}`의 줄임법은 `obj = new Object()`와 같습니다. 여기서 `Object`큰 객체에 `toString`메서드와 다른 메서드으로 큰 객체를 참조하는 자체 프로토타입을 가진 내장 객체 생성자 함수입니다.
18+
`obj = new Object()`를 줄이면 `obj = {}`가 됩니다. 여기서 `Object`내장 객체 생성자 함수인데, 이 생성자 함수의 `prototype``toString`을 비롯한 다양한 메서드가 구현되어있는 거대한 객체를 참조합니다.
1919

20-
어떤 일이 벌어지는지 보겠습니다.
20+
그림을 이용해 살펴봅시다.
2121

2222
![](object-prototype.svg)
2323

24-
`new Object()`를 호출하거나 실제 객체 `{...}`가 생성되었다고 할 때 객체의 `[Prototype]`은 이전 챕터에서 얘기한 룰에 따라서 `Object.prototype`으로 설정됩니다.
24+
`new Object()`를 호출하거나 리터럴 문법 `{...}`을 사용해 객체를 만들 때, 새롭게 생성된 객체의 `[[Prototype]]`은 이전 챕터에서 언급한 규칙에 따라 `Object.prototype`을 참조합니다.
2525

2626
![](object-prototype-1.svg)
2727

28-
따라서 `obj.toString()`이 호출될 때 메서드는 `Object.prototype`으로부터 가져옵니다.
28+
따라서 `obj.toString()`을 호출하면 `Object.prototype`에서 해당 메서드를 가져오게 되죠.
2929

30-
예제를 확인해 봅시다.
30+
예시를 통해 이를 확인할 수 있습니다.
3131

3232
```js run
3333
let obj = {};
@@ -36,80 +36,80 @@ alert(obj.__proto__ === Object.prototype); // true
3636
// obj.toString === obj.__proto__.toString == Object.prototype.toString
3737
```
3838

39-
`Object.prototype`위의 체인에는 더 이상`[[Prototype]]`없는 점을 알아두세요.
39+
그런데 이때 `Object.prototype` 위의 체인엔 `[[Prototype]]`없다는 점을 주의하셔야 합니다.
4040

4141
```js run
4242
alert(Object.prototype.__proto__); // null
4343
```
4444

4545
## 다른 내장 프로토타입
4646

47-
`Array`, `Date`, `Function`포함한 다른 내장 객체들 또한 메서드를 프로토타입 안에 유지합니다.
47+
`Array`, `Date`, `Function`비롯한 내장 객체들 역시 프로토타입에 메서드를 저장해 놓습니다.
4848

49-
예를 들면 배열`[1, 2, 3]` 을 생성할 때 기본 `new Array()` 생성자는 내부적으로 사용됩니다. 그래서 `Array.prototype`이 프로토타입이 되고 메서드를 제공하게 됩니다. 이는 상당히 메모리 효율적입니다.
49+
배열 `[1, 2, 3]`을 만들면 기본 `new Array()` 생성자가 내부에서 사용되기 때문에 `Array.prototype`배열 `[1, 2, 3]`프로토타입이 되죠. `Array.prototype`은 배열 메서드도 제공합니다. 이런 내부 동작은 메모리 효율을 높여주는 장점을 가져다줍니다.
5050

51-
구체적으로 모든 내장 프로토타입은 `Object.prototype`을 가장 위에 가집니다. 이 때문에 몇몇 사람들은 "모든 것은 객체로부터 온다"라고 말합니다.
51+
명세서에선 모든 내장 프로토타입의 꼭대기엔 `Object.prototype`이 있어야 한다고 규정합니다. 이런 규정 때문에 몇몇 사람들은 "모든 것은 객체를 상속받는다."라는 말을 하죠.
5252

53-
여기 전체적인 3개의 내장객체에 대한 그림이 있습니다.
53+
세 개의 내장 객체를 이용해 전체적인 그림을 그리면 다음과 같습니다.
5454

5555
![](native-prototypes-classes.svg)
5656

57-
프로토타입을 각각 확인해 봅시다.
57+
각 내장 객체의 프로토타입을 확인해 보겠습니다.
5858

5959
```js run
6060
let arr = [1, 2, 3];
6161

62-
// Array.prototype으로부터 상속되었나?
62+
// arr은 Array.prototype을 상속받았나요?
6363
alert( arr.__proto__ === Array.prototype ); // true
6464

65-
// 그럼 Object.prototype부터?
65+
// arr은 Object.prototype을 상속받았나요?
6666
alert( arr.__proto__.__proto__ === Object.prototype ); // true
6767

68-
// 그리고 가장 위의 null값
68+
// 체인 맨 위엔 null이 있습니다.
6969
alert( arr.__proto__.__proto__.__proto__ ); // null
7070
```
7171

72-
몇몇 프로토타입의 메서드가 중복이 될 수도 있습니다. 예를 들어 `Array.prototype`쉼표를 통해 구분된 요소들을 나열하는 자기 자신의 `toString`를 가집니다.
72+
체인 상의 프로토타입엔 중복 메서드가 있을 수 있습니다. `Array.prototype`엔 요소 사이에 쉼표를 넣어 요소 전체를 합친 문자열을 반환하는 자체 메서드 `toString`가 있습니다.
7373

7474
```js run
7575
let arr = [1, 2, 3]
7676
alert(arr); // 1,2,3 <-- Array.prototype.toString 의 결과
7777
```
7878

79-
전에 보았던 대로, `Object.prototype` 또한 `toString`을 가지고 있습니다. 그러나 `Array.prototype`체인에 더 가깝기 때문에 Array의 toString이 사용되었습니다.
79+
그런데 `Object.prototype`에도 메서드 `toString`있습니다. 이렇게 중복 메서드가 있을 때는 체인 상에서 가까운 곳에 있는 메서드가 사용됩니다. `Array.prototype`체인 상에서 더 가깝기 때문에 `Array.prototype``toString`이 사용되죠.
8080

8181

8282
![](native-prototypes-array-tostring.svg)
8383

8484

85-
Chrome 개발자 콘솔과 같은 브라우저 툴 내에서는 상속을 보여줍니다.(`console.dir`는 아마 내장 객체를 사용하기 위해 필요합니다.)
85+
Chrome 개발자 콘솔과 같은 도구를 사용하면 상속 관계를 확인할 수 있습니다. `console.dir`를 사용하면 내장 객체의 상속 관계를 확인하는 데 도움이 됩니다.
8686

8787
![](console_dir_array.png)
8888

89-
다른 내장 객체들 또한 같은 방법으로 동작합니다. 심지어 내장 `Function`객체 함수 생성자와 메서드(`call`/`apply` 등등)들도 `Fuction.prototype`으로 부터 가져옵니다. 함수 또한 자기 자신의`toString`를 가지고 있습니다.
89+
배열이 아닌 다른 내장 객체들 또한 같은 방법으로 동작합니다. 함수도 마찬가지이죠. 함수는 내장 객체 `Function`생성자를 사용해 만들어지는데 `call`, `apply`를 비롯한 함수에서 사용할 수 있는 메서드는 `Fuction.prototype`에서 가져옵니다. 함수에도 `toString`이 구현되어 있습니다.
9090

9191
```js run
9292
function f() {}
9393

9494
alert(f.__proto__ == Function.prototype); // true
95-
alert(f.__proto__.__proto__ == Object.prototype); // true, inherit from objects
95+
alert(f.__proto__.__proto__ == Object.prototype); // true, 객체에서 상속받음
9696
```
9797

9898
## 원시값
9999

100-
가장 복잡한 것은 문자열, 숫자 그리고 불값과 함께 생깁니다.
100+
문자열과 숫자 불린값을 다루는 것은 엄청 까다롭습니다.
101101

102-
기억하다시피 이것들은 객체가 아닙니다. 그러나 그들의 프로퍼티에 접근하려고 시도한다면 내장 생성자 `String`, `Number`, `Boolean`을 사용하는 임시 래퍼 객체가 생성되며 메서드를 제공하고 사라집니다.
102+
문자열과 숫자 불린값은 객체가 아닙니다. 그런데 이런 원시값들의 프로퍼티에 접근하려고 하면 내장 생성자 `String`, `Number`, `Boolean`을 사용하는 임시 래퍼 객체가 생성됩니다. 임시 래퍼 객체는 이런 메서드를 제공하고 난 후에 사라집니다.
103103

104-
이러한 객체들은 눈에 보이지 않게 생성되고 대부분의 엔진은 이를 최적화합니다. 명세서에도 이처럼 묘사됩니다. 객체들의 메서드는 `String.prototype`, `Number.prototype`, `Boolean.prototype`처럼 사용할 수 있는 프로토타입 안에 존재합니다.
104+
래퍼 객체는 보이지 않는 곳에서 만들어집니다. 최적화는 엔진이 담당하죠. 그런데 명세서에선 각 자료형에 해당하는 래퍼 객체의 메서드를 프로토타입 안에 구현해 놓고 `String.prototype`, `Number.prototype`, `Boolean.prototype`을 사용해 쓸 수 있도록 규정합니다.
105105

106-
```warn header="`null``undefined`의 값은 객체 래퍼를 가지지 않습니다."
107-
특수한 값인 `null``undefined`다른 것과는 거리가 있습니다. 객체 래퍼가 없기 때문에 메서드와 프로퍼티를 이용할 수 없습니다. 그리고 해당하는 프로퍼티도 존재하지 않습니다.
106+
```warn header="`null``undefined`에 대응하는 래퍼 객체는 없습니다."
107+
특수 값인 `null``undefined`문자열과 숫자 불린값과는 거리가 있습니다. `null``undefined`에 대응하는 래퍼 객체는 없죠. 따라서 `null``undefined`에선 메서드와 프로퍼티를 이용할 수 없습니다. 프로토타입도 물론 사용할 수 없습니다.
108108
```
109109
110-
## 네이티브 프로토타입 변경[#native-prototype-change]
110+
## 네이티브 프로토타입 변경하기[#native-prototype-change]
111111
112-
네이티브 프로토타입은 변경될 수 있습니다. 예를 들어 메서드를 `String.prototype`에 추가한다면 모든 문자열에서 `String.prototype`을 사용할 수 있습니다.
112+
네이티브 프로토타입을 수정할 수 있습니다. `String.prototype`에 메서드를 하나 추가하면 모든 문자열에서 해당 메서드를 사용할 수 있죠.
113113
114114
```js run
115115
String.prototype.show = function() {
@@ -119,32 +119,32 @@ String.prototype.show = function() {
119119
"BOOM!".show(); // BOOM!
120120
```
121121

122-
개발과정 도중 사용자의 편의에 따른 새로운 내장 메서드를 생성할 수 있습니다. 또한 새로운 내장 메서드를 네이티브 프로토타입에 추가할 수도 있습니다. 그러나 일반적으로 좋지 않은 아이디어입니다.
122+
개발을 하다 보면 "새로운 내장 메서드를 만드는 게 좋지 않을까?"라는 생각이 들 때가 있습니다. 네이티브 프로토타입에 새 내장 메서드를 추가하고 싶은 유혹이 자꾸 생기죠. 그런데 이는 좋지 않은 방법입니다.
123123

124124
```warn
125-
프로토타입은 전체에 영향을 미칩니다. 그래서 충돌이 쉽게 일어나는데 두 개의 라이브러리에서 `String.prototype.show` 메서드를 추가할 때 하나의 라이브러리에서 다른 하나의 라이브러리의 메서드를 덮어쓰게 됩니다.
125+
프로토타입은 전역으로 영향을 미치기 때문에 프로토타입을 조작하면 충돌이 날 가능성이 높습니다. 두 라이브러리에서 동시에 `String.prototype.show` 메서드를 추가하면 한 라이브러리의 메서드가 다른 라이브러리의 메서드를 덮어쓰죠.
126126
127-
그래서 일반적으로 네이티브 프로토타입을 수정하는 것은 좋지 않은 아이디어입니다.
127+
이런 이유로 네이티브 프로토타입을 수정하는 것을 추천하지 않습니다.
128128
```
129129

130-
**모던 프로그래밍에서는 오직 한 경우에만 네이티브 프로토타입 변경을 허용하고 있는데 바로 폴리필링입니다.**
130+
**모던 프로그래밍에서 네이티브 프로토타입 변경을 허용하는 경우는 딱 하나뿐입니다. 바로 폴리필을 만들 때입니다.**
131131

132-
폴리필링은 자바스크립트 명세서에 존재하는 메서드에 대한 대체재를 만드는 데 사용하는데 현재의 자바스크립트 엔진에서는 아직 지원하지 않습니다.
132+
폴리필은 자바스크립트 명세서에 있는 메서드와 동일한 기능을 하는 메서드 구현체를 의미합니다. 명세서에는 정의되어 있으나 특정 자바스크립트 엔진에서는 해당 기능이 구현되어있지 않을 때 폴리필을 사용합니다.
133133

134-
따라서 폴리필링을 수동으로 실행하며 내장 프로토타입과 함께 값을 가져옵니다.
134+
폴리필을 직접 구현하고 난 후 폴리필을 내장 프로토타입에 추가할 때만 네이티브 프로토타입을 변경합시다.
135135

136136
예시:
137137

138138
```js run
139-
if (!String.prototype.repeat) { // 해당 메서드가 존재하지 않는다면
140-
// 프로토타입을 추가
139+
if (!String.prototype.repeat) { // repeat이라는 메서드가 없다고 가정합시다
140+
// 프로토타입에 repeat를 추가
141141

142142
String.prototype.repeat = function(n) {
143-
// string을 n회 반복
143+
// string을 n회 반복(repeat)합니다.
144144

145-
// actually, the code should be a little bit more complex than that
146-
// (the full algorithm is in the specification)
147-
// but even an imperfect polyfill is often considered good enough
145+
// 실제 이 메서드를 구현하려면 코드는 더 복잡해질겁니다.
146+
// 전체 알고리즘은 명세서에서 확인할 수 있겠죠.
147+
// 그런데 완벽하지 않은 폴리필이라도 충분히 쓸만합니다.
148148
return new Array(n + 1).join(this);
149149
};
150150
}
@@ -153,17 +153,17 @@ alert( "La".repeat(3) ); // LaLaLa
153153
```
154154

155155

156-
## 프로토타입으로부터 빌리기
156+
## 프로토타입에서 빌려오기
157157

158-
<info:call-apply-decorators#method-borrowing>에서는 메서드 빌리기에 관하여 얘기하였습니다.
158+
<info:call-apply-decorators#method-borrowing>에서 메서드 빌리기에 대한 내용을 학습한 바 있습니다.
159159

160-
이는 메서드를 하나의 객체로부터 가져온 다음 다른 객체에 복사하는 것입니다.
160+
한 객체의 메서드를 다른 객체로 복사할 때 이 기법이 사용됩니다.
161161

162-
몇몇 네이티브 프로토타입의 메서드들은 자주 사용됩니다.
162+
개발을 하다 보면 네이티브 프로토타입에 구현된 메서드를 빌려야 하는 경우가 종종 생깁니다.
163163

164-
예를 들어 객체와 같은 배열을 만든다고 하면 아마 `Array` 메서드를 객체에 복사해야 합니다.
164+
유사 배열 객체를 만들고 여기에 `Array` 메서드를 복사해봅시다.
165165

166-
예시
166+
예시:
167167

168168
```js run
169169
let obj = {
@@ -179,18 +179,18 @@ obj.join = Array.prototype.join;
179179
alert( obj.join(',') ); // Hello,world!
180180
```
181181

182-
코드는 정상작동 합니다. 왜냐하면,내장 `join`메서드의 내장 알고리즘은 단지 인덱스의 일치 여부만 케어하며 `length` 프로퍼티는 객체가 실제로 배열에 존재하는지 체크하지 않습니다. 그리고 수많은 내장 메서드들도 또한 이와 같습니다.
182+
예시를 실행하면 에러 없이 의도한 대로 동작합니다. 내장 메서드 `join`의 내부 알고리즘은 제대로 된 인덱스가 있는지와 `length` 프로퍼티가 있는지만 확인하기 때문입니다. 호출 대상이 진짜 배열인지는 확인하지 않죠. 다수의 내장 메서드가 이런 식으로 동작합니다.
183183

184-
다른 가능성은 `obj.__proto__``Array.prototype`에 상속시키는 것입니다. 그래서 모든 `Array`메서드가 자동으로 `obj`에서 사용 가능하게 하는 것입니다.
184+
메서드 빌리기 말고도 `obj.__proto__``Array.prototype`로 설정해 배열 메서드를 상속받는 방법이 있습니다. 이렇게 하면 `obj`에서 모든 `Array`메서드를 사용할 수 있습니다.
185185

186-
`obj`이미 다른 객체로부터 상속받았다면 위 방법은 불가능합니다. 오직 한 번에 하나의 객체로부터 상속 가능함을 기억해 두세요.
186+
그런데 이 방법은 `obj`가 다른 객체를 상속받고 있을 때는 사용할 수 없습니다. 자바스크립트는 단일 상속만을 허용한다는 점을 기억하시기 바랍니다.
187187

188-
메서드 빌리기는 유연하여 필요에 따라 함수적 기능을 섞는 것을 다른 객체로부터 가능하게 합니다.
188+
메서드 빌리기는 유연합니다. 여러 객체에서 필요한 기능을 가져와 섞는 것을 가능하게 해줍니다.
189189

190190
## 요약
191191

192192
- 모든 내장 객체는 같은 패턴을 따릅니다.
193193
- 메서드는 프로토타입에 저장됩니다(`Array.prototype`, `Object.prototype`, `Date.prototype` 등).
194-
- 객체 스스로는 단지 데이터만 저장합니다(배열의 아이템, 객체의 프로퍼티, 날짜).
195-
- 원시값 또한 객체 래퍼의 프로토타입 안에 `Number.prototype`, `String.prototype`, `Boolean.prototype` 같은 메서드를 저장합니다. `undefined` `null` 값만 객체 래퍼를 가지지 않습니다.
196-
- 내장 프로토타입은 수정 가능하며 새로운 메서드와 함께 값을 가져올 수 있습니다. 그러나 내장 프로토타입을 변경하는 것을 추천하진 않습니다. 아마 새로운 표준을 추가하려고 할 때 만 가능합니다. 그러나 이는 자바스크립트 엔진 메서드에서는 아직 지원하지 않습니다.
194+
- 객체 자체엔 데이터만 저장합니다(배열의 요소, 객체의 프로퍼티, 날짜).
195+
- 원시값 또한 래퍼 객체의 프로토타입에 `Number.prototype`, `String.prototype`, `Boolean.prototype` 같은 메서드를 저장합니다. `undefined``null` 값은 래퍼 객체 래퍼를 가지지 않습니다.
196+
- 내장 프로토타입을 수정할 수 있습니다. 내장 프로토타입의 메서드를 빌려와 새로운 메서드를 만드는 것 역시 가능합니다. 그러나 내장 프로토타입 변경은 되도록 하지 않아야 합니다. 내장 프로토타입은 새로 명세서에 등록된 기능을 사용하고 싶은데 자바스크립트 엔진엔 이 기능이 구현되어있지 않을 때만 변경하는 게 좋습니다.

0 commit comments

Comments
 (0)