Skip to content

Commit 7e5ee0e

Browse files
authored
Merge branch 'ahnlab-220:main' into main
2 parents 643eed1 + a18a420 commit 7e5ee0e

7 files changed

Lines changed: 1493 additions & 19 deletions

File tree

book/공희재/chapter_21.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
1. Standard built-in objects 또는 Native objects 또는 Global objects (표준 빌트인 객체)
66
2. Host objects (호스트 객체)
77
3. User-defined objects (사용자 정의 객체)
8+
89
차례대로 살펴 보자.
910

1011
## 2. Standard built-in objects: 표준 빌트인 객체

book/이용우/chapter_12.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -461,7 +461,7 @@ documnet.getElementById('myButton').addEventListener('click', function () {
461461

462462
// 콜백 함수를 사용한 비동기 처리
463463
setTimeout(function () {
464-
console,log('1초 경과');
464+
console.log('1초 경과');
465465
}, 1000);
466466
```
467467

book/이용우/chapter_19.md

Lines changed: 14 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ const circle2 = new Circle(2);
8686
// Circle 생성자 함수는 인스턴스를 생성할 때마다 동일한 동작을 하는
8787
// getArea 메소드를 중복 생성하고 모든 인스턴스가 중복 소유합니다.
8888
// getArea 메소드는 하나만 생성하여 모든 인스턴스가 공유해서 사용하는 것이 바람직합니다.
89-
console.log(circle.getArea === circle2.getArea); // false
89+
console.log(circle1.getArea === circle2.getArea); // false
9090

9191
console.log(circle1.getArea());
9292
console.log(circle2.getArea());
@@ -106,7 +106,7 @@ console.log(circle2.getArea());
106106

107107
이처럼 동일한 생성자 함수에 의해 생성된 모든 인스턴스가 동일한 메소드를 중복 소유하는 것은 메모리를 불필요하게 낭비합니다.
108108
또한 인스턴스를 생성할 때마다 메소드를 생성하므로 퍼포먼스에도 악영향을 줍니다.
109-
만약 10개의 인스턴스를 생성하면 내용이 동일한 메소드로 10개 성상됩니다.
109+
만약 10개의 인스턴스를 생성하면 내용이 동일한 메소드로 10개 생성됩니다.
110110

111111
<br>
112112

@@ -120,7 +120,7 @@ function Circle(radius) {
120120
}
121121

122122
// Circle 생성자 함수가 생성한 모든 인스턴스가 getArea 메소드를
123-
// 공유해서 사용할 수 있도록 프로토토압에 추가합니다.
123+
// 공유해서 사용할 수 있도록 프로토타입에 추가합니다.
124124
// 프로토타입은 Circle 생성자 함수의 prototype 프로토타입에 바인딩되어 있습니다.
125125
Circle.prototype.getArea = function() {
126126
return Math.PI * this.radius ** 2;
@@ -135,7 +135,7 @@ const circle2 = new Circle(2);
135135
// Circle 생성자 함수는 인스턴스를 생성할 때마다 동일한 동작을 하는
136136
// getArea 메소드를 중복 생성하고 모든 인스턴스가 중복 소유합니다.
137137
// getArea 메소드는 하나만 생성하여 모든 인스턴스가 공유해서 사용하는 것이 바람직합니다.
138-
console.log(circle.getArea === circle2.getArea); // false
138+
console.log(circle1.getArea === circle2.getArea); // true
139139

140140
console.log(circle1.getArea());
141141
console.log(circle2.getArea());
@@ -153,7 +153,7 @@ console.log(circle2.getArea());
153153

154154
즉, 자신의 상태를 나타내는 `radius` 프로퍼티만 개별적으로 소유하고 내용이 동일한 메소드는 상속을 통해 공유하여 사용하는 것입니다.
155155
상속은 코드의 재사용이란 관점에서 매우 유용합니다.
156-
<font color='orange'>메소드를 프로토타입에 미리 구현해두면 모든 인스턴스는 별도의 구현 없이 상위(부모) 객체인 프로토토압의 자산을 공유하여 사용할 수 있습니다. </font>
156+
<font color='orange'>메소드를 프로토타입에 미리 구현해두면 모든 인스턴스는 별도의 구현 없이 상위(부모) 객체인 프로토타입의 자산을 공유하여 사용할 수 있습니다. </font>
157157

158158
<br><br>
159159

@@ -185,7 +185,7 @@ console.log(circle2.getArea());
185185

186186
##### __proto__ 접근자 프로퍼티
187187
모든 객체는 `__proto__` 접근자 프로퍼티를 통해 자신의 프로토타입,
188-
[[Prototype]] 내부 슬롯에 **간접적으로 접근할 수 있습니다.**
188+
[[Prototype]] 내부 슬롯이 가리키는 프로토타입에 **간접적으로 접근할 수 있습니다.**
189189

190190
<img width="300" alt="image" src="https://github.com/user-attachments/assets/bb50a2ca-1454-4d59-bb06-ef967dcad068" />
191191

@@ -252,7 +252,7 @@ console.log({}.__proto__ === Object.prototype); // true
252252
> 자바스크립트 엔진은 객체의 프로퍼티(메서드 포함)에 접근하려고 할 때
253253
> 해당 객체에 접근하려는 프로퍼티가 없다면 `__proto__` 접근자 프로퍼티가 가리키는 참조를 따라 자신의 부모 역할을 하는 프로토타입의 프로퍼티를 순차적으로 검색한다.
254254
>
255-
> 프로토타입 체인의 종점, 즉 프로토타입 체인의 최상위 객체는 `0bject.prototype`이며,
255+
> 프로토타입 체인의 종점, 즉 프로토타입 체인의 최상위 객체는 `Object.prototype`이며,
256256
> 이 객체의 프로퍼티와 메서드는 모든 객체에 상속된다.
257257
258258
<br><br>
@@ -277,7 +277,7 @@ parent.__proto__ = child; // TypeError: Cyclic __proto__ value
277277
위 예제에서는 `parent` 객체를 `child` 객체의 프로토타입으로 설정한 후,
278278
`child` 객체를 `parent` 객체의 프로토타입으로 설정했습니다.
279279

280-
이러한 코드가 에러 업싱 정상적으로 처리되면
280+
이러한 코드가 에러 없이 정상적으로 처리되면
281281
서로가 자신의 프로토타입이 되는 비정상적인 프로토타입 체인이 만들어지기 때문에
282282
`__proto__` 접근자 프로퍼티는 에러를 발생시킵니다.
283283

@@ -314,7 +314,7 @@ console.log(Object.getPrototypeOf(obj)); // null
314314
```
315315

316316
따라서 프로토타입의 참조를 얻고 싶은 경우에는, `Obejct.getPrototypeOf` 메소드를 사용하고,
317-
프로토타입을 교체하고 싶은 경우에는 `Object.setPrototypeO ㅈf` 메소드를 사용할 것을 권장합니다.
317+
프로토타입을 교체하고 싶은 경우에는 `Object.setPrototypeOf` 메소드를 사용할 것을 권장합니다.
318318

319319
``` js
320320
const obj = {};
@@ -350,17 +350,14 @@ console.log(obj.x); // 1
350350
`prototype` 프로퍼티를 소유하지 않으며 프로토타입도 생성하지 않습니다.
351351

352352
``` js
353-
// 화살표 함수는 non-constructor 이다.
353+
// 화살표 함수는 non-constructor 입니다.
354354
const Person = name => {
355355
this.name = name;
356356
};
357357

358358
// non-constructor는 prototype 프로퍼티를 소유하지 않는다.
359359
console.log(Person.hasOwnProperty('prototype')); // false
360360

361-
// non-constructor는 프로토타입을 생성하지 않는다.
362-
console.log(Person.prototype); // undefined
363-
364361
// ES6의 메소드 축약 표현으로 정의한 메소드는 non-constructor다.
365362
const obj = {
366363
foo() {}
@@ -377,7 +374,6 @@ console.log(obj.foo.prototype); // undefined
377374

378375
모든 객체가 가지고 있는 `__proto__` 접근자 프로퍼티와
379376
함수 객체만이 가지고 있는 `prototype` 프로퍼티는 결국 동일한 프로토타입을 가리킵니다.
380-
하지만 이들 프로퍼티를 사용하는 주체가 다릅니다.
381377

382378
|구분|소유||사용 주체|사용 목적|
383379
|--|--|--|--|--|
@@ -618,7 +614,7 @@ console.log(person.setName.prototype); // undefined
618614
<br><br>
619615

620616
이처럼 다양한 방식으로 생성된 모든 객체는 각 방식마다 세부적인 객체 생성 방식의 차이는 있으나
621-
추상 연산 `ordinaryobjectCreate`에 의해 생성된다는 공통점이 있습니다.
617+
추상 연산 `ordinaryObjectCreate`에 의해 생성된다는 공통점이 있습니다.
622618

623619
이는 즉, 프로토타입은 추상 연산 `OrdinaryObjectCreate`에 전달되는 인수에 의해 결정됩니다.
624620
이 인수는 객체가 생성되는 시점에 객체 생성 방식에 의해 결정됩니다.
@@ -910,7 +906,7 @@ console.log(Object.getPrototypeOf(obj) === Person.prototype); // true
910906
```
911907

912908
위와 같이 `Object.create` 메소드는 첫 번째 매개변수에 전달한 객체의 프로토타입 체인에 속하는 객체를 생성합니다.
913-
즉, 객체를 생서앟면서 직접적으로 상속을 구현하는 것입니다.
909+
즉, 객체를 생성하면서 직접적으로 상속을 구현하는 것입니다.
914910

915911
장점은 아래와 같습니다.
916912
- `new` 연산자 없이도 객체 생성이 가능합니다.
@@ -1018,12 +1014,12 @@ console.log('toString' in person); // true
10181014
`in` 연산자 대신 ES6에서 도입된 `Reflict.has` 메소드를 사용할 수 있습니다.
10191015

10201016
``` js
1021-
const perosn = {
1017+
const person = {
10221018
name: 'Lee'
10231019
};
10241020

10251021
console.log(Reflict.has(person, 'name')); // true
1026-
console.log(Reflict.has(person, 'toString')); // true
1022+
console.log(Reflict.has(person, 'toString')); // false
10271023
```
10281024

10291025
<br><br>

book/이용우/chapter_20.md

Lines changed: 238 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,238 @@
1+
### Chapter 20 - strict mode
2+
#### strict mode란?
3+
``` js
4+
function foo() {
5+
x = 10;
6+
}
7+
8+
foo();
9+
10+
console.log(x); // ?
11+
```
12+
13+
foo 함수 내에서 선언하지 않은 x 변수에 값 10을 할당했습니다.
14+
이때 x 변수를 찾아야 x에 값을 할당할 수 있기 때문에 자바스크립트 엔진은 x 변수가 어디서 선언되었는지 스코프 체인을 통해 검색하게 됩니다.
15+
16+
자바스크립트 엔진은 아래의 순서로 겁색을 시도할 것입니다.
17+
1. `foo` 함수의 스코프에서 `x` 변수의 선언을 검색한다. (`foo` 함수의 스코프에는 `x` 변수의 선언이 없으므로 검색에 실패한다.)
18+
2. `foo` 함수 컨텍스트의 상위 스코프(예제의 경우에는 전역 스코프)에서 `x` 변수의 선언을 검색한다.
19+
20+
전역 스코프에도 `x` 변수의 선언이 존재하지 않기 때문에 `ReferenceError`를 발생시킬 것 같지만
21+
자바스크립트 엔진은 <font color='orange'>암묵적으로 전역 객체에 `x` 프로퍼티를 생성합니다.</font>
22+
> 마치 전역 변수처럼 `x` 변수를 사용할 수 있게 된다.
23+
24+
**위와 같은 현상을 암묵적 전역(implict global)이라 합니다.**
25+
26+
<br>
27+
28+
개발자 의도와는 상관없이 발생한 암묵적 전역은 오류를 발생시키는 원인이 될 가능성이 큽니다.
29+
따라서 반드시 `var`, `let`, `const` 키워드를 사용하여 변수를 선언한 다음 사용해야 합니다.
30+
31+
<br>
32+
33+
다만 휴먼 에러로 실수는 언제나 존재할 수 있습니다.
34+
따라서 오류를 줄여 안정적인 코드를 생성하기 위해 잠재적으로 오류를 발생시키기 어려운 개발 환경을 만들고,
35+
그 환경에서 개발할 수 있도록 해결 방안을 모색하기 시작했습니다.
36+
37+
<br>
38+
39+
이를 위해 ES5 부터는 `strict mode(엄격 모드)`가 추가되었습니다.
40+
이 모드는 <font color='orange'>자바스크립트 언어의 문법을 조금 더 엄격하게 적용하여</font> 오류를 발생시킬 가능성이 높거나
41+
<font color='orange'>자바스크립트 엔진의 최적화 문제를 일으킬 수 있는 코드에 대해 명시적인 에러를 발생시키도록 해줍니다.</font>
42+
43+
<br>
44+
45+
`ESLint`와 같은 린트 도구를 사용해도 strict mode와 유사한 효과를 얻을 수 있습니다.
46+
> 린트 도구는 `정적 분석` 기능을 통해 소스코드를 실행하기 전에 문법적 오류 뿐만 아니라 잠재거인 오류까지 찾아내주는 도구이다.
47+
48+
<br><br>
49+
50+
51+
### strict mode의 적용
52+
53+
54+
자바스크립트에서 strict mode는 더 엄격한 문법과 오류 처리를 적용하여 잠재적인 오류를 방지하고 안전한 코드를 작성할 수 있도록 도와줍니다.
55+
strict mode를 사용하면 다음과 같은 이점이 있습니다:
56+
57+
- 암묵적 전역 변수 생성을 방지합니다.
58+
- 읽기 전용 속성에 값을 할당하는 등의 실수를 방지합니다.
59+
- `this``undefined`로 설정되는 것을 방지합니다.
60+
61+
strict mode를 활성화하려면 파일 또는 함수의 맨 위에 `"use strict";` 지시어를 추가합니다.
62+
<font color='orange'>다만, strict mode이 적용될 블록 스코프를 직접 정할 수 있습니다.</font>
63+
64+
``` js
65+
'use strict';
66+
67+
function foo() {
68+
x = 10; // ReferenceError: x is not defined
69+
}
70+
71+
foo();
72+
73+
console.log(x);
74+
```
75+
위 코드는 전역 스코프에 대해 strict mode가 적용되도록 할 수 있습니다.
76+
77+
<br><br>
78+
79+
``` js
80+
81+
82+
function foo() {
83+
'use strict';
84+
x = 10; // ReferenceError: x is not defined
85+
}
86+
87+
foo();
88+
89+
console.log(x);
90+
```
91+
92+
함수 스코프에 추가하면 해당 함수 및 중첩 함수에 strict mode가 적용됩니다.
93+
94+
95+
<br><br>
96+
97+
### 전역에 strict mode를 적용하는 것은 피하자
98+
99+
<font color='orange'>전역에 적용한 strict mode는 스크립트 단위로 적용됩니다.</font>
100+
101+
``` html
102+
<!DOCTYPE html>
103+
<html>
104+
<body>
105+
<script>
106+
'use scrict';
107+
</script>
108+
<script>
109+
x = 1; // 에러가 발생하지 않는다.
110+
console.log(x); // 1
111+
</script>
112+
<script>
113+
'use strict';
114+
115+
y = 1; // ReferenceError: y is not defined
116+
console.log(y);
117+
</script>
118+
</body>
119+
</html>
120+
```
121+
122+
123+
위 예제와 같이 스크립트 단위로 적용된 strict mode는 다른 스크립트에 영향을 주지 않습니다.
124+
하지만 `strict mode` 스크립트와 `non-strict mode` 스크립트를 혼용하는 것은 오류를 발생시킬 수 있습니다.
125+
> 외부 서드파티 라이브러리를 사용하는 경우 라이브러리가 `non-strict mode`인 경우가 있기 때문에 전역에 strict mode를 적용하는 것은 바람직하지 않다.
126+
127+
<br><br>
128+
129+
### 함수 단위로 strict mode를 적용하는 것을 피하자
130+
함수 단위로 strict mode를 적용할 수도 있지만
131+
어떤 함수는 strict mode를 적용하고 어떤 함수는 strict mode를 적용하지 않는 것은 바람직하지 않으며
132+
모든 함수에 일일이 strict mode를 적용하는 것은 번거롭습니다.
133+
134+
그리고 strict mode가 적용된 함수가 참조할 함수 외부의 컨텍스트에 strict mode를 적용하지 않는다면
135+
이 또한 문제가 발생할 수 있습니다.
136+
137+
138+
``` js
139+
(function () {
140+
// non-strict mode
141+
var let = 10; // 에러가 발생하지 않음
142+
143+
function foo() {
144+
'use strict';
145+
146+
let = 20; // SyntaxError: Unexpected strict mode reserved word
147+
}
148+
foo();
149+
})
150+
```
151+
152+
따라서 strict mode는 즉시 실행 함수로 감싼 스크립트 단위로 적용하는 것이 바람직합니다.
153+
154+
``` js
155+
// 즉시 실행 함수의 선두에 strict mode 적용
156+
(function () {
157+
'use strict';
158+
// Do something...
159+
}());
160+
161+
```
162+
163+
164+
<br><br>
165+
166+
167+
### strict mode가 발생시키는 에러
168+
아래는 strict mode를 적용시켰을 때 에러가 발생하는 대표적 사례입니다.
169+
170+
<br><br>
171+
172+
#### 암묵적 전역
173+
선언하지 않은 변수를 참조하면 `ReferenceError`가 발생합니다.
174+
175+
``` js
176+
(function () {
177+
'use strict';
178+
179+
x = 1;
180+
console.log(x); // ReferenceError: x is not defined
181+
}());
182+
```
183+
184+
<br><br>
185+
186+
#### 변수, 함수, 매개변수의 삭제
187+
`delete` 연산자로 변수, 함수, 매개변수를 삭제하면 SyntaxError가 발생합니다.
188+
189+
``` js
190+
(function () {
191+
'use strict';
192+
193+
var x = 1;
194+
delete x; // SyntaxError: Delete of an unqualified identifier in strict mode.
195+
196+
function foo(a){
197+
delete a; // SyntaxError: Delete of an unqualified identifier in strict mode.
198+
}
199+
delete foo; // SyntaxError: Delete of an unqualified identifier in strict mode.
200+
}());
201+
```
202+
203+
<br><br>
204+
205+
#### 매개변수 이름의 중복
206+
중복된 매개변수 이름을 사용하면 `SyntaxError`가 발생합니다.
207+
208+
``` js
209+
(function () {
210+
'use strict';
211+
212+
// SyntaxError: Duplicate parameter name not allowed in this context
213+
function foo(x, x) {
214+
return x + x;
215+
}
216+
console.log(foo(1, 2))
217+
}());
218+
```
219+
220+
<br><br>
221+
222+
#### with 문의 사용
223+
`with` 문을 사용하면 `SyntaxError`가 발생합니다.
224+
`with` 문은 전달된 객체를 스코프 체인에 추가합니다.
225+
226+
`with` 문은 동일한 객체의 프로퍼티를 반복해서 사용할 때 까지 객체 이름을 생략할 수 있어서 코드가 간단해질 수 있지만
227+
성능과 가독성이 나빠지는 문제가 있습니다. 따라서 `with` 문은 사용하지 않는 것이 좋습니다.
228+
229+
``` js
230+
(function() {
231+
'use strict';
232+
233+
// SyntaxError: Strict mode code may not include a with statement
234+
with({ x: 1}){
235+
console.log(x);
236+
}
237+
}());
238+
```

0 commit comments

Comments
 (0)