(253-1)
(`9007199254740991`) 보다 큰 값 혹은 -(253-1)
보다 작은 정수는 '숫자형'을 사용해 나타낼 수 없습니다.
사실 대부분의 상황에서 이런 제약사항은 문제가 되지 않습니다. 그렇지만 암호 관련 작업같이 아주 큰 숫자가 필요한 상황이거나 아주 높은 정밀도로 작업을 해야 할 때는 이런 큰 숫자가 필요합니다.
+=======
+In JavaScript, the "number" type cannot safely represent integer values larger than (253-1)
(that's `9007199254740991`), or less than -(253-1)
for negatives.
+
+To be really precise, the "number" type can store larger integers (up to 1.7976931348623157 * 10308
), but outside of the safe integer range ±(253-1)
there'll be a precision error, because not all digits fit into the fixed 64-bit storage. So an "approximate" value may be stored.
+
+For example, these two numbers (right above the safe range) are the same:
+
+```js
+console.log(9007199254740991 + 1); // 9007199254740992
+console.log(9007199254740991 + 2); // 9007199254740992
+```
+
+So to say, all odd integers greater than (253-1)
can't be stored at all in the "number" type.
+
+For most purposes ±(253-1)
range is quite enough, but sometimes we need the entire range of really big integers, e.g. for cryptography or microsecond-precision timestamps.
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
`BigInt`형은 표준으로 채택된 지 얼마 안 된 자료형으로, 길이에 상관없이 정수를 나타낼 수 있습니다.
@@ -81,11 +110,15 @@ const bigInt = 1234567890123456789012345678901234567890n;
`BigInt`형 숫자는 자주 쓰이지 않기 때문에 여기서 자세히 다루지 않고 별도의 챕터, ±(253-1)
.
+ - `bigint` for integer numbers of arbitrary length.
+ - `string` for strings. A string may have zero or more characters, there's no separate single-character type.
+ - `boolean` for `true`/`false`.
+ - `null` for unknown values -- a standalone type that has a single value `null`.
+ - `undefined` for unassigned values -- a standalone type that has a single value `undefined`.
+ - `symbol` for unique identifiers.
+- And one non-primitive data type:
+ - `object` for more complex data structures.
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
`typeof` 연산자는 피연산자의 자료형을 알려줍니다.
+<<<<<<< HEAD
- `typeof x` 또는 `typeof(x)` 형태로 사용합니다.
- 피연산자의 자료형을 문자열 형태로 반환합니다.
- `null`의 typeof 연산은 `"object"`인데, 이는 언어상 오류입니다. null은 객체가 아닙니다.
+=======
+- Usually used as `typeof x`, but `typeof(x)` is also possible.
+- Returns a string with the name of the type, like `"string"`.
+- For `null` returns `"object"` -- this is an error in the language, it's not actually an object.
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
이어지는 챕터에선 원시 자료형에 대해 학습해 볼 예정입니다. 원시형에 어느 정도 익숙해지면 객체형에 대해 알아보도록 하겠습니다.
diff --git a/1-js/02-first-steps/06-alert-prompt-confirm/article.md b/1-js/02-first-steps/06-alert-prompt-confirm/article.md
index e094ea75ee..278379e823 100644
--- a/1-js/02-first-steps/06-alert-prompt-confirm/article.md
+++ b/1-js/02-first-steps/06-alert-prompt-confirm/article.md
@@ -30,8 +30,13 @@ result = prompt(title, [default]);
`default`
: 입력 필드의 초깃값(선택값)
+<<<<<<< HEAD
```smart header="인수를 감싸는 대괄호 `[...]`의 의미"
`default`를 감싸는 대괄호는 이 매개변수가 필수가 아닌 선택값이라는 것을 의미합니다.
+=======
+```smart header="The square brackets in syntax `[...]`"
+The square brackets around `default` in the syntax above denote that the parameter is optional, not required.
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
```
사용자는 프롬프트 대화상자의 입력 필드에 원하는 값을 입력하고 확인을 누를 수 있습니다. 값을 입력하길 원하지 않는 경우는 취소(Cancel) 버튼을 누르거나 `key:Esc`를 눌러 대화상자를 빠져나가면 됩니다.
diff --git a/1-js/02-first-steps/07-type-conversions/article.md b/1-js/02-first-steps/07-type-conversions/article.md
index a4aecec113..5eaefbf34c 100644
--- a/1-js/02-first-steps/07-type-conversions/article.md
+++ b/1-js/02-first-steps/07-type-conversions/article.md
@@ -6,8 +6,13 @@
이 외에, 전달받은 값을 의도를 갖고 원하는 타입으로 변환(명시적 변환)해 주는 경우도 형 변환이라고 할 수 있습니다.
+<<<<<<< HEAD
```smart header="객체의 형변환은 나중에 다룹니다."
이 챕터에선 객체는 다루지 않겠습니다. 여기선 원시형의 형변환에 대해서만 다룰 예정입니다.
+=======
+```smart header="Not talking about objects yet"
+In this chapter, we won't cover objects. For now, we'll just be talking about primitives.
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
객체의 형 변환이 어떻게 이뤄지는지 true and false
| `1` 과 `0` |
| `string` | 문자열의 처음과 끝 공백이 제거됩니다. 공백 제거 후 남아있는 문자열이 없다면 `0`, 그렇지 않다면 문자열에서 숫자를 읽습니다. 변환에 실패하면 `NaN`이 됩니다.|
+=======
+|true and false
| `1` and `0` |
+| `string` | Whitespaces (includes spaces, tabs `\t`, newlines `\n` etc.) from the start and end are removed. If the remaining string is empty, the result is `0`. Otherwise, the number is "read" from the string. An error gives `NaN`. |
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
예시:
@@ -130,7 +144,11 @@ alert( Boolean(" ") ); // 공백이 있는 문자열도 비어있지 않은 문
|`undefined`|`NaN`|
|`null`|`0`|
|true / false
| `1 / 0` |
+<<<<<<< HEAD
| `string` | 전달받은 문자열을 "그대로" 읽되, 처음과 끝의 공백을 무시합니다. 문자열이 비어있다면 `0`이 되고, 오류 발생 시 `NaN`이 됩니다. |
+=======
+| `string` | The string is read "as is", whitespaces (includes spaces, tabs `\t`, newlines `\n` etc.) from both sides are ignored. An empty string becomes `0`. An error gives `NaN`. |
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
**`불린형으로 변환`** 은 논리 연산 시 발생합니다. `Boolean(value)`으로도 변환할 수 있습니다.
diff --git a/1-js/02-first-steps/08-operators/3-primitive-conversions-questions/solution.md b/1-js/02-first-steps/08-operators/3-primitive-conversions-questions/solution.md
index bde9d58328..6288cc0d99 100644
--- a/1-js/02-first-steps/08-operators/3-primitive-conversions-questions/solution.md
+++ b/1-js/02-first-steps/08-operators/3-primitive-conversions-questions/solution.md
@@ -9,7 +9,6 @@ true + false = 1
"$" + 4 + 5 = "$45"
"4" - 2 = 2
"4px" - 2 = NaN
-7 / 0 = Infinity
" -9 " + 5 = " -9 5" // (3)
" -9 " - 5 = -14 // (4)
null + 1 = 1 // (5)
@@ -17,10 +16,20 @@ undefined + 1 = NaN // (6)
" \t \n" - 2 = -2 // (7)
```
+<<<<<<< HEAD
1. 피 연산자 중 하나가 문자열인 `"" + 1`에서 `1`은 문자형으로 변환됩니다. 따라서 공백과 문자열 1을 더한, `"" + 1 = "1"`과 같은 효과를 발휘하죠. 그다음 연산 `"1" + 0`에도 같은 규칙이 적용됩니다.
2. 뺄셈 연산자 `-`는 기타 수학 연산자처럼 숫자형만을 인수로 받습니다. 빈 문자열 `""`는 숫자 `0`으로 변환되기 때문에 결과는 `-1`이 됩니다.
3. 피 연산자 중 하나가 문자열이므로 숫자 5가 문자열로 변환됩니다.
4. 뺄셈 연산자는 인수를 숫자형으로 변화시키므로 `" -9 "`는 숫자 `-9`로 변합니다. 앞, 뒤 공백은 제거되죠.
5. 숫자형으로 변환 시 `null`은 `0`이 됩니다.
6. `undefined`는 숫자형으로 변환시 `NaN`이 됩니다.
-7. 문자열이 숫자형으로 변할 땐 문자열 앞뒤의 공백이 삭제됩니다. 뺄셈 연산자 앞의 피연산자는 공백을 만드는 문자 `\t`와 `\n`, 그 사이의 "일반적인" 공백으로 구성됩니다. 따라서 `" \t \n"`는 숫자형으로 변환 시 길이가 `0`인 문자열로 취급되어 숫자 `0`이 됩니다.
\ No newline at end of file
+7. 문자열이 숫자형으로 변할 땐 문자열 앞뒤의 공백이 삭제됩니다. 뺄셈 연산자 앞의 피연산자는 공백을 만드는 문자 `\t`와 `\n`, 그 사이의 "일반적인" 공백으로 구성됩니다. 따라서 `" \t \n"`는 숫자형으로 변환 시 길이가 `0`인 문자열로 취급되어 숫자 `0`이 됩니다.
+=======
+1. The addition with a string `"" + 1` converts `1` to a string: `"" + 1 = "1"`, and then we have `"1" + 0`, the same rule is applied.
+2. The subtraction `-` (like most math operations) only works with numbers, it converts an empty string `""` to `0`.
+3. The addition with a string appends the number `5` to the string.
+4. The subtraction always converts to numbers, so it makes `" -9 "` a number `-9` (ignoring spaces around it).
+5. `null` becomes `0` after the numeric conversion.
+6. `undefined` becomes `NaN` after the numeric conversion.
+7. Space characters are trimmed off string start and end when a string is converted to a number. Here the whole string consists of space characters, such as `\t`, `\n` and a "regular" space between them. So, similarly to an empty string, it becomes `0`.
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
diff --git a/1-js/02-first-steps/08-operators/3-primitive-conversions-questions/task.md b/1-js/02-first-steps/08-operators/3-primitive-conversions-questions/task.md
index cff6c67e6a..2c45b127f9 100644
--- a/1-js/02-first-steps/08-operators/3-primitive-conversions-questions/task.md
+++ b/1-js/02-first-steps/08-operators/3-primitive-conversions-questions/task.md
@@ -16,7 +16,6 @@ true + false
"$" + 4 + 5
"4" - 2
"4px" - 2
-7 / 0
" -9 " + 5
" -9 " - 5
null + 1
diff --git a/1-js/02-first-steps/08-operators/4-fix-prompt/solution.md b/1-js/02-first-steps/08-operators/4-fix-prompt/solution.md
index defe5642c0..d130e9a1ee 100644
--- a/1-js/02-first-steps/08-operators/4-fix-prompt/solution.md
+++ b/1-js/02-first-steps/08-operators/4-fix-prompt/solution.md
@@ -9,7 +9,11 @@ let b = "2"; // prompt("덧셈할 두 번째 숫자를 입력해주세요.", 2);
alert(a + b); // 12
```
+<<<<<<< HEAD
예시가 제대로 동작하게 하려면 덧셈 연산 `+`가 수행되기 전에 문자열을 숫자로 변환해야 합니다. 이때 `Number()`를 사용하거나 변수 앞에 `+`를 붙여줄 수 있습니다.
+=======
+What we should do is to convert strings to numbers before `+`. For example, using `Number()` or prepending them with `+`.
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
아래 코드에선 `prompt` 함수 바로 앞에서 문자열을 숫자로 변환했습니다.
diff --git a/1-js/02-first-steps/08-operators/article.md b/1-js/02-first-steps/08-operators/article.md
index 29193f4995..e3e3485687 100644
--- a/1-js/02-first-steps/08-operators/article.md
+++ b/1-js/02-first-steps/08-operators/article.md
@@ -50,23 +50,46 @@
예시:
```js run
+<<<<<<< HEAD
alert( 5 % 2 ); // 5를 2로 나눈 후의 나머지인 1을 출력
alert( 8 % 3 ); // 8을 3으로 나눈 후의 나머지인 2를 출력
+=======
+alert( 5 % 2 ); // 1, the remainder of 5 divided by 2
+alert( 8 % 3 ); // 2, the remainder of 8 divided by 3
+alert( 8 % 4 ); // 0, the remainder of 8 divided by 4
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
```
## 거듭제곱 연산자 **
+<<<<<<< HEAD
거듭제곱 연산자(exponentiation operator)를 사용한 `a ** b`를 평가하면 `a`를 `b`번 곱한 값이 반환됩니다.
+=======
+The exponentiation operator `a ** b` raises `a` to the power of `b`.
+
+In school maths, we write that as ab.
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
예시:
```js run
+<<<<<<< HEAD
alert( 2 ** 2 ); // 4 (2 * 2)
alert( 2 ** 3 ); // 8 (2 * 2 * 2)
alert( 2 ** 4 ); // 16 (2 * 2 * 2 * 2)
```
거듭제곱 연산자는 정수가 아닌 숫자에 대해서도 동작합니다. `1/2`을 사용하면 제곱근을 구할 수 있죠.
+=======
+alert( 2 ** 2 ); // 2² = 4
+alert( 2 ** 3 ); // 2³ = 8
+alert( 2 ** 4 ); // 2⁴ = 16
+```
+
+Just like in maths, the exponentiation operator is defined for non-integer numbers as well.
+
+For example, a square root is an exponentiation by ½:
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
```js run
alert( 4 ** (1/2) ); // 2 (1/2 거듭제곱은 제곱근)
@@ -76,7 +99,11 @@ alert( 8 ** (1/3) ); // 2 (1/3 거듭제곱은 세제곱근)
## 이항 연산자 '+'와 문자열 연결
+<<<<<<< HEAD
이제 학교에서 배운 기본 산술 연산자를 넘어, 자바스크립트가 제공하는 특별한 연산자 기능에 대해 살펴봅시다.
+=======
+Let's meet the features of JavaScript operators that are beyond school arithmetics.
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
덧셈 연산자 `+`는 대개 숫자를 더한 결과를 반환합니다.
@@ -104,7 +131,16 @@ alert( 2 + '1' ); // "21"
alert(2 + 2 + '1' ); // '221'이 아니라 '41'이 출력됩니다.
```
+<<<<<<< HEAD
연산은 왼쪽에서 오른쪽으로 순차적으로 진행되기 때문에 이런 결과가 나왔습니다. 두 개의 숫자 뒤에 문자열이 오는 경우, 숫자가 먼저 더해지고, 그 후 더해진 숫자와 문자열과의 병합이 일어납니다.
+=======
+Here, operators work one after another. The first `+` sums two numbers, so it returns `4`, then the next `+` adds the string `1` to it, so it's like `4 + '1' = '41'`.
+
+```js run
+alert('1' + 2 + 2); // "122" and not "14"
+```
+Here, the first operand is a string, the compiler treats the other two operands as strings too. The `2` gets concatenated to `'1'`, so it's like `'1' + 2 = "12"` and `"12" + 2 = "122"`.
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
이처럼 이항 덧셈 연산자 `+`는 문자열 연결과 변환이라는 특별한 기능을 제공합니다. 다른 산술 연산자가 오직 숫자형의 피연산자만 다루고, 피연산자가 숫자형이 아닌 경우에 그 형을 숫자형으로 바꾸는 것과는 대조적입니다.
@@ -180,6 +216,7 @@ alert( +apples + +oranges ); // 5
자바스크립트는 다양한 연산자를 제공하는데, 이 모든 연산자엔 우선순위가 매겨져 있습니다. 우선순위 숫자가 클수록 먼저 실행됩니다. 순위가 같으면 왼쪽부터 시작해서 오른쪽으로 연산이 수행됩니다.
+<<<<<<< HEAD
아래는 [우선순위 테이블(precedence table)](https://developer.mozilla.org/en/JavaScript/Reference/operators/operator_precedence)의 일부를 발췌한 표입니다. 순서를 기억할 필요는 없지만, 동일한 기호의 단항 연산자는 이항 연산자보다 우선순위가 더 높다는 것에 주목해 주시기 바랍니다.
| 순위 | 연산자 이름 | 기호 |
@@ -197,10 +234,33 @@ alert( +apples + +oranges ); // 5
| ... | ... | ... |
'단항 덧셈 연산자'는 우선순위 `17`로, '(이항) 덧셈 연산자'의 우선순위 `13`보다 높습니다. 표현식 `"+apples + +oranges"`에서 단항 덧셈 연산자가 덧셈보다 먼저 수행되는 이유가 바로 이 때문입니다.
+=======
+Here's an extract from the [precedence table](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_Precedence) (you don't need to remember this, but note that unary operators are higher than corresponding binary ones):
+
+| Precedence | Name | Sign |
+|------------|------|------|
+| ... | ... | ... |
+| 14 | unary plus | `+` |
+| 14 | unary negation | `-` |
+| 13 | exponentiation | `**` |
+| 12 | multiplication | `*` |
+| 12 | division | `/` |
+| 11 | addition | `+` |
+| 11 | subtraction | `-` |
+| ... | ... | ... |
+| 2 | assignment | `=` |
+| ... | ... | ... |
+
+As we can see, the "unary plus" has a priority of `14` which is higher than the `11` of "addition" (binary plus). That's why, in the expression `"+apples + +oranges"`, unary pluses work before the addition.
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
## 할당 연산자
+<<<<<<< HEAD
무언가를 할당할 때 쓰이는 `=`도 연산자입니다. 이 연산자는 할당(assignment) 연산자라고 불리는데, 우선순위는 `3`으로 아주 낮습니다.
+=======
+Let's note that an assignment `=` is also an operator. It is listed in the precedence table with the very low priority of `2`.
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
`x = 2 * 2 + 1`과 같은 표현식에서 계산이 먼저 이뤄지고, 그 결과가 `x`에 할당되는 이유가 바로 이 때문입니다.
@@ -214,7 +274,11 @@ alert( x ); // 5
`=`는 연산자이기 때문에 흥미로운 함축성을 내포하고 있습니다.
+<<<<<<< HEAD
자바스크립트에서 대부분의 연산자들은 값을 반환합니다. `+`와 `-`뿐만 아니라 `=` 역시 값을 반환하죠.
+=======
+All operators in JavaScript return a value. That's obvious for `+` and `-`, but also true for `=`.
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
`x = value`을 호출하면 `value`가 `x`에 쓰여지고, 이에 더하여 *`value`가 반환됩니다*.
@@ -294,9 +358,13 @@ alert( n ); // 14
```js run
let n = 2;
-n *= 3 + 5;
+n *= 3 + 5; // right part evaluated first, same as n *= 8
+<<<<<<< HEAD
alert( n ); // 16 (*=의 우측이 먼저 평가되므로, 위 식은 n *= 8과 동일합니다.)
+=======
+alert( n ); // 16
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
```
## 증가·감소 연산자
@@ -428,7 +496,11 @@ counter++;
- 오른쪽 시프트(RIGHT SHIFT) ( `>>` )
- 부호 없는 오른쪽 시프트(ZERO-FILL RIGHT SHIFT) ( `>>>` )
+<<<<<<< HEAD
비트 연산자는 저수준(2진 표현)에서 숫자를 다뤄야 할 때 쓰이므로 흔하게 쓰이진 않습니다. 웹 개발 시엔 이런 일이 자주 일어나지 않기 때문에 비트 연산자를 만날 일은 거의 없죠. 그렇긴 해도 암호를 다뤄야 할 땐 비트 연산자가 유용하기 때문에 때가 되면 MDN의 [비트 연산자](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators) 문서를 보시는 걸 추천합니다.
+=======
+These operators are used very rarely, when we need to fiddle with numbers on the very lowest (bitwise) level. We won't need these operators any time soon, as web development has little use of them, but in some special areas, such as cryptography, they are useful. You can read the [Bitwise Operators](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators#bitwise_operators) chapter on MDN when a need arises.
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
## 쉼표 연산자
diff --git a/1-js/02-first-steps/09-comparison/1-comparison-questions/solution.md b/1-js/02-first-steps/09-comparison/1-comparison-questions/solution.md
index 6066afae22..57056c3563 100644
--- a/1-js/02-first-steps/09-comparison/1-comparison-questions/solution.md
+++ b/1-js/02-first-steps/09-comparison/1-comparison-questions/solution.md
@@ -12,10 +12,20 @@ null === +"\n0\n" → false
해설:
+<<<<<<< HEAD
1. 명백히 true입니다.
2. 문자열의 비교는 사전순서가 기준이므로 false입니다. `"a"`는 `"p"`보다 작습니다.
3. 두 피연산자는 문자열이므로, 사전순으로 비교가 이뤄집니다. 왼쪽 피연산자의 첫 번째 글자 `"2"`는 오른쪽 피연산자의 첫 번째 글자 `"1"`보다 큽니다.
4. `null`과 `undefined`는 같습니다.
5. 일치 연산자는 형도 체크합니다. 형이 다르면 false가 반환됩니다.
6. (4)와 유사한 문제입니다. `null`은 오직 `undefined`와 같습니다.
-7. 형이 다르므로 false가 반환됩니다.
\ No newline at end of file
+7. 형이 다르므로 false가 반환됩니다.
+=======
+1. Obviously, true.
+2. Dictionary comparison, hence false. `"a"` is smaller than `"p"`.
+3. Again, dictionary comparison, first char `"2"` is greater than the first char `"1"`.
+4. Values `null` and `undefined` equal each other only.
+5. Strict equality is strict. Different types from both sides lead to false.
+6. Similar to `(4)`, `null` only equals `undefined`.
+7. Strict equality of different types.
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
diff --git a/1-js/02-first-steps/09-comparison/article.md b/1-js/02-first-steps/09-comparison/article.md
index 0619bae6c0..afdef79a9a 100644
--- a/1-js/02-first-steps/09-comparison/article.md
+++ b/1-js/02-first-steps/09-comparison/article.md
@@ -4,6 +4,7 @@
자바스크립트에서 기본 수학 연산은 아래와 같은 문법을 사용해 표현할 수 있습니다.
+<<<<<<< HEAD
- 보다 큼·작음: a > b
, a < b
- 보다 크거나·작거나 같음: a >= b
, a <= b
- 같음(동등): `a == b`. 등호 `=`가 두 개 연달아 오는 것에 유의하세요. `a = b`와 같이 등호가 하나일 때는 할당을 의미합니다.
@@ -12,6 +13,16 @@
이번 글에선 비교 시 일어나는 기이한 현상을 포함하여 다양한 자료형을 대상으로 자바스크립트가 어떻게 비교를 하는지에 대해 다룰 예정입니다.
글 말미에는 자바스크립트에서만 일어나는 '기이한' 현상을 어떻게 예방할 수 있는지에 대해서 언급해두었습니다.
+=======
+- Greater/less than: a > b
, a < b
.
+- Greater/less than or equals: a >= b
, a <= b
.
+- Equals: `a == b`, please note the double equality sign `==` means the equality test, while a single one `a = b` means an assignment.
+- Not equals: In maths the notation is ≠
, but in JavaScript it's written as a != b
.
+
+In this article we'll learn more about different types of comparisons, how JavaScript makes them, including important peculiarities.
+
+At the end you'll find a good recipe to avoid "JavaScript quirks"-related issues.
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
## 불린형 반환
@@ -57,7 +68,13 @@ alert( 'Bee' > 'Be' ); // true
4. 글자 간 비교가 끝날 때까지 이 과정을 반복합니다.
5. 비교가 종료되었고 문자열의 길이도 같다면 두 문자열은 동일하다고 결론 냅니다. 비교가 종료되었지만 두 문자열의 길이가 다르면 길이가 긴 문자열이 더 크다고 결론 냅니다.
+<<<<<<< HEAD
예시의 `'Z' > 'A'`는 위 알고리즘의 첫 번째 단계에서 비교 결과가 도출됩니다. 반면, 문자열 `'Glow'`와 `'Glee'`는 복수의 문자로 이루어진 문자열이기 때문에, 아래와 같은 순서로 문자열 비교가 이뤄집니다.
+=======
+In the first example above, the comparison `'Z' > 'A'` gets to a result at the first step.
+
+The second comparison `'Glow'` and `'Glee'` needs more steps as strings are compared character-by-character:
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
1. `G`는 `G`와 같습니다.
2. `l`은 `l`과 같습니다.
diff --git a/1-js/02-first-steps/10-ifelse/2-check-standard/task.md b/1-js/02-first-steps/10-ifelse/2-check-standard/task.md
index 2f0a250112..562802995e 100644
--- a/1-js/02-first-steps/10-ifelse/2-check-standard/task.md
+++ b/1-js/02-first-steps/10-ifelse/2-check-standard/task.md
@@ -6,7 +6,11 @@ importance: 2
`if..else` 구조를 이용해 "자바스크립트의 '공식' 이름은 무엇일까요?"라는 질문을 하는 코드를 작성해 보세요.
+<<<<<<< HEAD
사용자가 'ECMAScript'를 입력했다면 '정답입니다!', 아니라면 '모르셨나요? 정답은 ECMAScript입니다!'라는 메시지를 보여주세요.
+=======
+If the visitor enters "ECMAScript", then output "Right!", otherwise -- output: "You don't know? ECMAScript!"
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9

diff --git a/1-js/02-first-steps/10-ifelse/article.md b/1-js/02-first-steps/10-ifelse/article.md
index 9d12c2ce83..0879f47fdb 100644
--- a/1-js/02-first-steps/10-ifelse/article.md
+++ b/1-js/02-first-steps/10-ifelse/article.md
@@ -68,7 +68,11 @@ if (cond) {
## 'else'절
+<<<<<<< HEAD
`if`문엔 `else` 절을 붙일 수 있습니다. `else` 뒤에 이어지는 코드 블록은 조건이 거짓일 때 실행됩니다.
+=======
+The `if` statement may contain an optional `else` block. It executes when the condition is falsy.
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
예시:
```js run
@@ -180,10 +184,17 @@ alert( message );
물음표 연산자를 이런 방식으로 쓰는 걸 처음 본 분이라면 이 코드가 어떻게 동작하는지 파악하기 힘들 수 있습니다. 그러나 주의를 집중하고 보면, 단순히 여러 조건을 나열한 코드임에 불과하다는 것을 알 수 있습니다.
+<<<<<<< HEAD
1. 첫 번째 물음표에선 조건문 `age < 3`을 검사합니다.
2. 그 결과가 참이면 `'아기야 안녕?'`를 반환합니다. 그렇지 않다면 첫 번째 콜론 `":"`에 이어지는 조건문 `age < 18`을 검사합니다.
3. 그 결과가 참이면 `'안녕!'`를 반환합니다. 그렇지 않다면 다음 콜론 `":"`에 이어지는 조건문 `age < 100`을 검사합니다.
4. 그 결과가 참이면 `'환영합니다!'`를 반환합니다. 그렇지 않다면 마지막 콜론 `":"` 이후의 표현식인 `'나이가 아주 많으시거나, 나이가 아닌 값을 입력 하셨군요!'`를 반환합니다.
+=======
+1. The first question mark checks whether `age < 3`.
+2. If true -- it returns `'Hi, baby!'`. Otherwise, it continues to the expression after the colon ":", checking `age < 18`.
+3. If that's true -- it returns `'Hello!'`. Otherwise, it continues to the expression after the next colon ":", checking `age < 100`.
+4. If that's true -- it returns `'Greetings!'`. Otherwise, it continues to the expression after the last colon ":", returning `'What an unusual age!'`.
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
`if..else`를 사용하면 위 예시를 아래와 같이 변형할 수 있습니다.
diff --git a/1-js/02-first-steps/11-logical-operators/3-alert-1-null-2/solution.md b/1-js/02-first-steps/11-logical-operators/3-alert-1-null-2/solution.md
index f3265b77bb..994e62d7bf 100644
--- a/1-js/02-first-steps/11-logical-operators/3-alert-1-null-2/solution.md
+++ b/1-js/02-first-steps/11-logical-operators/3-alert-1-null-2/solution.md
@@ -1,6 +1,6 @@
피연산자 중 첫 번째 falsy인 `null`이 출력됩니다.
```js run
-alert( 1 && null && 2 );
+alert(1 && null && 2);
```
diff --git a/1-js/02-first-steps/11-logical-operators/6-check-if-in-range/task.md b/1-js/02-first-steps/11-logical-operators/6-check-if-in-range/task.md
index e11019df3c..4d5c47bebf 100644
--- a/1-js/02-first-steps/11-logical-operators/6-check-if-in-range/task.md
+++ b/1-js/02-first-steps/11-logical-operators/6-check-if-in-range/task.md
@@ -4,6 +4,10 @@ importance: 3
# 사이 범위 확인하기
+<<<<<<< HEAD
`age`(나이)가 `14`세 이상 `90`세 이하에 속하는지를 확인하는 `if`문을 작성하세요.
+=======
+Write an `if` condition to check that `age` is between `14` and `90` inclusively.
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
"이상과 이하"는 `age`(나이) 범위에 `14`나 `90`이 포함된다는 의미입니다.
diff --git a/1-js/02-first-steps/11-logical-operators/7-check-if-out-range/task.md b/1-js/02-first-steps/11-logical-operators/7-check-if-out-range/task.md
index 8add5934a5..e0e8b05b6f 100644
--- a/1-js/02-first-steps/11-logical-operators/7-check-if-out-range/task.md
+++ b/1-js/02-first-steps/11-logical-operators/7-check-if-out-range/task.md
@@ -4,6 +4,10 @@ importance: 3
# 바깥 범위 확인하기
+<<<<<<< HEAD
`age`(나이)가 `14`세 이상 `90`세 이하에 속하지 않는지를 확인하는 `if`문을 작성하세요.
+=======
+Write an `if` condition to check that `age` is NOT between `14` and `90` inclusively.
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
답안은 NOT `!` 연산자를 사용한 답안과 사용하지 않은 답안 2가지를 제출해 주세요.
\ No newline at end of file
diff --git a/1-js/02-first-steps/11-logical-operators/9-check-login/solution.md b/1-js/02-first-steps/11-logical-operators/9-check-login/solution.md
index 66e7916d0d..707a266ad5 100644
--- a/1-js/02-first-steps/11-logical-operators/9-check-login/solution.md
+++ b/1-js/02-first-steps/11-logical-operators/9-check-login/solution.md
@@ -3,20 +3,32 @@
```js run demo
let userName = prompt("사용자 이름을 입력해주세요.", '');
-if (userName == 'Admin') {
+if (userName === 'Admin') {
let pass = prompt('비밀번호:', '');
+<<<<<<< HEAD
if (pass == 'TheMaster') {
alert( '환영합니다!' );
} else if (pass == '' || pass == null) {
alert( '취소되었습니다.' );
+=======
+ if (pass === 'TheMaster') {
+ alert( 'Welcome!' );
+ } else if (pass === '' || pass === null) {
+ alert( 'Canceled' );
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
} else {
alert( '인증에 실패하였습니다.' );
}
+<<<<<<< HEAD
} else if (userName == '' || userName == null) {
alert( '취소되었습니다.' );
+=======
+} else if (userName === '' || userName === null) {
+ alert( 'Canceled' );
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
} else {
alert( "인증되지 않은 사용자입니다." );
}
diff --git a/1-js/02-first-steps/11-logical-operators/article.md b/1-js/02-first-steps/11-logical-operators/article.md
index a71878d535..a62f237f49 100644
--- a/1-js/02-first-steps/11-logical-operators/article.md
+++ b/1-js/02-first-steps/11-logical-operators/article.md
@@ -1,6 +1,10 @@
# 논리 연산자
+<<<<<<< HEAD
자바스크립트엔 세 종류의 논리 연산자 `||`(OR), `&&`(AND), `!`(NOT)이 있습니다.
+=======
+There are four logical operators in JavaScript: `||` (OR), `&&` (AND), `!` (NOT), `??` (Nullish Coalescing). Here we cover the first three, the `??` operator is in the next article.
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
연산자에 '논리'라는 수식어가 붙긴 하지만 논리 연산자는 피연산자로 불린형뿐만 아니라 모든 타입의 값을 받을 수 있습니다. 연산 결과 역시 모든 타입이 될 수 있습니다.
@@ -64,7 +68,11 @@ if (hour < 10 || hour > 18 || isWeekend) {
}
```
+<<<<<<< HEAD
## 첫 번째 truthy를 찾는 OR 연산자 '||'
+=======
+## OR "||" finds the first truthy value [#or-finds-the-first-truthy-value]
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
지금까진 피연산자가 불린형인 경우만을 다뤘습니다. 전통적인 방식이죠. 이제 자바스크립트에서만 제공하는 논리연산자 OR의 '추가'기능에 대해 알아보겠습니다.
@@ -84,7 +92,11 @@ result = value1 || value2 || value3;
여기서 핵심은 반환 값이 형 변환을 하지 않은 원래 값이라는 것입니다.
+<<<<<<< HEAD
정리해 보자면 이렇습니다. OR `"||"` 연산자를 여러 개 체이닝(chaining) 하면 첫 번째 truthy를 반환합니다. 피연산자에 truthy가 하나도 없다면 마지막 피연산자를 반환합니다.
+=======
+In other words, a chain of OR `||` returns the first truthy value or the last one if no truthy value is found.
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
예시:
@@ -101,9 +113,15 @@ alert( undefined || null || 0 ); // 0 (모두 falsy이므로, 마지막 값을
1. **변수 또는 표현식으로 구성된 목록에서 첫 번째 truthy 얻기**
+<<<<<<< HEAD
`firstName`, `lastName`, `nickName`이란 변수가 있는데 이 값들은 모두 옵션 값이라고 해봅시다.
OR `||`을 사용하면 실제 값이 들어있는 변수를 찾고, 그 값을 보여줄 수 있습니다. 변수 모두에 값이 없는 경우엔 `익명`를 보여줍시다.
+=======
+ For instance, we have `firstName`, `lastName` and `nickName` variables, all optional (i.e. can be undefined or have falsy values).
+
+ Let's use OR `||` to choose the one that has the data and show it (or `"Anonymous"` if nothing set):
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
```js run
let firstName = "";
@@ -115,7 +133,11 @@ alert( undefined || null || 0 ); // 0 (모두 falsy이므로, 마지막 값을
*/!*
```
+<<<<<<< HEAD
모든 변수가 falsy이면 `"익명"`이 출력되었을 겁니다.
+=======
+ If all variables were falsy, `"Anonymous"` would show up.
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
2. **단락 평가**
@@ -123,7 +145,11 @@ alert( undefined || null || 0 ); // 0 (모두 falsy이므로, 마지막 값을
위에서 설명해 드린 바와 같이 OR`||`은 왼쪽부터 시작해서 오른쪽으로 평가를 진행하는데, truthy를 만나면 나머지 값들은 건드리지 않은 채 평가를 멈춥니다. 이런 프로세스를 '단락 평가'라고 합니다.
+<<<<<<< HEAD
단락 평가의 동작 방식은 두 번째 피연산자가 변수 할당과 같은 부수적인 효과(side effect)를 가지는 표현식 일 때 명확히 볼 수 있습니다.
+=======
+ The importance of this feature becomes obvious if an operand isn't just a value, but an expression with a side effect, such as a variable assignment or a function call.
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
아래 예시를 실행하면 두 번째 메시지만 출력됩니다.
@@ -223,8 +249,13 @@ AND 연산자 `&&`의 우선순위는 OR 연산자 `||`보다 높습니다.
따라서 `a && b || c && d`는 `(a && b) || (c && d)`와 동일하게 동작합니다.
````
+<<<<<<< HEAD
````warn header="`if`를 ||나 &&로 대체하지 마세요."
어떤 개발자들은 AND 연산자 `&&`를 `if`문을 '짧게' 줄이는 용도로 사용하곤 합니다.
+=======
+````warn header="Don't replace `if` with `||` or `&&`"
+Sometimes, people use the AND `&&` operator as a "shorter way to write `if`".
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
예시:
@@ -244,7 +275,11 @@ let x = 1;
if (x > 0) alert( '0보다 큽니다!' );
```
+<<<<<<< HEAD
`&&`를 사용한 코드가 더 짧긴 하지만 `if`문을 사용한 예시가 코드에서 무엇을 구현하고자 하는지 더 명백히 드러내고, 가독성도 좋습니다. 그러니 if 조건문이 필요하면 `if`를 사용하고 AND 연산자는 연산자 목적에 맞게 사용합시다.
+=======
+Although, the variant with `&&` appears shorter, `if` is more obvious and tends to be a little bit more readable. So we recommend using every construct for its purpose: use `if` if we want `if` and use `&&` if we want AND.
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
````
diff --git a/1-js/02-first-steps/12-nullish-coalescing-operator/article.md b/1-js/02-first-steps/12-nullish-coalescing-operator/article.md
index 04ca8f04bd..a4c91ce166 100644
--- a/1-js/02-first-steps/12-nullish-coalescing-operator/article.md
+++ b/1-js/02-first-steps/12-nullish-coalescing-operator/article.md
@@ -2,6 +2,7 @@
[recent browser="new"]
+<<<<<<< HEAD
nullish 병합 연산자(nullish coalescing operator) `??`를 사용하면 짧은 문법으로 여러 피연산자 중 그 값이 '확정되어있는' 변수를 찾을 수 있습니다.
`a ?? b`의 평가 결과는 다음과 같습니다.
@@ -9,11 +10,27 @@ nullish 병합 연산자(nullish coalescing operator) `??`를 사용하면 짧
- 그 외의 경우는 `b`
nullish 병합 연산자 `??`없이 `x = a ?? b`와 동일한 동작을 하는 코드를 작성하면 다음과 같습니다.
+=======
+The nullish coalescing operator is written as two question marks `??`.
+
+As it treats `null` and `undefined` similarly, we'll use a special term here, in this article. For brevity, we'll say that a value is "defined" when it's neither `null` nor `undefined`.
+
+The result of `a ?? b` is:
+- if `a` is defined, then `a`,
+- if `a` isn't defined, then `b`.
+
+In other words, `??` returns the first argument if it's not `null/undefined`. Otherwise, the second one.
+
+The nullish coalescing operator isn't anything completely new. It's just a nice syntax to get the first "defined" value of the two.
+
+We can rewrite `result = a ?? b` using the operators that we already know, like this:
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
```js
-x = (a !== null && a !== undefined) ? a : b;
+result = (a !== null && a !== undefined) ? a : b;
```
+<<<<<<< HEAD
비교 연산자와 논리 연산자만으로 nullish 병합 연산자와 같은 기능을 하는 코드를 작성하니 코드 길이가 길어지네요.
또 다른 예시를 살펴봅시다. `firstName`, `lastName`, `nickName`이란 변수에 사용자 이름이나 별명을 저장하는데, 사용자가 아무런 정보도 입력하지 않는 케이스도 허용한다고 해보겠습니다.
@@ -21,13 +38,46 @@ x = (a !== null && a !== undefined) ? a : b;
화면엔 세 변수 중 실제 값이 있는 변수의 값을 출력하는데, 세 변수 모두 값이 없다면 '익명의 사용자'가 출력되도록 해보죠.
이럴 때 nullish 병합 연산자 `??`를 사용하면 값이 정해진 변수를 간편하게 찾아낼 수 있습니다.
+=======
+Now it should be absolutely clear what `??` does. Let's see where it helps.
+
+The common use case for `??` is to provide a default value.
+
+For example, here we show `user` if its value isn't `null/undefined`, otherwise `Anonymous`:
+
+```js run
+let user;
+
+alert(user ?? "Anonymous"); // Anonymous (user is undefined)
+```
+
+Here's the example with `user` assigned to a name:
+
+```js run
+let user = "John";
+
+alert(user ?? "Anonymous"); // John (user is not null/undefined)
+```
+
+We can also use a sequence of `??` to select the first value from a list that isn't `null/undefined`.
+
+Let's say we have a user's data in variables `firstName`, `lastName` or `nickName`. All of them may be not defined, if the user decided not to fill in the corresponding values.
+
+We'd like to display the user name using one of these variables, or show "Anonymous" if all of them are `null/undefined`.
+
+Let's use the `??` operator for that:
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
```js run
let firstName = null;
let lastName = null;
let nickName = "바이올렛";
+<<<<<<< HEAD
// null이나 undefined가 아닌 첫 번째 피연산자
+=======
+// shows the first defined value:
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
*!*
alert(firstName ?? lastName ?? nickName ?? "익명의 사용자"); // 바이올렛
*/!*
@@ -35,6 +85,7 @@ alert(firstName ?? lastName ?? nickName ?? "익명의 사용자"); // 바이올
## '??'와 '||'의 차이
+<<<<<<< HEAD
nullish 병합 연산자는 OR 연산자 `||`와 상당히 유사해 보입니다. 실제로 위 예시에서 `??`를 `||`로 바꿔도 그 결과는 동일하기까지 하죠. 관련 내용은 [이전 챕터](info:logical-operators#or-finds-the-first-truthy-value)에서 살펴본 바 있습니다.
그런데 두 연산자 사이에는 중요한 차이점이 있습니다.
@@ -42,9 +93,38 @@ nullish 병합 연산자는 OR 연산자 `||`와 상당히 유사해 보입니
- `??`는 첫 번째 *정의된(defined)* 값을 반환합니다.
`null`과 `undefined`, 숫자 `0`을 구분 지어 다뤄야 할 때 이 차이점은 매우 중요한 역할을 합니다.
+=======
+The OR `||` operator can be used in the same way as `??`, as it was described in the [previous chapter](info:logical-operators#or-finds-the-first-truthy-value).
+
+For example, in the code above we could replace `??` with `||` and still get the same result:
+
+```js run
+let firstName = null;
+let lastName = null;
+let nickName = "Supercoder";
+
+// shows the first truthy value:
+*!*
+alert(firstName || lastName || nickName || "Anonymous"); // Supercoder
+*/!*
+```
+
+Historically, the OR `||` operator was there first. It's been there since the beginning of JavaScript, so developers were using it for such purposes for a long time.
+
+On the other hand, the nullish coalescing operator `??` was added to JavaScript only recently, and the reason for that was that people weren't quite happy with `||`.
+
+The important difference between them is that:
+- `||` returns the first *truthy* value.
+- `??` returns the first *defined* value.
+
+In other words, `||` doesn't distinguish between `false`, `0`, an empty string `""` and `null/undefined`. They are all the same -- falsy values. If any of these is the first argument of `||`, then we'll get the second argument as the result.
+
+In practice though, we may want to use default value only when the variable is `null/undefined`. That is, when the value is really unknown/not set.
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
예시를 살펴봅시다.
+<<<<<<< HEAD
```js
height = height ?? 100;
```
@@ -53,6 +133,8 @@ height = height ?? 100;
이제 `??`와 `||`을 비교해봅시다.
+=======
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
```js run
let height = 0;
@@ -60,19 +142,36 @@ alert(height || 100); // 100
alert(height ?? 100); // 0
```
+<<<<<<< HEAD
`height || 100`은 `height`에 `0`을 할당했지만 `0`을 falsy 한 값으로 취급했기 때문에 `null`이나 `undefined`를 할당한 것과 동일하게 처리합니다. 따라서 `height || 100`의 평가 결과는 `100`입니다.
반면 `height ?? 100`의 평가 결과는 `height`가 정확하게 `null`이나 `undefined`일 경우에만 `100`이 됩니다. 예시에선 `height`에 `0`이라는 값을 할당했기 때문에 얼럿창엔 `0`이 출력됩니다.
이런 특징 때문에 높이처럼 `0`이 할당될 수 있는 변수를 사용해 기능을 개발할 땐 `||`보다 `??`가 적합합니다.
+=======
+- The `height || 100` checks `height` for being a falsy value, and it's `0`, falsy indeed.
+ - so the result of `||` is the second argument, `100`.
+- The `height ?? 100` checks `height` for being `null/undefined`, and it's not,
+ - so the result is `height` "as is", that is `0`.
+
+In practice, the zero height is often a valid value, that shouldn't be replaced with the default. So `??` does just the right thing.
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
## 연산자 우선순위
+<<<<<<< HEAD
[`??`의 연산자 우선순위](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_Precedence#Table)는 `5`로 꽤 낮습니다.
따라서 `??`는 `=`와 `?` 보다는 먼저, 대부분의 연산자보다는 나중에 평가됩니다.
그렇기 때문에 복잡한 표현식 안에서 `??`를 사용해 값을 하나 선택할 땐 괄호를 추가하는 게 좋습니다.
+=======
+The precedence of the `??` operator is the same as `||`. They both equal `3` in the [MDN table](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_Precedence#Table).
+
+That means that, just like `||`, the nullish coalescing operator `??` is evaluated before `=` and `?`, but after most other operations, such as `+`, `*`.
+
+So we may need to add parentheses in expressions like this:
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
```js run
let height = null;
@@ -84,6 +183,7 @@ let area = (height ?? 100) * (width ?? 50);
alert(area); // 5000
```
+<<<<<<< HEAD
그렇지 않으면 `*`가 `??`보다 우선순위가 높기 때문에 `*`가 먼저 실행됩니다.
결국엔 아래 예시처럼 동작하겠죠.
@@ -96,6 +196,21 @@ let area = height ?? (100 * width) ?? 50;
`??`엔 자바스크립트 언어에서 규정한 또 다른 제약사항이 있습니다.
**안정성 관련 이슈 때문에 `??`는 `&&`나 `||`와 함께 사용하지 못합니다.**
+=======
+Otherwise, if we omit parentheses, then as `*` has the higher precedence than `??`, it would execute first, leading to incorrect results.
+
+```js
+// without parentheses
+let area = height ?? 100 * width ?? 50;
+
+// ...works this way (not what we want):
+let area = height ?? (100 * width) ?? 50;
+```
+
+### Using ?? with && or ||
+
+Due to safety reasons, JavaScript forbids using `??` together with `&&` and `||` operators, unless the precedence is explicitly specified with parentheses.
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
아래 예시를 실행하면 문법 에러가 발생합니다.
@@ -103,7 +218,11 @@ let area = height ?? (100 * width) ?? 50;
let x = 1 && 2 ?? 3; // SyntaxError: Unexpected token '??'
```
+<<<<<<< HEAD
이 제약에 대해선 아직 논쟁이 많긴 하지만 사람들이 `||`를 `??`로 바꾸기 시작하면서 만드는 실수를 방지하고자 명세서에 제약이 추가된 상황입니다.
+=======
+The limitation is surely debatable, it was added to the language specification with the purpose to avoid programming mistakes, when people start to switch from `||` to `??`.
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
제약을 피하려면 괄호를 사용해주세요.
@@ -117,7 +236,11 @@ alert(x); // 2
## 요약
+<<<<<<< HEAD
- nullish 병합 연산자 `??`를 사용하면 피연산자 중 '값이 할당된' 변수를 빠르게 찾을 수 있습니다.
+=======
+- The nullish coalescing operator `??` provides a short way to choose the first "defined" value from a list.
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
`??`는 변수에 기본값을 할당하는 용도로 사용할 수 있습니다.
@@ -126,5 +249,10 @@ alert(x); // 2
height = height ?? 100;
```
+<<<<<<< HEAD
- `??`의 연산자 우선순위는 대다수의 연산자보다 낮고 `?`와 `=` 보다는 높습니다.
- 괄호 없이 `??`를 `||`나 `&&`와 함께 사용하는 것은 금지되어있습니다.
+=======
+- The operator `??` has a very low precedence, only a bit higher than `?` and `=`, so consider adding parentheses when using it in an expression.
+- It's forbidden to use it with `||` or `&&` without explicit parentheses.
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
diff --git a/1-js/02-first-steps/13-while-for/6-repeat-until-correct/solution.md b/1-js/02-first-steps/13-while-for/6-repeat-until-correct/solution.md
index dff25b0bc7..0f2c5fa340 100644
--- a/1-js/02-first-steps/13-while-for/6-repeat-until-correct/solution.md
+++ b/1-js/02-first-steps/13-while-for/6-repeat-until-correct/solution.md
@@ -9,7 +9,12 @@ do {
`do..while`반복문을 사용해 아래 두 조건이 모두 truthy인 경우 프롬프트 창이 뜨게 하면 됩니다.
+<<<<<<< HEAD
1. `num <= 100`인지 확인하기. `100`보다 작거나 같은 값을 입력한 경우 프롬프트 창이 떠야 합니다.
2. `num`이 `null`이나 빈 문자열인지 확인하기. `num`이 `null`이나 빈 문자열이면 `&& num`이 거짓이 되므로 `while` 반복문이 종료됩니다.
+=======
+1. The check for `num <= 100` -- that is, the entered value is still not greater than `100`.
+2. The check `&& num` is false when `num` is `null` or an empty string. Then the `while` loop stops too.
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
참고: `num`이 `null`인 경우 `num <= 100`은 `true`가 되므로 두 번째 조건이 없으면 취소 버튼을 눌러도 반복문이 계속해서 실행됩니다. 따라서 위 두 조건을 모두 확인해야 합니다.
diff --git a/1-js/02-first-steps/13-while-for/article.md b/1-js/02-first-steps/13-while-for/article.md
index fee9f4adcc..33ef3079df 100644
--- a/1-js/02-first-steps/13-while-for/article.md
+++ b/1-js/02-first-steps/13-while-for/article.md
@@ -6,7 +6,24 @@
*반복문(loop)* 을 사용하면 동일한 코드를 여러 번 반복할 수 있습니다.
+<<<<<<< HEAD
## 'while' 반복문
+=======
+```smart header="The for..of and for..in loops"
+A small announcement for advanced readers.
+
+This article covers only basic loops: `while`, `do..while` and `for(..;..;..)`.
+
+If you came to this article searching for other types of loops, here are the pointers:
+
+- See [for..in](info:object#forin) to loop over object properties.
+- See [for..of](info:array#loops) and [iterables](info:iterable) for looping over arrays and iterable objects.
+
+Otherwise, please read on.
+```
+
+## The "while" loop
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
`while` 반복문의 문법은 다음과 같습니다.
@@ -106,10 +123,17 @@ for (let i = 0; i < 3; i++) { // 0, 1, 2가 출력됩니다.
| 구성 요소 | | |
|-------|----------|----------------------------------------------------------------------------|
+<<<<<<< HEAD
| begin | `i = 0` | 반복문에 진입할 때 단 한 번 실행됩니다. |
| condition | `i < 3`| 반복마다 해당 조건이 확인됩니다. false이면 반복문을 멈춥니다. |
| body | `alert(i)`| condition이 truthy일 동안 계속해서 실행됩니다. |
| step| `i++` | 각 반복의 body가 실행된 이후에 실행됩니다. |
+=======
+| begin | `let i = 0` | Executes once upon entering the loop. |
+| condition | `i < 3`| Checked before every loop iteration. If false, the loop stops. |
+| body | `alert(i)`| Runs again and again while the condition is truthy. |
+| step| `i++` | Executes after the body on each iteration. |
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
일반적인 반복문 알고리즘은 다음과 같습니다.
@@ -162,11 +186,14 @@ for (i = 0; i < 3; i++) { // 기존에 정의된 변수 사용
alert(i); // 3, 반복문 밖에서 선언한 변수이므로 사용할 수 있음
```
-
````
+<<<<<<< HEAD
### 구성 요소 생략하기
+=======
+### Skipping parts
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
`for`문의 구성 요소를 생략하는 것도 가능합니다.
@@ -268,7 +295,11 @@ for (let i = 0; i < 10; i++) {
기술적인 관점에서 봤을 때, 이 예시는 위쪽에 있는 예시와 동일합니다. `continue`를 사용하는 대신 코드를 `if` 블록으로 감싼 점만 다릅니다.
+<<<<<<< HEAD
그런데 이렇게 코드를 작성하면 부작용으로 중첩 레벨(중괄호 안의 `alert` 호출)이 하나 더 늘어납니다. `if` 안의 코드가 길어진다면 전체 가독성이 떨어질 수 있습니다.
+=======
+But as a side effect, this created one more level of nesting (the `alert` call inside the curly braces). If the code inside of `if` is longer than a few lines, that may decrease the overall readability.
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
````
````warn header="'?' 오른쪽엔 `break`나 `continue`가 올 수 없습니다."
@@ -286,7 +317,6 @@ if (i > 5) {
물음표를 사용해서 위 조건문을 아래와 같이 바꾸려는 시도를 할 수 있을겁니다.
-
```js no-beautify
(i > 5) ? alert(i) : *!*continue*/!*; // 여기에 continue를 사용하면 안 됩니다.
```
@@ -318,9 +348,16 @@ alert('완료!');
사용자가 `Cancel` 버튼을 눌렀을 때 반복문을 중단시킬 방법이 필요합니다.
+<<<<<<< HEAD
`input` 아래에 평범한 `break` 지시자를 사용하면 안쪽에 있는 반복문만 빠져나올 수 있습니다. 이것만으론 충분하지 않습니다(중첩 반복문을 포함한 반복문 두 개 모두를 빠져나와야 하기 때문이죠 - 옮긴이). 이럴 때 레이블을 사용할 수 있습니다.
*레이블(label)* 은 반복문 앞에 콜론과 함께 쓰이는 식별자입니다.
+=======
+The ordinary `break` after `input` would only break the inner loop. That's not sufficient -- labels, come to the rescue!
+
+A *label* is an identifier with a colon before a loop:
+
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
```js
labelName: for (...) {
...
@@ -342,7 +379,12 @@ labelName: for (...) {
// 입력받은 값을 가지고 무언가를 함
}
}
+<<<<<<< HEAD
alert('완료!');
+=======
+
+alert('Done!');
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
```
위 예시에서 `break outer`는 `outer`라는 레이블이 붙은 반복문을 찾고, 해당 반복문을 빠져나오게 해줍니다.
@@ -361,14 +403,37 @@ for (let i = 0; i < 3; i++) { ... }
````warn header="레이블은 마음대로 '점프'할 수 있게 해주지 않습니다."
레이블을 사용한다고 해서 원하는 곳으로 마음대로 점프할 수 있는 것은 아닙니다.
+<<<<<<< HEAD
아래 예시처럼 레이블을 사용하는 것은 불가능합니다.
```js
break label; // 아래 for 문으로 점프할 수 없습니다.
+=======
+For example, it is impossible to do this:
+
+```js
+break label; // jump to the label below (doesn't work)
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
label: for (...)
```
+<<<<<<< HEAD
`break`와 `continue`는 반복문 안에서만 사용할 수 있고, 레이블은 반드시 `break`이나 `continue` 지시자 위에 있어야 합니다.
+=======
+A `break` directive must be inside a code block. Technically, any labelled code block will do, e.g.:
+
+```js
+label: {
+ // ...
+ break label; // works
+ // ...
+}
+```
+
+...Although, 99.9% of the time `break` is used inside loops, as we've seen in the examples above.
+
+A `continue` is only possible from inside a loop.
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
````
## 요약
diff --git a/1-js/02-first-steps/14-switch/article.md b/1-js/02-first-steps/14-switch/article.md
index 251cbba446..dbf775660e 100644
--- a/1-js/02-first-steps/14-switch/article.md
+++ b/1-js/02-first-steps/14-switch/article.md
@@ -47,7 +47,11 @@ switch (a) {
break;
*/!*
case 5:
+<<<<<<< HEAD
alert( '비교하려는 값보다 큽니다.' );
+=======
+ alert( 'Too big' );
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
break;
default:
alert( "어떤 값인지 파악이 되지 않습니다." );
@@ -139,7 +143,11 @@ switch (a) {
`case 3`과 `case 5`는 동일한 메시지를 보여줍니다.
+<<<<<<< HEAD
`switch/case`문에서 `break`문이 없는 경우엔 조건에 상관없이 다음 `case`문이 실행되는 부작용이 발생합니다. 위 예시에서 `case 3`이 참인 경우엔 `(*)`로 표시한 줄 아래의 코드가 실행되는데, 그 아래 줄엔 `case 5`가 있고 `break`문도 없기 때문에 12번째 줄의 `break`문을 만날 때까지 코드는 계속 실행됩니다.
+=======
+The ability to "group" cases is a side effect of how `switch/case` works without `break`. Here the execution of `case 3` starts from the line `(*)` and goes through `case 5`, because there's no `break`.
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
## 자료형의 중요성
diff --git a/1-js/02-first-steps/15-function-basics/1-if-else-required/solution.md b/1-js/02-first-steps/15-function-basics/1-if-else-required/solution.md
index 85b5d8ab37..8ee841c60d 100644
--- a/1-js/02-first-steps/15-function-basics/1-if-else-required/solution.md
+++ b/1-js/02-first-steps/15-function-basics/1-if-else-required/solution.md
@@ -1 +1,7 @@
-동일하게 동작합니다.
\ No newline at end of file
+<<<<<<< HEAD
+동일하게 동작합니다.
+=======
+No difference!
+
+In both cases, `return confirm('Did parents allow you?')` executes exactly when the `if` condition is falsy.
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
diff --git a/1-js/02-first-steps/15-function-basics/2-rewrite-function-question-or/solution.md b/1-js/02-first-steps/15-function-basics/2-rewrite-function-question-or/solution.md
index e0a188c9ba..51db4ad085 100644
--- a/1-js/02-first-steps/15-function-basics/2-rewrite-function-question-or/solution.md
+++ b/1-js/02-first-steps/15-function-basics/2-rewrite-function-question-or/solution.md
@@ -14,4 +14,8 @@ function checkAge(age) {
}
```
-`age > 18`을 감싸고 있는 괄호는 가독성을 높이기 위해 넣었습니다. 괄호가 없어도 동일하게 동작합니다.
\ No newline at end of file
+<<<<<<< HEAD
+`age > 18`을 감싸고 있는 괄호는 가독성을 높이기 위해 넣었습니다. 괄호가 없어도 동일하게 동작합니다.
+=======
+Note that the parentheses around `age > 18` are not required here. They exist for better readability.
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
diff --git a/1-js/02-first-steps/15-function-basics/article.md b/1-js/02-first-steps/15-function-basics/article.md
index 327bed8f91..4d77a83368 100644
--- a/1-js/02-first-steps/15-function-basics/article.md
+++ b/1-js/02-first-steps/15-function-basics/article.md
@@ -20,11 +20,19 @@ function showMessage() {
}
```
+<<<<<<< HEAD
`function` 키워드, *함수 이름*, 괄호로 둘러싼 매개변수를 차례로 써주면 함수를 선언할 수 있습니다. 위 함수에는 매개변수가 없는데, 만약 매개변수가 여러 개 있다면 각 매개변수를 콤마로 구분해 줍니다. 이어서 함수를 구성하는 코드의 모임인 '함수 본문(body)'을 중괄호로 감싸 붙여줍시다.
```js
function name(parameter1, parameter2, ... parameterN) {
// 함수 본문
+=======
+The `function` keyword goes first, then goes the *name of the function*, then a list of *parameters* between the parentheses (comma-separated, empty in the example above, we'll see examples later) and finally the code of the function, also named "the function body", between curly braces.
+
+```js
+function name(parameter1, parameter2, ... parameterN) {
+ // body
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
}
```
@@ -137,12 +145,20 @@ alert( userName ); // 함수는 외부 변수에 접근하지 않습니다. 따
## 매개변수
+<<<<<<< HEAD
매개변수(parameter)를 이용하면 임의의 데이터를 함수 안에 전달할 수 있습니다. 매개변수는 *인자(parameter)* 라고 불리기도 합니다.
+=======
+We can pass arbitrary data to functions using parameters.
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
아래 예시에서 함수 showMessage는 매개변수 `from` 과 `text`를 가집니다.
```js run
+<<<<<<< HEAD
function showMessage(*!*from, text*/!*) { // 인자: from, text
+=======
+function showMessage(*!*from, text*/!*) { // parameters: from, text
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
alert(from + ': ' + text);
}
@@ -152,8 +168,11 @@ function showMessage(*!*from, text*/!*) { // 인자: from, text
`(*)`, `(**)`로 표시한 줄에서 함수를 호출하면, 함수에 전달된 인자는 지역변수 `from`과 `text`에 복사됩니다. 그 후 함수는 지역변수에 복사된 값을 사용합니다.
+<<<<<<< HEAD
예시 하나를 더 살펴봅시다. 전역 변수 `from`이 있고, 이 변수를 함수에 전달하였습니다. 함수가 `from`을 변경하지만, 변경 사항은 외부 변수 `from`에 반영되지 않았습니다. 함수는 언제나 복사된 값을 사용하기 때문입니다.
+=======
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
```js run
function showMessage(from, text) {
@@ -172,9 +191,27 @@ showMessage(from, "Hello"); // *Ann*: Hello
alert( from ); // Ann
```
+<<<<<<< HEAD
함수의 매개변수에 전달된 값을 *인수(argument)*라고 부르기도 합니다.
더 정확한 이해를 돕기 위해 용어를 다시 한번 정리해볼까요?
+=======
+When a value is passed as a function parameter, it's also called an *argument*.
+
+In other words, to put these terms straight:
+
+- A parameter is the variable listed inside the parentheses in the function declaration (it's a declaration time term).
+- An argument is the value that is passed to the function when it is called (it's a call time term).
+
+We declare functions listing their parameters, then call them passing arguments.
+
+In the example above, one might say: "the function `showMessage` is declared with two parameters, then called with two arguments: `from` and `"Hello"`".
+
+
+## Default values
+
+If a function is called, but an argument is not provided, then the corresponding value becomes `undefined`.
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
- 매개변수는 함수 선언 방식 괄호 사이에 있는 변수입니다(선언 시 쓰이는 용어).
- 인수는 함수를 호출할 때 매개변수에 전달되는 값입니다(호출 시 쓰이는 용어).
@@ -193,9 +230,15 @@ alert( from ); // Ann
showMessage("Ann");
```
+<<<<<<< HEAD
이렇게 코드를 작성해도 에러가 발생하지 않습니다. 두 번째 매개변수에 값을 전달하지 않았기 때문에 `text`엔 `undefined`가 할당될 뿐입니다. 따라서 에러 없이 `"Ann: undefined"`가 출력됩니다.
매개변수에 값을 전달하지 않아도 그 값이 `undefined`가 되지 않게 하려면 함수를 선언할 때 `=`를 사용해 '기본값(default value)'을 설정해주면 됩니다.
+=======
+That's not an error. Such a call would output `"*Ann*: undefined"`. As the value for `text` isn't passed, it becomes `undefined`.
+
+We can specify the so-called "default" (to use if omitted) value for a parameter in the function declaration, using `=`:
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
```js run
function showMessage(from, *!*text = "no text given"*/!*) {
@@ -205,7 +248,17 @@ function showMessage(from, *!*text = "no text given"*/!*) {
showMessage("Ann"); // Ann: no text given
```
+<<<<<<< HEAD
이젠 `text`가 값을 전달받지 못해도 `undefined` 대신 기본값 `"no text given"`이 할당됩니다.
+=======
+Now if the `text` parameter is not passed, it will get the value `"no text given"`.
+
+The default value also jumps in if the parameter exists, but strictly equals `undefined`, like this:
+
+```js
+showMessage("Ann", undefined); // Ann: no text given
+```
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
매개변수에 값을 전달해도 그 값이 `undefined`와 엄격히 일치한다면 기본값이 할당됩니다.
@@ -230,6 +283,7 @@ function showMessage(from, text = anotherFunction()) {
반면 `text`에 값이 없는 경우 `showMessage()`를 호출할 때마다 `anotherFunction()`이 호출됩니다.
+<<<<<<< HEAD
```
````smart header="구식 자바스크립트에서 매개변수 기본값 설정하는 방법"
@@ -270,14 +324,63 @@ function showMessage(from, text) {
가끔은 함수를 선언할 때가 아닌 함수 선언 후에 매개변수 기본값을 설정하는 것이 적절한 경우도 있습니다.
이런 경우엔 함수를 호출할 때 매개변수를 `undefined`와 비교하여 매개변수가 전달되었는지를 확인합니다.
+=======
+In the example above, `anotherFunction()` isn't called at all, if the `text` parameter is provided.
+
+On the other hand, it's independently called every time when `text` is missing.
+```
+
+````smart header="Default parameters in old JavaScript code"
+Several years ago, JavaScript didn't support the syntax for default parameters. So people used other ways to specify them.
+
+Nowadays, we can come across them in old scripts.
+
+For example, an explicit check for `undefined`:
+
+```js
+function showMessage(from, text) {
+*!*
+ if (text === undefined) {
+ text = 'no text given';
+ }
+*/!*
+
+ alert( from + ": " + text );
+}
+```
+
+...Or using the `||` operator:
+
+```js
+function showMessage(from, text) {
+ // If the value of text is falsy, assign the default value
+ // this assumes that text == "" is the same as no text at all
+ text = text || 'no text given';
+ ...
+}
+```
+````
+
+
+### Alternative default parameters
+
+Sometimes it makes sense to assign default values for parameters at a later stage after the function declaration.
+
+We can check if the parameter is passed during the function execution, by comparing it with `undefined`:
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
```js run
function showMessage(text) {
// ...
*!*
+<<<<<<< HEAD
if (text === undefined) { // 매개변수가 생략되었다면
text = '빈 문자열';
+=======
+ if (text === undefined) { // if the parameter is missing
+ text = 'empty message';
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
}
*/!*
@@ -290,18 +393,31 @@ showMessage(); // 빈 문자열
이렇게 `if`문을 쓰는 것 대신 논리 연산자 `||`를 사용할 수도 있습니다.
```js
+<<<<<<< HEAD
// 매개변수가 생략되었거나 빈 문자열("")이 넘어오면 변수에 '빈 문자열'이 할당됩니다.
function showMessage(text) {
text = text || '빈 문자열';
+=======
+function showMessage(text) {
+ // if text is undefined or otherwise falsy, set it to 'empty'
+ text = text || 'empty';
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
...
}
```
+<<<<<<< HEAD
이 외에도 모던 자바스크립트 엔진이 지원하는 [nullish 병합 연산자(nullish coalescing operator)](info:nullish-coalescing-operator) `??`를 사용하면 `0`처럼 falsy로 평가되는 값들을 일반 값처럼 처리할 수 있어서 좋습니다.
```js run
// 매개변수 'count'가 `undefined` 또는 `null`이면 'unknown'을 출력해주는 함수
+=======
+Modern JavaScript engines support the [nullish coalescing operator](info:nullish-coalescing-operator) `??`, it's better when most falsy values, such as `0`, should be considered "normal":
+
+```js run
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
function showCount(count) {
+ // if count is undefined or null, show "unknown"
alert(count ?? "unknown");
}
@@ -463,9 +579,15 @@ checkPermission(..) // 승인 여부를 확인하고 true나 false를 반환함
```smart header="아주 짧은 이름"
정말 *빈번히* 쓰이는 함수 중에 이름이 아주 짧은 함수가 있습니다.
+<<<<<<< HEAD
[jQuery](http://jquery.com) 프레임워크에서 쓰이는 함수 `$`와 [Lodash](http://lodash.com/) 라이브러리의 핵심 함수 `_` 말이죠.
이 함수들은 지금까지 소개한 함수 이름짓기에 관련된 규칙을 지키지 않고 있습니다. 예외에 속하죠. 함수 이름은 간결하고 함수가 어떤 일을 하는지 설명할 수 있게 지어야 합니다.
+=======
+For example, the [jQuery](https://jquery.com/) framework defines a function with `$`. The [Lodash](https://lodash.com/) library has its core function named `_`.
+
+These are exceptions. Generally function names should be concise and descriptive.
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
```
## 함수 == 주석
@@ -531,7 +653,11 @@ function 함수이름(복수의, 매개변수는, 콤마로, 구분합니다) {
깔끔하고 이해하기 쉬운 코드를 작성하려면 함수 내부에서 외부 변수를 사용하는 방법 대신 지역 변수와 매개변수를 활용하는 게 좋습니다.
+<<<<<<< HEAD
개발자는 매개변수를 받아서 그 변수를 가지고 반환 값을 만들어 내는 함수를 더 쉽게 이해할 수 있습니다. 매개변수 없이 함수 내부에서 외부 변수를 수정해 반환 값을 만들어 내는 함수는 쉽게 이해하기 힘듭니다.
+=======
+It is always easier to understand a function which gets parameters, works with them and returns a result than a function which gets no parameters, but modifies outer variables as a side effect.
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
함수 이름을 지을 땐 아래와 같은 규칙을 따르는 것이 좋습니다.
diff --git a/1-js/02-first-steps/16-function-expressions/article.md b/1-js/02-first-steps/16-function-expressions/article.md
index 1ea5b81e3a..e1806a4ebb 100644
--- a/1-js/02-first-steps/16-function-expressions/article.md
+++ b/1-js/02-first-steps/16-function-expressions/article.md
@@ -12,7 +12,13 @@ function sayHi() {
함수 선언 방식 외에 *함수 표현식(Function Expression)* 을 사용해서 함수를 만들 수 있습니다.
+<<<<<<< HEAD
함수 표현식으로 함수를 생성해보겠습니다.
+=======
+It allows us to create a new function in the middle of any expression.
+
+For example:
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
```js
let sayHi = function() {
@@ -20,9 +26,25 @@ let sayHi = function() {
};
```
+<<<<<<< HEAD
함수를 생성하고 변수에 값을 할당하는 것처럼 함수가 변수에 할당되었습니다. 함수가 어떤 방식으로 만들어졌는지에 관계없이 함수는 값이고, 따라서 변수에 할당할 수 있습니다. 위 예시에선 함수가 변수 `sayHi`에 저장된 값이 되었습니다.
위 예시를 간단한 말로 풀면 다음과 같습니다: "함수를 만들고 그 함수를 변수 `sayHi`에 할당하기"
+=======
+Here we can see a variable `sayHi` getting a value, the new function, created as `function() { alert("Hello"); }`.
+
+As the function creation happens in the context of the assignment expression (to the right side of `=`), this is a *Function Expression*.
+
+Please note, there's no name after the `function` keyword. Omitting a name is allowed for Function Expressions.
+
+Here we immediately assign it to the variable, so the meaning of these code samples is the same: "create a function and put it into the variable `sayHi`".
+
+In more advanced situations, that we'll come across later, a function may be created and immediately called or scheduled for a later execution, not stored anywhere, thus remaining anonymous.
+
+## Function is a value
+
+Let's reiterate: no matter how the function is created, a function is a value. Both examples above store a function in the `sayHi` variable.
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
함수는 값이기 때문에 `alert`를 이용하여 함수 코드를 출력할 수도 있습니다.
@@ -63,22 +85,31 @@ sayHi(); // Hello // 본래 함수도 정상적으로 실행됩니다.
2. `(2)` 에선 `sayHi`를 새로운 변수 `func`에 복사합니다. 이때 `sayHi` 다음에 괄호가 없다는 점에 유의하시기 바랍니다. 괄호가 있었다면 `func = sayHi()` 가 되어 `sayHi` *함수* 그 자체가 아니라, *함수 호출 결과(함수의 반환 값)* 가 `func`에 저장되었을 겁니다.
3. 이젠 `sayHi()` 와 `func()`로 함수를 호출할 수 있게 되었습니다.
+<<<<<<< HEAD
함수 `sayHi`는 아래와 같이 함수 표현식을 사용해 정의할 수 있습니다.
+=======
+We could also have used a Function Expression to declare `sayHi`, in the first line:
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
```js
-let sayHi = function() {
+let sayHi = function() { // (1) create
alert( "Hello" );
};
-let func = sayHi;
+let func = sayHi; //(2)
// ...
```
동작 결과는 동일합니다.
+<<<<<<< HEAD
````smart header="끝에 세미 콜론은 왜 있나요?"
함수 표현식의 끝에 왜 세미 콜론 `;`이 붙는지 의문이 들 수 있습니다. 함수 선언문에는 세미 콜론이 없는데 말이죠.
+=======
+````smart header="Why is there a semicolon at the end?"
+You might wonder, why do Function Expressions have a semicolon `;` at the end, but Function Declarations do not:
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
```js
function sayHi() {
@@ -90,9 +121,15 @@ let sayHi = function() {
}*!*;*/!*
```
+<<<<<<< HEAD
이유는 간단합니다.
- `if { ... }`, `for { }`, `function f { }` 같이 중괄호로 만든 코드 블록 끝엔 `;`이 없어도 됩니다.
- 함수 표현식은 `let sayHi = ...;`과 같은 구문 안에서 값의 역할을 합니다. 코드 블록이 아니고 값처럼 취급되어 변수에 할당되죠. 모든 구문의 끝엔 세미 콜론 `;`을 붙이는 게 좋습니다. 함수 표현식에 쓰인 세미 콜론은 함수 표현식 때문에 붙여진 게 아니라, 구문의 끝이기 때문에 붙여졌습니다.
+=======
+The answer is simple: a Function Expression is created here as `function(…) {…}` inside the assignment statement: `let sayHi = …;`. The semicolon `;` is recommended at the end of the statement, it's not a part of the function syntax.
+
+The semicolon would be there for a simpler assignment, such as `let sayHi = 5;`, and it's also there for a function assignment.
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
````
## 콜백 함수
@@ -132,13 +169,21 @@ function showCancel() {
ask("동의하십니까?", showOk, showCancel);
```
+<<<<<<< HEAD
이렇게 함수를 작성하는 방법은 실무에서 아주 유용하게 쓰입니다. 면대면으로 질문하는 것보다 위처럼 컨펌창을 띄워 질문을 던지고 답변을 받으면 간단하게 설문조사를 진행할 수 있습니다. 실제 상용 서비스에선 컨펌 창을 좀 더 멋지게 꾸미는 등의 작업이 동반되긴 하지만, 일단 여기선 그게 중요한 포인트는 아닙니다.
+=======
+In practice, such functions are quite useful. The major difference between a real-life `ask` and the example above is that real-life functions use more complex ways to interact with the user than a simple `confirm`. In the browser, such functions usually draw a nice-looking question window. But that's another story.
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
**함수 `ask`의 인수, `showOk`와 `showCancel`은 *콜백 함수* 또는 *콜백*이라고 불립니다.**
함수를 함수의 인수로 전달하고, 필요하다면 인수로 전달한 그 함수를 "나중에 호출(called back)"하는 것이 콜백 함수의 개념입니다. 위 예시에선 사용자가 "yes"라고 대답한 경우 `showOk`가 콜백이 되고, "no"라고 대답한 경우 `showCancel`가 콜백이 됩니다.
+<<<<<<< HEAD
아래와 같이 함수 표현식을 사용하면 코드 길이가 짧아집니다.
+=======
+We can use Function Expressions to write an equivalent, shorter function:
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
```js run no-beautify
function ask(question, yes, no) {
@@ -174,7 +219,11 @@ ask(
첫 번째는 문법입니다. 코드를 통해 어떤 차이가 있는지 살펴봅시다.
+<<<<<<< HEAD
- *함수 선언문:* 함수는 주요 코드 흐름 중간에 독자적인 구문 형태로 존재합니다.
+=======
+- *Function Declaration:* a function, declared as a separate statement, in the main code flow:
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
```js
// 함수 선언문
@@ -182,8 +231,13 @@ ask(
return a + b;
}
```
+<<<<<<< HEAD
- *함수 표현식:* 함수는 표현식이나 구문 구성(syntax construct) 내부에 생성됩니다. 아래 예시에선 함수가 할당 연산자 `=`를 이용해 만든 "할당 표현식" 우측에 생성되었습니다.
+=======
+- *Function Expression:* a function, created inside an expression or inside another syntax construct. Here, the function is created on the right side of the "assignment expression" `=`:
+
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
```js
// 함수 표현식
let sum = function(a, b) {
@@ -279,9 +333,15 @@ if (age < 18) {
welcome(); // \ (실행)
*/!*
// |
+<<<<<<< HEAD
function welcome() { // |
alert("안녕!"); // | 함수 선언문은 함수가 선언된 블록 내
} // | 어디에서든 유효합니다
+=======
+ function welcome() { // |
+ alert("Hello!"); // | Function Declaration is available
+ } // | everywhere in the block where it's declared
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
// |
*!*
welcome(); // / (실행)
@@ -289,8 +349,13 @@ if (age < 18) {
} else {
+<<<<<<< HEAD
function welcome() {
alert("안녕하세요!");
+=======
+ function welcome() {
+ alert("Greetings!");
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
}
}
@@ -347,8 +412,13 @@ welcome(); // 제대로 동작합니다.
```
+<<<<<<< HEAD
```smart header="함수 선언문과 함수 표현식 중 무엇을 선택해야 하나요?"
제 경험에 따르면 함수 선언문을 이용해 함수를 선언하는 걸 먼저 고려하는 게 좋습니다. 함수 선언문으로 함수를 정의하면, 함수가 선언되기 전에 호출할 수 있어서 코드 구성을 좀 더 자유롭게 할 수 있습니다.
+=======
+```smart header="When to choose Function Declaration versus Function Expression?"
+As a rule of thumb, when we need to declare a function, the first thing to consider is Function Declaration syntax. It gives more freedom in how to organize our code, because we can call such functions before they are declared.
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
함수 선언문을 사용하면 가독성도 좋아집니다. 코드에서 `let f = function(…) {…}`보다 `function f(…) {…}` 을 찾는 게 더 쉽죠. 함수 선언 방식이 더 "눈길을 사로잡습니다".
diff --git a/1-js/02-first-steps/17-arrow-functions-basics/1-rewrite-arrow/solution.md b/1-js/02-first-steps/17-arrow-functions-basics/1-rewrite-arrow/solution.md
index b944933855..d2690fa736 100644
--- a/1-js/02-first-steps/17-arrow-functions-basics/1-rewrite-arrow/solution.md
+++ b/1-js/02-first-steps/17-arrow-functions-basics/1-rewrite-arrow/solution.md
@@ -1,7 +1,7 @@
```js run
function ask(question, yes, no) {
- if (confirm(question)) yes()
+ if (confirm(question)) yes();
else no();
}
diff --git a/1-js/02-first-steps/17-arrow-functions-basics/1-rewrite-arrow/task.md b/1-js/02-first-steps/17-arrow-functions-basics/1-rewrite-arrow/task.md
index 2f98f308a9..479ba89c8e 100644
--- a/1-js/02-first-steps/17-arrow-functions-basics/1-rewrite-arrow/task.md
+++ b/1-js/02-first-steps/17-arrow-functions-basics/1-rewrite-arrow/task.md
@@ -5,7 +5,7 @@
```js run
function ask(question, yes, no) {
- if (confirm(question)) yes()
+ if (confirm(question)) yes();
else no();
}
diff --git a/1-js/02-first-steps/17-arrow-functions-basics/article.md b/1-js/02-first-steps/17-arrow-functions-basics/article.md
index bcaa1f38aa..848bee57f2 100644
--- a/1-js/02-first-steps/17-arrow-functions-basics/article.md
+++ b/1-js/02-first-steps/17-arrow-functions-basics/article.md
@@ -5,15 +5,19 @@
바로 화살표 함수(arrow function)를 사용하는 것입니다. 화살표 함수라는 이름은 문법의 생김새를 차용해 지어졌습니다.
```js
-let func = (arg1, arg2, ...argN) => expression
+let func = (arg1, arg2, ..., argN) => expression;
```
+<<<<<<< HEAD
이렇게 코드를 작성하면 인자 `arg1..argN`를 받는 함수 `func`이 만들어집니다. 함수 `func`는 화살표(`=>`) 우측의 `표현식(expression)`을 평가하고, 평가 결과를 반환합니다.
+=======
+This creates a function `func` that accepts arguments `arg1..argN`, then evaluates the `expression` on the right side with their use and returns its result.
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
아래 함수의 축약 버전이라고 할 수 있죠.
```js
-let func = function(arg1, arg2, ...argN) {
+let func = function(arg1, arg2, ..., argN) {
return expression;
};
```
@@ -33,7 +37,11 @@ let sum = function(a, b) {
alert( sum(1, 2) ); // 3
```
+<<<<<<< HEAD
보시는 바와 같이 `(a, b) => a + b`는 인수 `a`와 `b`를 받는 함수입니다. `(a, b) => a + b`는 실행되는 순간 표현식 `a + b`를 평가하고 그 결과를 반환합니다.
+=======
+As you can see, `(a, b) => a + b` means a function that accepts two arguments named `a` and `b`. Upon the execution, it evaluates the expression `a + b` and returns the result.
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
- 인수가 하나밖에 없다면 인수를 감싸는 괄호를 생략할 수 있습니다. 괄호를 생략하면 코드 길이를 더 줄일 수 있습니다.
@@ -48,7 +56,11 @@ alert( sum(1, 2) ); // 3
alert( double(3) ); // 6
```
+<<<<<<< HEAD
- 인수가 하나도 없을 땐 괄호를 비워놓으면 됩니다. 다만, 이 때 괄호는 생략할 수 없습니다.
+=======
+- If there are no arguments, parentheses are empty, but they must be present:
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
```js run
let sayHi = () => alert("안녕하세요!");
@@ -64,8 +76,13 @@ alert( sum(1, 2) ); // 3
let age = prompt("나이를 알려주세요.", 18);
let welcome = (age < 18) ?
+<<<<<<< HEAD
() => alert('안녕') :
() => alert("안녕하세요!");
+=======
+ () => alert('Hello!') :
+ () => alert("Greetings!");
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
welcome();
```
@@ -76,9 +93,15 @@ welcome();
## 본문이 여러 줄인 화살표 함수
+<<<<<<< HEAD
위에서 소개해 드린 화살표 함수들은 `=>` 왼쪽에 있는 인수를 이용해 `=>` 오른쪽에 있는 표현식을 평가하는 함수들이었습니다.
그런데 평가해야 할 표현식이나 구문이 여러 개인 함수가 있을 수도 있습니다. 이 경우 역시 화살표 함수 문법을 사용해 함수를 만들 수 있습니다. 다만, 이때는 중괄호 안에 평가해야 할 코드를 넣어주어야 합니다. 그리고 `return` 지시자를 사용해 명시적으로 결괏값을 반환해 주어야 합니다.
+=======
+The arrow functions that we've seen so far were very simple. They took arguments from the left of `=>`, evaluated and returned the right-side expression with them.
+
+Sometimes we need a more complex function, with multiple expressions and statements. In that case, we can enclose them in curly braces. The major difference is that curly braces require a `return` within them to return a value (just like a regular function does).
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
아래와 같이 말이죠.
@@ -86,7 +109,11 @@ welcome();
let sum = (a, b) => { // 중괄호는 본문 여러 줄로 구성되어 있음을 알려줍니다.
let result = a + b;
*!*
+<<<<<<< HEAD
return result; // 중괄호를 사용했다면, return 지시자로 결괏값을 반환해주어야 합니다.
+=======
+ return result; // if we use curly braces, then we need an explicit "return"
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
*/!*
};
@@ -105,7 +132,14 @@ alert( sum(1, 2) ); // 3
## 요약
+<<<<<<< HEAD
화살표 함수는 본문이 한 줄인 함수를 작성할 때 유용합니다. 본문이 한 줄이 아니라면 다른 방법으로 화살표 함수를 작성해야 합니다.
1. 중괄호 없이 작성: `(...args) => expression` -- 화살표 오른쪽에 표현식을 둡니다. 함수는 이 표현식을 평가하고, 평가 결과를 반환합니다.
2. 중괄호와 함께 작성: `(...args) => { body }` -- 본문이 여러 줄로 구성되었다면 중괄호를 사용해야 합니다. 다만, 이 경우는 반드시 `return` 지시자를 사용해 반환 값을 명기해 주어야 합니다.
+=======
+Arrow functions are handy for simple actions, especially for one-liners. They come in two flavors:
+
+1. Without curly braces: `(...args) => expression` -- the right side is an expression: the function evaluates it and returns the result. Parentheses can be omitted, if there's only a single argument, e.g. `n => n*2`.
+2. With curly braces: `(...args) => { body }` -- brackets allow us to write multiple statements inside the function, but we need an explicit `return` to return something.
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
diff --git a/1-js/02-first-steps/18-javascript-specials/article.md b/1-js/02-first-steps/18-javascript-specials/article.md
index 915fdf1513..a116b17388 100644
--- a/1-js/02-first-steps/18-javascript-specials/article.md
+++ b/1-js/02-first-steps/18-javascript-specials/article.md
@@ -55,7 +55,11 @@ for(;;) {
`'use strict'`는 스크립트 최상단이나 함수 본문 최상단에 있어야 합니다.
+<<<<<<< HEAD
`'use strict'`가 없어도 코드는 정상적으로 동작합니다. 다만, 모던한 방식이 아닌 옛날 방식으로 동작하죠. '하위 호환성'을 지키면서 말이죠. 될 수 있으면 모던한 방식을 사용하는 걸 추천해 드립니다.
+=======
+Without `"use strict"`, everything still works, but some features behave in the old-fashioned, "compatible" way. We'd generally prefer the modern behavior.
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
참고로, 추후에 배우게 될 클래스와 같은 몇몇 모던 기능은 엄격 모드를 자동으로 활성화합니다.
@@ -103,6 +107,7 @@ typeof function(){} == "function" // 함수는 특별하게 취급됩니다.
호스트 환경이 브라우저인 경우, 다음과 같은 UI 함수를 이용해 사용자와 상호작용할 수 있습니다.
+<<<<<<< HEAD
[`prompt(question, [default])`](mdn:api/Window/prompt)
: 프롬프트 창에 매개변수로 받은 `question`을 넣어 사용자에게 보여줍니다. '확인' 버튼을 눌렀을 땐 사용자가 입력한 값을 반환해주고, '취소' 버튼을 눌렀을 땐 `null`을 반환합니다.
@@ -111,6 +116,16 @@ typeof function(){} == "function" // 함수는 특별하게 취급됩니다.
[`alert(message)`](mdn:api/Window/alert)
: `message`가 담긴 얼럿 창을 보여줍니다.
+=======
+[`prompt(question, [default])`](https://developer.mozilla.org/en-US/docs/Web/API/Window/prompt)
+: Ask a `question`, and return either what the visitor entered or `null` if they clicked "cancel".
+
+[`confirm(question)`](https://developer.mozilla.org/en-US/docs/Web/API/Window/confirm)
+: Ask a `question` and suggest to choose between Ok and Cancel. The choice is returned as `true/false`.
+
+[`alert(message)`](https://developer.mozilla.org/en-US/docs/Web/API/Window/alert)
+: Output a `message`.
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
세 함수는 모두 *모달* 창을 띄워주는데, 모달 창이 닫히기 전까지 코드 실행이 중지됩니다. 사용자는 모달 창 외에 페이지에 있는 그 무엇과도 상호작용할 수 없습니다.
@@ -143,8 +158,13 @@ alert( "차 주문 여부: " + isTeaWanted ); // true
할당 연산자
: `a = b` 형태의 할당 연산자와 `a *= 2` 형태의 복합 할당 연산자가 있습니다.
+<<<<<<< HEAD
비트 연산자
: 비트 연산자는 인수를 32비트 정수로 변환하여 이진 연산을 수행합니다. 자세한 내용은 [docs](mdn:/JavaScript/Reference/Operators/Bitwise_Operators)에서 볼 수 있습니다.
+=======
+Bitwise
+: Bitwise operators work with 32-bit integers at the lowest, bit-level: see the [docs](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators#bitwise_operators) when they are needed.
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
조건부 연산자
: 조건부 연산자는 자바스크립트 연산자 중 유일하게 매개변수가 3개인 연산자입니다. `cond ? resultA : resultB`와 같은 형태로 사용하고, `cond`가 truthy면 `resultA`를, 아니면 `resultB`를 반환합니다.
@@ -256,7 +276,11 @@ switch (age) {
3. 화살표 함수:
```js
+<<<<<<< HEAD
// 화살표(=>) 우측엔 표현식이 있음
+=======
+ // expression on the right side
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
let sum = (a, b) => a + b;
// 중괄호{ ... }를 사용하면 본문에 여러 줄의 코드를 작성할 수 있음. return문이 꼭 있어야 함.
@@ -273,9 +297,15 @@ switch (age) {
```
+<<<<<<< HEAD
- 함수는 지역 변수를 가질 수 있습니다. 지역 변수는 함수의 본문에 선언된 변수로, 함수 내부에서만 접근할 수 있습니다.
- 매개변수에 기본값을 설정할 수 있습니다. 문법은 다음과 같습니다. `function sum(a = 1, b = 2) {...}`
- 함수는 항상 무언가를 반환합니다. `return`문이 없는 경우는 `undefined`를 반환합니다.
+=======
+- Functions may have local variables: those declared inside its body or its parameter list. Such variables are only visible inside the function.
+- Parameters can have default values: `function sum(a = 1, b = 2) {...}`.
+- Functions always return something. If there's no `return` statement, then the result is `undefined`.
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
자세한 내용은 253
이상이거나 -253
이하일 수 없다는 제약 때문에 BigInt라는 새로운 자료형이 만들어졌습니다. BigInt는 아주 특별한 경우에만 사용되므로, 별도의 챕터 (253-1)
or be less than -(253-1)
, as we mentioned earlier in the chapter func`string`
같이 첫 번째 백틱 바로 앞에 함수 이름(`func`)을 써주면, 이 함수는 백틱 안의 문자열 조각이나 표현식 평가 결과를 인수로 받아 자동으로 호출됩니다. 이런 기능을 '태그드 템플릿(tagged template)'이라 부르는데, 태그드 템플릿을 사용하면 사용자 지정 템플릿에 맞는 문자열을 쉽게 만들 수 있습니다. 태그드 템플릿과 템플릿 함수에 대한 자세한 내용은 MDN [문서](mdn:/JavaScript/Reference/Template_literals#Tagged_templates)에서 확인해보세요. 참고로 이 기능은 자주 사용되진 않습니다.
+=======
+Single and double quotes come from ancient times of language creation, when the need for multiline strings was not taken into account. Backticks appeared much later and thus are more versatile.
+
+Backticks also allow us to specify a "template function" before the first backtick. The syntax is: func`string`
. The function `func` is called automatically, receives the string and embedded expressions and can process them. This feature is called "tagged templates", it's rarely seen, but you can read about it in the MDN: [Template literals](mdn:/JavaScript/Reference/Template_literals#Tagged_templates).
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
## 특수 기호
@@ -59,10 +65,17 @@ let guestList = "손님: // Error: Invalid or unexpected token
```js run
let guestList = "손님:\n * John\n * Pete\n * Mary";
+<<<<<<< HEAD
alert(guestList); // 손님 리스트를 여러 줄에 걸쳐 작성함
```
따옴표를 이용해 만든 여러 줄 문자열과 백틱을 이용해 만든 여러 줄 문자열은 표현 방식만 다를 뿐 차이가 없습니다.
+=======
+alert(guestList); // a multiline list of guests, same as above
+```
+
+As a simpler example, these two lines are equal, just written differently:
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
```js run
let str1 = "Hello\nWorld"; // '줄 바꿈 기호'를 사용해 두 줄짜리 문자열을 만듦
@@ -74,12 +87,17 @@ World`;
alert(str1 == str2); // true
```
+<<<<<<< HEAD
자바스크립트엔 줄 바꿈 문자를 비롯한 다양한 '특수' 문자들이 있습니다.
특수 문자 목록:
+=======
+There are other, less common special characters:
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
| 특수 문자 | 설명 |
|-----------|-------------|
+<<<<<<< HEAD
|`\n`|줄 바꿈|
|`\r`|캐리지 리턴(carriage return). Windows에선 캐리지 리턴과 줄 바꿈 특수 문자를 조합(`\r\n`)해 줄을 바꿉니다. 캐리지 리턴을 단독으론 사용하는 경우는 없습니다. |
|`\'`, `\"`|따옴표|
@@ -101,6 +119,24 @@ alert( "\u{1F60D}" ); // 😍, 웃는 얼굴 기호(긴 유니코드)
모든 특수 문자는 '이스케이프 문자(escape character)'라고도 불리는 역슬래시 (backslash character) `\`로 시작합니다.
역슬래시는 문자열 내에 따옴표를 넣을 때도 사용할 수 있습니다.
+=======
+|`\n`|New line|
+|`\r`|In Windows text files a combination of two characters `\r\n` represents a new break, while on non-Windows OS it's just `\n`. That's for historical reasons, most Windows software also understands `\n`. |
+|`\'`, `\"`, \\`
|Quotes|
+|`\\`|Backslash|
+|`\t`|Tab|
+|`\b`, `\f`, `\v`| Backspace, Form Feed, Vertical Tab -- mentioned for completeness, coming from old times, not used nowadays (you can forget them right now). |
+
+As you can see, all special characters start with a backslash character `\`. It is also called an "escape character".
+
+Because it's so special, if we need to show an actual backslash `\` within the string, we need to double it:
+
+```js run
+alert( `The backslash: \\` ); // The backslash: \
+```
+
+So-called "escaped" quotes `\'`, `\"`, \\`
are used to insert a quote into the same-quoted string.
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
예시:
@@ -110,12 +146,17 @@ alert( 'I*!*\'*/!*m the Walrus!' ); // *!*I'm*/!* the Walrus!
위 예시에서 살펴본 바와 같이 문자열 내의 따옴표엔 `\`를 꼭 붙여줘야 합니다. 이렇게 하지 않으면 자바스크립트는 해당 따옴표가 문자열을 닫는 용도로 사용된 것이라 해석하기 때문입니다.
+<<<<<<< HEAD
이스케이프 문자는 문자열을 감쌀 때 사용한 따옴표와 동일한 따옴표에만 붙여주면 됩니다. 문자열 내에서 좀 더 우아하게 따옴표를 사용하려면 아래와 같이 따옴표 대신 백틱으로 문자열을 감싸주면 됩니다.
+=======
+Of course, only the quotes that are the same as the enclosing ones need to be escaped. So, as a more elegant solution, we could switch to double quotes or backticks instead:
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
```js run
-alert( `I'm the Walrus!` ); // I'm the Walrus!
+alert( "I'm the Walrus!" ); // I'm the Walrus!
```
+<<<<<<< HEAD
역슬래시 `\`는 문자열을 정확하게 읽기 위한 용도로 만들어졌으므로 `\`는 제 역할이 끝나면 사라집니다. 메모리에 저장되는 문자열엔 `\`가 없습니다. 앞선 예시들을 실행했을 때 뜨는 `alert` 창을 통해 이를 확인할 수 있습니다.
그렇다면 문자열 안에 역슬래시 `\`를 보여줘야 하는 경우엔 어떻게 해야 할까요?
@@ -125,6 +166,9 @@ alert( `I'm the Walrus!` ); // I'm the Walrus!
```js run
alert( `역슬래시: \\` ); // 역슬래시: \
```
+=======
+Besides these special characters, there's also a special notation for Unicode codes `\u…`, it's rarely used and is covered in the optional chapter about [Unicode](info:unicode).
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
## 문자열의 길이
@@ -139,33 +183,55 @@ alert( `My\n`.length ); // 3
```warn header="`length`는 프로퍼티입니다."
자바스크립트 이외의 언어를 사용했던 개발자들은 `str.length`가 아닌 `str.length()`로 문자열의 길이를 알아내려고 하는 경우가 있습니다. 하지만 원하는 대로 동작하지 않습니다.
+<<<<<<< HEAD
`length`는 함수가 아니고, 숫자가 저장되는 프로퍼티라는 점에 주의하시기 바랍니다. 뒤에 괄호를 붙일 필요가 없습니다.
+=======
+Please note that `str.length` is a numeric property, not a function. There is no need to add parenthesis after it. Not `.length()`, but `.length`.
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
```
## 특정 글자에 접근하기
+<<<<<<< HEAD
문자열 내 특정 위치인 `pos`에 있는 글자에 접근하려면 `[pos]`같이 대괄호를 이용하거나 [str.charAt(pos)](mdn:js/String/charAt)라는 메서드를 호출하면 됩니다. 위치는 0부터 시작합니다.
+=======
+To get a character at position `pos`, use square brackets `[pos]` or call the method [str.at(pos)](mdn:js/String/at). The first character starts from the zero position:
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
```js run
let str = `Hello`;
// 첫 번째 글자
alert( str[0] ); // H
-alert( str.charAt(0) ); // H
+alert( str.at(0) ); // H
// 마지막 글자
alert( str[str.length - 1] ); // o
+alert( str.at(-1) );
```
+<<<<<<< HEAD
근래에는 대괄호를 이용하는 방식을 사용합니다. `charAt`은 하위 호환성을 위해 남아있는 메서드라고 생각하시면 됩니다.
두 접근 방식의 차이는 반환할 글자가 없을 때 드러납니다. 접근하려는 위치에 글자가 없는 경우 `[]`는 `undefined`를, `charAt`은 빈 문자열을 반환합니다.
+=======
+As you can see, the `.at(pos)` method has a benefit of allowing negative position. If `pos` is negative, then it's counted from the end of the string.
+
+So `.at(-1)` means the last character, and `.at(-2)` is the one before it, etc.
+
+The square brackets always return `undefined` for negative indexes, for instance:
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
```js run
let str = `Hello`;
+<<<<<<< HEAD
alert( str[1000] ); // undefined
alert( str.charAt(1000) ); // '' (빈 문자열)
+=======
+alert( str[-2] ); // undefined
+alert( str.at(-2) ); // l
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
```
`for..of`를 사용하면 문자열을 구성하는 글자를 대상으로 반복 작업을 할 수 있습니다.
@@ -214,7 +280,7 @@ alert( 'Interface'.toLowerCase() ); // interface
글자 하나의 케이스만 변경하는 것도 가능합니다.
-```js
+```js run
alert( 'Interface'[0].toLowerCase() ); // 'i'
```
@@ -239,7 +305,11 @@ alert( str.indexOf('widget') ); // -1, indexOf는 대·소문자를 따지므로
alert( str.indexOf("id") ); // 1, "id"는 첫 번째 위치에서 발견됨 (Widget에서 id)
```
+<<<<<<< HEAD
`str.indexOf(substr, pos)`의 두 번째 매개변수 `pos`는 선택적으로 사용할 수 있는데, 이를 명시하면 검색이 해당 위치부터 시작됩니다.
+=======
+The optional second parameter allows us to start searching from a given position.
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
부분 문자열 `"id"`는 위치 `1`에서 처음 등장하는데, 두 번째 인수에 `2`를 넘겨 `"id"`가 두 번째로 등장하는 위치가 어디인지 알아봅시다.
@@ -310,6 +380,7 @@ if (str.indexOf("Widget") != -1) {
}
```
+<<<<<<< HEAD
#### 비트 NOT 연산자를 사용한 기법
오래전부터 전해 오는 [비트(bitwise) NOT 연산자](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators#Bitwise_NOT) `~`를 사용한 기법 하나를 소개해드리겠습니다. 비트 NOT 연산자는 피연산자를 32비트 정수로 바꾼 후(소수부는 모두 버려짐) 모든 비트를 반전합니다.
@@ -349,6 +420,8 @@ if (~str.indexOf("Widget")) {
모던 자바스크립트에선 `.includes` 메서드(아래에서 배움)를 사용해 부분 문자열 포함 여부를 검사합니다. 이런 기법은 오래된 자바스크립트에서만 볼 수 있습니다.
+=======
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
### includes, startsWith, endsWith
비교적 근래에 나온 메서드인 [str.includes(substr, pos)](mdn:js/String/includes)는 `str`에 부분 문자열 `substr`이 있는지에 따라 `true`나 `false`를 반환합니다.
@@ -371,8 +444,13 @@ alert( "Widget".includes("id", 3) ); // false, 세 번째 위치 이후엔 "id"
메서드 [str.startsWith](mdn:js/String/startsWith)와 [str.endsWith](mdn:js/String/endsWith)는 메서드 이름 그대로 문자열 `str`이 특정 문자열로 시작하는지(start with) 여부와 특정 문자열로 끝나는지(end with) 여부를 확인할 때 사용할 수 있습니다.
```js run
+<<<<<<< HEAD
alert( "Widget".startsWith("Wid") ); // true, "Widget"은 "Wid"로 시작합니다.
alert( "Widget".endsWith("get") ); // true, "Widget"은 "get"으로 끝납니다.
+=======
+alert( "*!*Wid*/!*get".startsWith("Wid") ); // true, "Widget" starts with "Wid"
+alert( "Wid*!*get*/!*".endsWith("get") ); // true, "Widget" ends with "get"
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
```
## 부분 문자열 추출하기
@@ -407,9 +485,15 @@ alert( "Widget".endsWith("get") ); // true, "Widget"은 "get"으로 끝납니다
```
`str.substring(start [, end])`
+<<<<<<< HEAD
: `start`와 `end` *사이*에 있는 문자열을 반환합니다.
`substring`은 `slice`와 아주 유사하지만 `start`가 `end`보다 커도 괜찮다는 데 차이가 있습니다.
+=======
+: Returns the part of the string *between* `start` and `end` (not including `end`).
+
+ This is almost the same as `slice`, but it allows `start` to be greater than `end` (in this case it simply swaps `start` and `end` values).
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
예시:
@@ -445,18 +529,36 @@ alert( "Widget".endsWith("get") ); // true, "Widget"은 "get"으로 끝납니다
alert( str.substr(-4, 2) ); // gi, 끝에서 네 번째 위치부터 글자 두 개
```
+<<<<<<< HEAD
부분 문자열 추출과 관련된 메서드를 요약해 봅시다.
+=======
+ This method resides in the [Annex B](https://tc39.es/ecma262/#sec-string.prototype.substr) of the language specification. It means that only browser-hosted Javascript engines should support it, and it's not recommended to use it. In practice, it's supported everywhere.
+
+Let's recap these methods to avoid any confusion:
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
| 메서드 | 추출할 부분 문자열 | 음수 허용 여부(인수)|
|--------|-----------|-----------|
+<<<<<<< HEAD
| `slice(start, end)` | `start`부터 `end`까지(`end`는 미포함) | 음수 허용 |
| `substring(start, end)` | `start`와 `end` 사이 | 음수는 `0`으로 취급함 |
| `substr(start, length)` | `start`부터 `length`개의 글자 | 음수 허용 |
+=======
+| `slice(start, end)` | from `start` to `end` (not including `end`) | allows negatives |
+| `substring(start, end)` | between `start` and `end` (not including `end`)| negative values mean `0` |
+| `substr(start, length)` | from `start` get `length` characters | allows negative `start` |
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
```smart header="어떤 메서드를 선택해야 하나요?"
모두 사용해도 괜찮습니다. 그런데 `substr`에는 단점이 하나 있습니다. `substr`는 코어 자바스크립트 명세서(ECMA-262 - 옮긴이)가 아닌, 구식 스크립트에 대응하기 위해 남겨 둔 브라우저 전용 기능들을 명시해 놓은 부록 B(Annex B)에 정의되어있습니다. 거의 모든 곳에서 이 메서드가 동작하긴 하지만 브라우저 이외의 호스트 환경에서는 제대로 동작하지 않을 수 있습니다.
+<<<<<<< HEAD
남은 두 메서드 중 `slice`는 음수 인수를 허용한다는 측면에서 `substring`보다 좀 더 유연합니다. 메서드 이름도 더 짧죠. 따라서 세 메서드 중 `slice`만 외워놓고 사용해도 충분할 것 같습니다.
+=======
+Of the other two variants, `slice` is a little bit more flexible, it allows negative arguments and shorter to write.
+
+So, for practical use it's enough to remember only `slice`.
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
```
## 문자열 비교하기
@@ -479,6 +581,7 @@ alert( "Widget".endsWith("get") ); // true, "Widget"은 "get"으로 끝납니다
이런 예외사항 때문에 이름순으로 국가를 나열할 때 예상치 못한 결과가 나올 수 있습니다. 사람들은 `Österreich`가 `Zealand`보다 앞서 나올 것이라 예상하는데 그렇지 않죠.
+<<<<<<< HEAD
자바스크립트 내부에서 문자열이 어떻게 표시되는지 상기하며 원인을 알아봅시다.
모든 문자열은 [UTF-16](https://en.wikipedia.org/wiki/UTF-16)을 사용해 인코딩되는데, UTF-16에선 모든 글자가 숫자 형식의 코드와 매칭됩니다. 코드로 글자를 얻거나 글자에서 연관 코드를 알아낼 수 있는 메서드는 다음과 같습니다.
@@ -489,7 +592,20 @@ alert( "Widget".endsWith("get") ); // true, "Widget"은 "get"으로 끝납니다
```js run
// 글자는 같지만 케이스는 다르므로 반환되는 코드가 다릅니다.
alert( "z".codePointAt(0) ); // 122
+=======
+To understand what happens, we should be aware that strings in Javascript are encoded using [UTF-16](https://en.wikipedia.org/wiki/UTF-16). That is: each character has a corresponding numeric code.
+
+There are special methods that allow to get the character for the code and back:
+
+`str.codePointAt(pos)`
+: Returns a decimal number representing the code for the character at position `pos`:
+
+ ```js run
+ // different case letters have different codes
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
alert( "Z".codePointAt(0) ); // 90
+ alert( "z".codePointAt(0) ); // 122
+ alert( "z".codePointAt(0).toString(16) ); // 7a (if we need a hexadecimal value)
```
`String.fromCodePoint(code)`
@@ -497,6 +613,7 @@ alert( "Widget".endsWith("get") ); // true, "Widget"은 "get"으로 끝납니다
```js run
alert( String.fromCodePoint(90) ); // Z
+<<<<<<< HEAD
```
`\u` 뒤에 특정 글자에 대응하는 16진수 코드를 붙이는 방식으로도 원하는 글자를 만들 수 있습니다.
@@ -504,6 +621,9 @@ alert( "Widget".endsWith("get") ); // true, "Widget"은 "get"으로 끝납니다
```js run
// 90을 16진수로 변환하면 5a입니다.
alert( '\u005a' ); // Z
+=======
+ alert( String.fromCodePoint(0x5a) ); // Z (we can also use a hex value as an argument)
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
```
이제 이 배경지식을 가지고 코드 `65`와 `220` 사이(라틴계열 알파벳과 기타 글자들이 여기에 포함됨)에 대응하는 글자들을 출력해봅시다.
@@ -515,6 +635,7 @@ for (let i = 65; i <= 220; i++) {
str += String.fromCodePoint(i);
}
alert( str );
+// Output:
// ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
// ¡¢£¤¥¦§¨©ª«¬®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜ
```
@@ -525,16 +646,27 @@ alert( str );
글자는 글자에 대응하는 숫자 형식의 코드를 기준으로 비교됩니다. 코드가 크면 대응하는 글자 역시 크다고 취급되죠. 따라서 `a`(코드:97)는 `Z`(코드:90) 보다 크다는 결론이 도출됩니다.
+<<<<<<< HEAD
- 알파벳 소문자의 코드는 대문자의 코드보다 크므로 소문자는 대문자 뒤에 옵니다.
- `Ö` 같은 글자는 일반 알파벳과 멀리 떨어져 있습니다. `Ö`의 코드는 알파벳 소문자의 코드보다 훨씬 큽니다.
### 문자열 제대로 비교하기
+=======
+- All lowercase letters go after uppercase letters because their codes are greater.
+- Some letters like `Ö` stand apart from the main alphabet. Here, its code is greater than anything from `a` to `z`.
+
+### Correct comparisons [#correct-comparisons]
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
언어마다 문자 체계가 다르기 때문에 문자열을 '제대로' 비교하는 알고리즘을 만드는 건 생각보다 간단하지 않습니다.
문자열을 비교하려면 일단 페이지에서 어떤 언어를 사용하고 있는지 브라우저가 알아야 합니다.
+<<<<<<< HEAD
다행히도 모던 브라우저 대부분이 국제화 관련 표준인 [ECMA-402](http://www.ecma-international.org/ecma-402/1.0/ECMA-402.pdf)를 지원합니다(IE10은 아쉽게도 [Intl.js](https://github.com/andyearnshaw/Intl.js/) 라이브러리를 사용해야 합니다).
+=======
+Luckily, modern browsers support the internationalization standard [ECMA-402](https://www.ecma-international.org/publications-and-standards/standards/ecma-402/).
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
ECMA-402엔 언어가 다를 때 적용할 수 있는 문자열 비교 규칙과 이를 준수하는 메서드가 정의되어있습니다.
@@ -552,6 +684,7 @@ alert( 'Österreich'.localeCompare('Zealand') ); // -1
`localeCompare`엔 선택 인수 두 개를 더 전달할 수 있습니다. 기준이 되는 언어를 지정(아무것도 지정하지 않았으면 호스트 환경의 언어가 기준 언어가 됨)해주는 인수와 대·소문자를 구분할지나 `"a"`와 `"á"`를 다르게 취급할지에 대한 것을 설정해주는 인수가 더 있죠. 자세한 사항은 관련 [페이지](mdn:js/String/localeCompare)에서 확인해 보시기 바랍니다.
+<<<<<<< HEAD
## 문자열 심화
```warn header="심화 학습"
@@ -669,6 +802,17 @@ alert( "S\u0307\u0323".normalize() == "\u1e68" ); // true
- 소문자로 바꾸려면 `toLowerCase`, 대문자로 바꾸려면 `toUpperCase`를 사용하세요.
- `indexOf`를 사용하면 부분 문자열의 위치를 얻을 수 있습니다. 부분 문자열 여부만 알고 싶다면 `includes/startsWith/endsWith`를 사용하면 됩니다.
- 특정 언어에 적합한 비교 기준 사용해 문자열을 비교하려면 `localeCompare`를 사용하세요. 이 메서드를 사용하지 않으면 글자 코드를 기준으로 문자열이 비교됩니다.
+=======
+## Summary
+
+- There are 3 types of quotes. Backticks allow a string to span multiple lines and embed expressions `${…}`.
+- We can use special characters, such as a line break `\n`.
+- To get a character, use: `[]` or `at` method.
+- To get a substring, use: `slice` or `substring`.
+- To lowercase/uppercase a string, use: `toLowerCase/toUpperCase`.
+- To look for a substring, use: `indexOf`, or `includes/startsWith/endsWith` for simple checks.
+- To compare strings according to the language, use: `localeCompare`, otherwise they are compared by character codes.
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
이외에도 문자열에 쓸 수 있는 유용한 메서드 몇 가지가 있습니다.
@@ -676,4 +820,10 @@ alert( "S\u0307\u0323".normalize() == "\u1e68" ); // true
- `str.repeat(n)` -- 문자열을 `n`번 반복합니다.
- 이 외의 메서드는 [MDN 문서](mdn:js/String)에서 확인해보시기 바랍니다.
+<<<<<<< HEAD
정규 표현식을 사용해 문자열을 찾거나 교체해주는 메서드도 여러 개 있는데 이는 아주 큰 주제이기 때문에 별도의 섹션 alert
will trigger immediately.
+
+## FinalizationRegistry
+
+Now it is time to talk about finalizers. Before we move on, let's clarify the terminology:
+
+**Cleanup callback (finalizer)** - is a function that is executed, when an object, registered in the `FinalizationRegistry`, is deleted from memory by the garbage collector.
+
+Its purpose - is to provide the ability to perform additional operations, related to the object, after it has been finally deleted from memory.
+
+**Registry** (or `FinalizationRegistry`) - is a special object in JavaScript that manages the registration and unregistration of objects and their cleanup callbacks.
+
+This mechanism allows registering an object to track and associate a cleanup callback with it.
+Essentially it is a structure that stores information about registered objects and their cleanup callbacks, and then automatically invokes those callbacks when the objects are deleted from memory.
+
+To create an instance of the `FinalizationRegistry`, it needs to call its constructor, which takes a single argument - the cleanup callback (finalizer).
+
+Syntax:
+
+```js
+function cleanupCallback(heldValue) {
+ // cleanup callback code
+}
+
+const registry = new FinalizationRegistry(cleanupCallback);
+```
+
+Here:
+
+- `cleanupCallback` - a cleanup callback that will be automatically called when a registered object is deleted from memory.
+- `heldValue` - the value that is passed as an argument to the cleanup callback. If `heldValue` is an object, the registry keeps a strong reference to it.
+- `registry` - an instance of `FinalizationRegistry`.
+
+`FinalizationRegistry` methods:
+
+- `register(target, heldValue [, unregisterToken])` - used to register objects in the registry.
+
+ `target` - the object being registered for tracking. If the `target` is garbage collected, the cleanup callback will be called with `heldValue` as its argument.
+
+ Optional `unregisterToken` – an unregistration token. It can be passed to unregister an object before the garbage collector deletes it. Typically, the `target` object is used as `unregisterToken`, which is the standard practice.
+- `unregister(unregisterToken)` - the `unregister` method is used to unregister an object from the registry. It takes one argument - `unregisterToken` (the unregister token that was obtained when registering the object).
+
+Now let's move on to a simple example. Let's use the already-known `user` object and create an instance of `FinalizationRegistry`:
+
+```js
+let user = { name: "John" };
+
+const registry = new FinalizationRegistry((heldValue) => {
+ console.log(`${heldValue} has been collected by the garbage collector.`);
+});
+```
+
+Then, we will register the object, that requires a cleanup callback by calling the `register` method:
+
+```js
+registry.register(user, user.name);
+```
+
+The registry does not keep a strong reference to the object being registered, as this would defeat its purpose. If the registry kept a strong reference, then the object would never be garbage collected.
+
+If the object is deleted by the garbage collector, our cleanup callback may be called at some point in the future, with the `heldValue` passed to it:
+
+```js
+// When the user object is deleted by the garbage collector, the following message will be printed in the console:
+"John has been collected by the garbage collector."
+```
+
+There are also situations where, even in implementations that use a cleanup callback, there is a chance that it will not be called.
+
+For example:
+- When the program fully terminates its operation (for example, when closing a tab in a browser).
+- When the `FinalizationRegistry` instance itself is no longer reachable to JavaScript code.
+ If the object that creates the `FinalizationRegistry` instance goes out of scope or is deleted, the cleanup callbacks registered in that registry might also not be invoked.
+
+## Caching with FinalizationRegistry
+
+Returning to our *weak* cache example, we can notice the following:
+- Even though the values wrapped in the `WeakRef` have been collected by the garbage collector, there is still an issue of "memory leakage" in the form of the remaining keys, whose values have been collected by the garbage collector.
+
+Here is an improved caching example using `FinalizationRegistry`:
+
+```js
+function fetchImg() {
+ // abstract function for downloading images...
+}
+
+function weakRefCache(fetchImg) {
+ const imgCache = new Map();
+
+ *!*
+ const registry = new FinalizationRegistry((imgName) => { // (1)
+ const cachedImg = imgCache.get(imgName);
+ if (cachedImg && !cachedImg.deref()) imgCache.delete(imgName);
+ });
+ */!*
+
+ return (imgName) => {
+ const cachedImg = imgCache.get(imgName);
+
+ if (cachedImg?.deref()) {
+ return cachedImg?.deref();
+ }
+
+ const newImg = fetchImg(imgName);
+ imgCache.set(imgName, new WeakRef(newImg));
+ *!*
+ registry.register(newImg, imgName); // (2)
+ */!*
+
+ return newImg;
+ };
+}
+
+const getCachedImg = weakRefCache(fetchImg);
+```
+
+1. To manage the cleanup of "dead" cache entries, when the associated `WeakRef` objects are collected by the garbage collector, we create a `FinalizationRegistry` cleanup registry.
+
+ The important point here is, that in the cleanup callback, it should be checked, if the entry was deleted by the garbage collector and not re-added, in order not to delete a "live" entry.
+2. Once the new value (image) is downloaded and put into the cache, we register it in the finalizer registry to track the `WeakRef` object.
+
+This implementation contains only actual or "live" key/value pairs.
+In this case, each `WeakRef` object is registered in the `FinalizationRegistry`.
+And after the objects are cleaned up by the garbage collector, the cleanup callback will delete all `undefined` values.
+
+Here is a visual representation of the updated code:
+
+
+
+A key aspect of the updated implementation is that finalizers allow parallel processes to be created between the "main" program and cleanup callbacks.
+In the context of JavaScript, the "main" program - is our JavaScript-code, that runs and executes in our application or web page.
+
+Hence, from the moment an object is marked for deletion by the garbage collector, and to the actual execution of the cleanup callback, there may be a certain time gap.
+It is important to understand that during this time gap, the main program can make any changes to the object or even bring it back to memory.
+
+That's why, in the cleanup callback, we must check to see if an entry has been added back to the cache by the main program to avoid deleting "live" entries.
+Similarly, when searching for a key in the cache, there is a chance that the value has been deleted by the garbage collector, but the cleanup callback has not been executed yet.
+
+Such situations require special attention if you are working with `FinalizationRegistry`.
+
+## Using WeakRef and FinalizationRegistry in practice
+
+Moving from theory to practice, imagine a real-life scenario, where a user synchronizes their photos on a mobile device with some cloud service
+(such as [iCloud](https://en.wikipedia.org/wiki/ICloud) or [Google Photos](https://en.wikipedia.org/wiki/Google_Photos)),
+and wants to view them from other devices. In addition to the basic functionality of viewing photos, such services offer a lot of additional features, for example:
+
+- Photo editing and video effects.
+- Creating "memories" and albums.
+- Video montage from a series of photos.
+- ...and much more.
+
+Here, as an example, we will use a fairly primitive implementation of such a service.
+The main point - is to show a possible scenario of using `WeakRef` and `FinalizationRegistry` together in real life.
+
+Here is what it looks like:
+
+
+
+weakRefCache
function checks whether the required image is in the cache.
+If not, it downloads it from the cloud and puts it in the cache for further use.
+This happens for each selected image:
+Messages:
+ +Logger:
+Logger:
'; +}; + +const downloadCollage = () => { + const date = new Date(); + const fileName = `Collage-${date.getDay()}-${date.getMonth()}-${date.getFullYear()}.png`; + const img = canvasEl.toDataURL("image/png"); + const link = document.createElement("a"); + link.download = fileName; + link.href = img; + link.click(); + link.remove(); +}; + +const changeLayout = ({ target }) => { + state.currentLayout = JSON.parse(target.value); +}; + +// Listeners. +selectEl.addEventListener("change", changeLayout); +createCollageBtn.addEventListener("click", createCollage); +startOverBtn.addEventListener("click", startOver); +downloadBtn.addEventListener("click", downloadCollage); diff --git a/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry.view/utils.js b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry.view/utils.js new file mode 100644 index 0000000000..f0140c116a --- /dev/null +++ b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry.view/utils.js @@ -0,0 +1,321 @@ +const loggerContainerEl = document.querySelector(".loggerContainer"); + +export const images = [ + { + img: "https://images.unsplash.com/photo-1471357674240-e1a485acb3e1", + }, + { + img: "https://images.unsplash.com/photo-1589118949245-7d38baf380d6", + }, + { + img: "https://images.unsplash.com/photo-1527631746610-bca00a040d60", + }, + { + img: "https://images.unsplash.com/photo-1500835556837-99ac94a94552", + }, + { + img: "https://images.unsplash.com/photo-1503220317375-aaad61436b1b", + }, + { + img: "https://images.unsplash.com/photo-1501785888041-af3ef285b470", + }, + { + img: "https://images.unsplash.com/photo-1528543606781-2f6e6857f318", + }, + { + img: "https://images.unsplash.com/photo-1523906834658-6e24ef2386f9", + }, + { + img: "https://images.unsplash.com/photo-1539635278303-d4002c07eae3", + }, + { + img: "https://images.unsplash.com/photo-1533105079780-92b9be482077", + }, + { + img: "https://images.unsplash.com/photo-1516483638261-f4dbaf036963", + }, + { + img: "https://images.unsplash.com/photo-1502791451862-7bd8c1df43a7", + }, + { + img: "https://plus.unsplash.com/premium_photo-1663047367140-91adf819d007", + }, + { + img: "https://images.unsplash.com/photo-1506197603052-3cc9c3a201bd", + }, + { + img: "https://images.unsplash.com/photo-1517760444937-f6397edcbbcd", + }, + { + img: "https://images.unsplash.com/photo-1518684079-3c830dcef090", + }, + { + img: "https://images.unsplash.com/photo-1505832018823-50331d70d237", + }, + { + img: "https://images.unsplash.com/photo-1524850011238-e3d235c7d4c9", + }, + { + img: "https://plus.unsplash.com/premium_photo-1661277758451-b5053309eea1", + }, + { + img: "https://images.unsplash.com/photo-1541410965313-d53b3c16ef17", + }, + { + img: "https://images.unsplash.com/photo-1528702748617-c64d49f918af", + }, + { + img: "https://images.unsplash.com/photo-1502003148287-a82ef80a6abc", + }, + { + img: "https://plus.unsplash.com/premium_photo-1661281272544-5204ea3a481a", + }, + { + img: "https://images.unsplash.com/photo-1503457574462-bd27054394c1", + }, + { + img: "https://images.unsplash.com/photo-1499363536502-87642509e31b", + }, + { + img: "https://images.unsplash.com/photo-1551918120-9739cb430c6d", + }, + { + img: "https://plus.unsplash.com/premium_photo-1661382219642-43e54f7e81d7", + }, + { + img: "https://images.unsplash.com/photo-1497262693247-aa258f96c4f5", + }, + { + img: "https://images.unsplash.com/photo-1525254134158-4fd5fdd45793", + }, + { + img: "https://plus.unsplash.com/premium_photo-1661274025419-4c54107d5c48", + }, + { + img: "https://images.unsplash.com/photo-1553697388-94e804e2f0f6", + }, + { + img: "https://images.unsplash.com/photo-1574260031597-bcd9eb192b4f", + }, + { + img: "https://images.unsplash.com/photo-1536323760109-ca8c07450053", + }, + { + img: "https://images.unsplash.com/photo-1527824404775-dce343118ebc", + }, + { + img: "https://images.unsplash.com/photo-1612278675615-7b093b07772d", + }, + { + img: "https://images.unsplash.com/photo-1522010675502-c7b3888985f6", + }, + { + img: "https://images.unsplash.com/photo-1501555088652-021faa106b9b", + }, + { + img: "https://plus.unsplash.com/premium_photo-1669223469435-27e091439169", + }, + { + img: "https://images.unsplash.com/photo-1506012787146-f92b2d7d6d96", + }, + { + img: "https://images.unsplash.com/photo-1511739001486-6bfe10ce785f", + }, + { + img: "https://images.unsplash.com/photo-1553342385-111fd6bc6ab3", + }, + { + img: "https://images.unsplash.com/photo-1516546453174-5e1098a4b4af", + }, + { + img: "https://images.unsplash.com/photo-1527142879-95b61a0b8226", + }, + { + img: "https://images.unsplash.com/photo-1520466809213-7b9a56adcd45", + }, + { + img: "https://images.unsplash.com/photo-1516939884455-1445c8652f83", + }, + { + img: "https://images.unsplash.com/photo-1545389336-cf090694435e", + }, + { + img: "https://plus.unsplash.com/premium_photo-1669223469455-b7b734c838f4", + }, + { + img: "https://images.unsplash.com/photo-1454391304352-2bf4678b1a7a", + }, + { + img: "https://images.unsplash.com/photo-1433838552652-f9a46b332c40", + }, + { + img: "https://images.unsplash.com/photo-1506125840744-167167210587", + }, + { + img: "https://images.unsplash.com/photo-1522199873717-bc67b1a5e32b", + }, + { + img: "https://images.unsplash.com/photo-1495904786722-d2b5a19a8535", + }, + { + img: "https://images.unsplash.com/photo-1614094082869-cd4e4b2905c7", + }, + { + img: "https://images.unsplash.com/photo-1474755032398-4b0ed3b2ae5c", + }, + { + img: "https://images.unsplash.com/photo-1501554728187-ce583db33af7", + }, + { + img: "https://images.unsplash.com/photo-1515859005217-8a1f08870f59", + }, + { + img: "https://images.unsplash.com/photo-1531141445733-14c2eb7d4c1f", + }, + { + img: "https://images.unsplash.com/photo-1500259783852-0ca9ce8a64dc", + }, + { + img: "https://images.unsplash.com/photo-1510662145379-13537db782dc", + }, + { + img: "https://images.unsplash.com/photo-1573790387438-4da905039392", + }, + { + img: "https://images.unsplash.com/photo-1512757776214-26d36777b513", + }, + { + img: "https://images.unsplash.com/photo-1518855706573-84de4022b69b", + }, + { + img: "https://images.unsplash.com/photo-1500049242364-5f500807cdd7", + }, + { + img: "https://images.unsplash.com/photo-1528759335187-3b683174c86a", + }, +]; +export const THUMBNAIL_PARAMS = "w=240&h=240&fit=crop&auto=format"; + +// Console styles. +export const CONSOLE_BASE_STYLES = [ + "font-size: 12px", + "padding: 4px", + "border: 2px solid #5a5a5a", + "color: white", +].join(";"); +export const CONSOLE_PRIMARY = [ + CONSOLE_BASE_STYLES, + "background-color: #13315a", +].join(";"); +export const CONSOLE_SUCCESS = [ + CONSOLE_BASE_STYLES, + "background-color: #385a4e", +].join(";"); +export const CONSOLE_ERROR = [ + CONSOLE_BASE_STYLES, + "background-color: #5a1a24", +].join(";"); + +// Layouts. +export const LAYOUT_4_COLUMNS = { + name: "Layout 4 columns", + columns: 4, + itemWidth: 240, + itemHeight: 240, +}; +export const LAYOUT_8_COLUMNS = { + name: "Layout 8 columns", + columns: 8, + itemWidth: 240, + itemHeight: 240, +}; +export const LAYOUTS = [LAYOUT_4_COLUMNS, LAYOUT_8_COLUMNS]; + +export const createImageFile = async (src) => + new Promise((resolve, reject) => { + const img = new Image(); + img.src = src; + img.onload = () => resolve(img); + img.onerror = () => reject(new Error("Failed to construct image.")); + }); + +export const loadImage = async (url) => { + try { + const response = await fetch(url); + if (!response.ok) { + throw new Error(String(response.status)); + } + + return await response.blob(); + } catch (e) { + console.log(`%cFETCHED_FAILED: ${e}`, CONSOLE_ERROR); + } +}; + +export const weakRefCache = (fetchImg) => { + const imgCache = new Map(); + const registry = new FinalizationRegistry(({ imgName, size, type }) => { + const cachedImg = imgCache.get(imgName); + if (cachedImg && !cachedImg.deref()) { + imgCache.delete(imgName); + console.log( + `%cCLEANED_IMAGE: Url: ${imgName}, Size: ${size}, Type: ${type}`, + CONSOLE_ERROR, + ); + + const logEl = document.createElement("div"); + logEl.classList.add("logger-item", "logger--error"); + logEl.innerHTML = `CLEANED_IMAGE: Url: ${imgName}, Size: ${size}, Type: ${type}`; + loggerContainerEl.appendChild(logEl); + loggerContainerEl.scrollTop = loggerContainerEl.scrollHeight; + } + }); + + return async (imgName) => { + const cachedImg = imgCache.get(imgName); + + if (cachedImg?.deref() !== undefined) { + console.log( + `%cCACHED_IMAGE: Url: ${imgName}, Size: ${cachedImg.size}, Type: ${cachedImg.type}`, + CONSOLE_SUCCESS, + ); + + const logEl = document.createElement("div"); + logEl.classList.add("logger-item", "logger--success"); + logEl.innerHTML = `CACHED_IMAGE: Url: ${imgName}, Size: ${cachedImg.size}, Type: ${cachedImg.type}`; + loggerContainerEl.appendChild(logEl); + loggerContainerEl.scrollTop = loggerContainerEl.scrollHeight; + + return cachedImg?.deref(); + } + + const newImg = await fetchImg(imgName); + console.log( + `%cFETCHED_IMAGE: Url: ${imgName}, Size: ${newImg.size}, Type: ${newImg.type}`, + CONSOLE_PRIMARY, + ); + + const logEl = document.createElement("div"); + logEl.classList.add("logger-item", "logger--primary"); + logEl.innerHTML = `FETCHED_IMAGE: Url: ${imgName}, Size: ${newImg.size}, Type: ${newImg.type}`; + loggerContainerEl.appendChild(logEl); + loggerContainerEl.scrollTop = loggerContainerEl.scrollHeight; + + imgCache.set(imgName, new WeakRef(newImg)); + registry.register(newImg, { + imgName, + size: newImg.size, + type: newImg.type, + }); + + return newImg; + }; +}; + +export const stateObj = { + loading: false, + drawing: true, + collageRendered: false, + currentLayout: LAYOUTS[0], + selectedImages: new Set(), +}; diff --git a/2-ui/1-document/01-browser-environment/article.md b/2-ui/1-document/01-browser-environment/article.md index f9fcd3e89e..7555d4c9d9 100644 --- a/2-ui/1-document/01-browser-environment/article.md +++ b/2-ui/1-document/01-browser-environment/article.md @@ -1,10 +1,18 @@ # 브라우저 환경과 다양한 명세서 +<<<<<<< HEAD 자바스크립트는 본래 웹 브라우저에서 사용하려고 만든 언어입니다. 이후 진화를 거쳐 다양한 사용처와 플랫폼을 지원하는 언어로 변모하였습니다. 자바스크립트가 돌아가는 플랫폼은 *호스트(host)* 라고 불립니다. 호스트는 브라우저, 웹서버, 심지어는 커피 머신이 될 수도 있습니다. 각 플랫폼은 해당 플랫폼에 특정되는 기능을 제공하는데, 자바스크립트 명세서에선 이를 *호스트 환경(host environment)* 이라고 부릅니다. 호스트 환경은 랭귀지 코어(ECMAScript - 옮긴이)에 더하여 플랫폼에 특정되는 객체와 함수를 제공합니다. 웹브라우저는 웹페이지를 제어하기 위한 수단을 제공하고, Node.js는 서버 사이드 기능을 제공해주죠. +======= +The JavaScript language was initially created for web browsers. Since then, it has evolved into a language with many uses and platforms. + +A platform may be a browser, or a web-server or another *host*, or even a "smart" coffee machine if it can run JavaScript. Each of these provides platform-specific functionality. The JavaScript specification calls that a *host environment*. + +A host environment provides its own objects and functions in addition to the language core. Web browsers give a means to control web pages. Node.js provides server-side features, and so on. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 아래 그림은 호스트 환경이 웹 브라우저일 때 사용할 수 있는 기능을 개괄적으로 보여줍니다. @@ -15,7 +23,11 @@ 1.Hello
`. + - [Comment](https://dom.spec.whatwg.org/#interface-comment) -- the class for comments. They are not shown, but each comment becomes a member of DOM. + +- [Element](https://dom.spec.whatwg.org/#interface-element) -- is the base class for DOM elements. + + It provides element-level navigation like `nextElementSibling`, `children` and searching methods like `getElementsByTagName`, `querySelector`. + + A browser supports not only HTML, but also XML and SVG. So the `Element` class serves as a base for more specific classes: `SVGElement`, `XMLElement` (we don't need them here) and `HTMLElement`. + +- Finally, [HTMLElement](https://html.spec.whatwg.org/multipage/dom.html#htmlelement) is the basic class for all HTML elements. We'll work with it most of the time. + + It is inherited by concrete HTML elements: + - [HTMLInputElement](https://html.spec.whatwg.org/multipage/forms.html#htmlinputelement) -- the class for `` elements, + - [HTMLBodyElement](https://html.spec.whatwg.org/multipage/semantics.html#htmlbodyelement) -- the class for `` elements, + - [HTMLAnchorElement](https://html.spec.whatwg.org/multipage/semantics.html#htmlanchorelement) -- the class for `` elements, + - ...and so on. + +There are many other tags with their own classes that may have specific properties and methods, while some elements, such as ``, `