diff --git a/1-js/02-first-steps/04-variables/article.md b/1-js/02-first-steps/04-variables/article.md index e6953fd7bc..1f9bcef423 100644 --- a/1-js/02-first-steps/04-variables/article.md +++ b/1-js/02-first-steps/04-variables/article.md @@ -1,61 +1,61 @@ -# 여러가지 변수 +# 여러 가지 변수 -Most of the time, a JavaScript application needs to work with information. Here are two examples: -1. An online shop -- the information might include goods being sold and a shopping cart. -2. A chat application -- the information might include users, messages, and much more. +대부분의 자바스크립트 애플리케이션은 정보와 함께 작업해야 합니다. 여기 두 예시가 있습니다.: +1. 온라인 쇼핑몰 -- 판매 중인 상품이나 쇼핑 카트 등의 정보 +2. 채팅 애플리케이션 -- 사용자, 메시지, 그 외의 더 많은 정보 변수는 이러한 정보를 저장하기 위해 사용됩니다. ## 변수(variable) -[변수(variable)](https://en.wikipedia.org/wiki/Variable_(computer_science)) 는 데이터를 저장하기 위해 "이름을 붙인 저장소" 입니다. We can use variables to store goodies, visitors and other data. +[변수(variable)](https://en.wikipedia.org/wiki/Variable_(computer_science)) 는 데이터를 저장하기 위해 "이름을 붙인 저장소" 입니다. 우리는 상품, 방문객, 그리고 또 다른 데이터를 저장하기 위해 변수를 사용할 수 있습니다. 자바스크립트에서 변수를 생성하기 위해서는 `let` 키워드를 사용해야 합니다. -아래 statement는 "message"라는 이름을 가진 변수를 생성(즉, *선언* 또는 *정의*)합니다. +아래 문은 "message"라는 이름을 가진 변수를 생성(즉, *선언* 또는 *정의*)합니다. ```js let message; ``` -이제 우리는 할당 연산자인 `=`를 통해 이 변수 안에 어떤 데이터를 저장할 수 있습니다.: +이제 우리는 할당 연산자인 `=`를 통해 이 변수 안에 데이터를 저장할 수 있습니다.: ```js let message; *!* -message = 'Hello'; // store the string +message = 'Hello'; // 문자열을 저장합니다. */!* ``` -The string is now saved into the memory area associated with the variable. We can access it using the variable name: +이 문자열은 이제 변수로 연결되어 메모리 영역에 저장되었습니다. 우리는 변수명을 통해 이 문자열에 접근할 수 있습니다.: ```js run let message; message = 'Hello!'; *!* -alert(message); // shows the variable content +alert(message); // 변수가 저장한 값을 보여줍니다. */!* ``` -To be concise, we can combine the variable declaration and assignment into a single line: +간결하게 변수 선언과 할당을 한 줄에 작성할 수 있습니다.: ```js run -let message = 'Hello!'; // define the variable and assign the value +let message = 'Hello!'; // 변수를 정의하고 값을 할당합니다. alert(message); // Hello! ``` -하나의 라인에 여러 변수를 선언할 수도 있습니다.: +한 줄에 여러 변수를 선언할 수도 있습니다.: ```js no-beautify let user = 'John', age = 25, message = 'Hello'; ``` -이렇게 작성하면 좀 더 코드가 짧아보이지만, 권장되는 것은 아닙니다. 좀 더 좋은 가독성을 위해, 변수 하나 당 하나의 라인을 사용해주세요. +이렇게 작성하면 좀 더 코드가 짧아 보이지만, 권장하진 않습니다. 가독성을 위해 한 변수는 한 줄에 작성해주세요. -여러 라인에 걸쳐 변수를 선언하면 좀 더 코드가 길어보이지만, 읽기엔 편합니다.: +여러 줄에 걸쳐 변수를 선언하면 좀 더 코드가 길어 보이지만, 읽기엔 편합니다.: ```js let user = 'John'; @@ -78,30 +78,34 @@ let user = 'John' , message = 'Hello'; ``` -기술적으로 보면, 이 모든 방식은 같은 작업을 하고 있습니다. So, it's a matter of personal taste and aesthetics. +기술적으로 보면, 이 모든 방식은 같은 작업을 하고 있습니다. 그러므로 이것은 개인의 취향과 미적 감각의 문제입니다. - -````smart header="`var` instead of `let`" -In older scripts, you may also find another keyword: `var` instead of `let`: +````smart header="`let` 대신 `let`" +여러분은 오래전에 작성된 스크립트에서 `let` 대신 `var`라는 다른 키워드를 발견했을지도 모릅니다.: ```js *!*var*/!* message = 'Hello'; ``` -The `var` keyword is *almost* the same as `let`. It also declares a variable, but in a slightly different, "old-school" way. +`var` 키워드는 *거의* `let`과 같습니다. 똑같이 변수를 선언하지만, 약간 다른, "오래된" 방식을 사용합니다. + +`let`과 `var` 사이에는 미묘한 차이점이 존재합니다. 하지만 우리에게 아직 이런 차이점은 중요하지 않습니다. 이후 주제에서 이에 대해 자세히 다루겠습니다. -There are subtle differences between `let` and `var`, but they do not matter for us yet. We'll cover them in detail in the chapter . ```` -## A real-life analogy +## 현실 속의 비유 -We can easily grasp the concept of a "variable" if we imagine it as a "box" for data, with a uniquely-named sticker on it. +자료를 보관하고 있고 그 위에는 이름 스티커가 붙여진 "상자"를 떠올리면 "변수"의 개념을 쉽게 이해할 수 있습니다. -For instance, the variable `message` can be imagined as a box labeled `"message"` with the value `"Hello!"` in it: +예를 들어, `message` 변수는 `"message"`라는 라벨이 붙여져 있고 그 안에 `"Hello!"` 라는 값이 담긴 상자로 생각할 수 있습니다.: ![](variable.png) -We can put any value in the box. + +우리는 상자 속에 어떤 값이든지 넣을 수 있습니다. + +원하는 만큼 값을 변경할 수도 있습니다.: + We can also change it as many times as we want: ```js run @@ -109,16 +113,16 @@ let message; message = 'Hello!'; -message = 'World!'; // value changed +message = 'World!'; // 값이 변경되었습니다. alert(message); ``` -When the value is changed, the old data is removed from the variable: +값이 변경되면 이전 값은 변수로부터 제거됩니다.: ![](variable-change.png) -We can also declare two variables and copy data from one into the other. +두 변수를 선언하고 한 변수의 데이터를 다른 변수에 복사할 수도 있습니다. ```js run let hello = 'Hello world!'; @@ -126,135 +130,134 @@ let hello = 'Hello world!'; let message; *!* -// copy 'Hello world' from hello into message +// hello의 'Hello world' 값을 message에 복사합니다. message = hello; */!* -// now two variables hold the same data +// 이제 두 변수는 같은 데이터를 지니고 있습니다. alert(hello); // Hello world! alert(message); // Hello world! ``` -```smart header="Functional languages" -It's interesting to note that [functional](https://en.wikipedia.org/wiki/Functional_programming) programming languages, like [Scala](http://www.scala-lang.org/) or [Erlang](http://www.erlang.org/), forbid changing variable values. +```smart header="함수형 언어" +변수값 변경을 금지하는 [함수형(functional)](https://en.wikipedia.org/wiki/Functional_programming) 프로그래밍 언어가 존재한다는 사실이 흥미로울 수도 있습니다. 예를 들면 [스칼라(Scala)](http://www.scala-lang.org/) 와 [얼랭(Erlang)](http://www.erlang.org/) 이 있습니다. -In such languages, once the value is stored "in the box", it's there forever. If we need to store something else, the language forces us to create a new box (declare a new variable). We can't reuse the old one. +이 언어들에서는 한 번 값이 "상자 속에" 저장되면 그 값은 영원히 그곳에 유지됩니다. 또 다른 값을 저장하고 싶다면 새로운 상자를 만들어야(새 변수를 선언해야)만 합니다. 이전 변수를 재사용할 수 없습니다. -Though it may seem a little odd at first sight, these languages are quite capable of serious development. More than that, there are areas like parallel computations where this limitation confers certain benefits. Studying such a language (even if you're not planning to use it soon) is recommended to broaden the mind. -``` +처음 봤을 땐 좀 이상해 보일 수 있지만 이들은 중대한 개발에 상당히 적합한 언어입니다. 더 나아가, 이런 제약이 장점으로 작용하는 병렬 계산과 같은 영역이 있습니다. 이런 언어를 (곧 사용할 계획이 없을지라도) 공부한다면 시야를 넓히는 데 도움이 될 것입니다. -## Variable naming [#variable-naming] +## 변수 명명법 [#variable-naming] -There are two limitations on variable names in JavaScript: +자바스크립트에는 변수명에 두 가지 제약이 존재합니다. -1. The name must contain only letters, digits, or the symbols `$` and `_`. -2. The first character must not be a digit. +1. 변수명에는 오직 문자, 숫자, 기호로는 `$`와 `_`만 올 수 있습니다. +2. 첫 글자는 숫자가 될 수 없습니다. -Examples of valid names: +유효한 변수명의 예시입니다.: ```js let userName; let test123; ``` -When the name contains multiple words, [camelCase](https://en.wikipedia.org/wiki/CamelCase) is commonly used. That is: words go one after another, each word starting with a capital letter: `myVeryLongName`. +변수명이 여러 단어를 포함할 땐 [카멜 케이스(camelCase)](https://en.wikipedia.org/wiki/CamelCase) 가 흔히 사용됩니다. 즉, 단어가 차례대로 오면서 각 단어는 대문자로 작성합니다.: `myVeryLongName`. -What's interesting -- the dollar sign `'$'` and the underscore `'_'` can also be used in names. They are regular symbols, just like letters, without any special meaning. +흥미로운 사실은 -- 달러 기호 `'$'` 와 언더스코어 `'_'` 는 변수명에 사용될 수 있다는 것입니다. 이들은 문자처럼 특별한 의미가 없는 일반적인 기호입니다. -These names are valid: +이런 변수명도 가능합니다.: ```js run untrusted -let $ = 1; // declared a variable with the name "$" -let _ = 2; // and now a variable with the name "_" +let $ = 1; // "$"라는 이름의 변수를 선언합니다. +let _ = 2; // "_"라는 이름의 변수를 선언합니다. alert($ + _); // 3 ``` -Examples of incorrect variable names: +잘못된 변수명의 예시는 다음과 같습니다.: ```js no-beautify -let 1a; // cannot start with a digit +let 1a; // 숫자로 시작해선 안 됩니다. -let my-name; // hyphens '-' aren't allowed in the name +let my-name; // 하이픈 '-'은 변수명에 올 수 없습니다. ``` -```smart header="Case matters" -Variables named `apple` and `AppLE` are two different variables. -``` +```smart header="대소문자 구별" +`apple`와 `AppLE`라는 이름의 변수는 -- 두 개의 서로 다른 변수입니다. + -````smart header="Non-English letters are allowed, but not recommended" -It is possible to use any language, including cyrillic letters or even hieroglyphs, like this: +````smart header="영어가 아닌 언어의 문자도 가능하지만 권장하지 않습니다." +다음과 같이 키릴 문자나 심지어 상형문자를 포함한 어떤 언어나 사용 가능합니다: ```js let имя = '...'; let 我 = '...'; ``` -Technically, there is no error here, such names are allowed, but there is an international tradition to use English in variable names. Even if we're writing a small script, it may have a long life ahead. People from other countries may need to read it some time. +기술적으로 이 코드에는 에러가 없으며 이 변수명들은 유효합니다. 그러나 변수명으로 영어를 사용하는 것이 국제적 관습입니다. 비록 우리가 짧은 스크립트를 작성하고 있지만 앞으로 길게 봐야 합니다. 다른 나라 사람이 우리가 작성한 스크립트를 볼지도 모릅니다. ```` -````warn header="Reserved names" -There is a [list of reserved words](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Lexical_grammar#Keywords), which cannot be used as variable names because they are used by the language itself. +````warn header="예약어" +언어 자체에 의해 사용되어 변수명으로 사용할 수 없는 [예약어 목록](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Lexical_grammar#Keywords)이 있습니다. -For example: `let`, `class`, `return`, and `function` are reserved. +예를 들어 `let`, `class`, `return`, `function`과 같은 단어가 예약어입니다. -The code below gives a syntax error: +아래 코드는 문법 에러를 발생시킵니다.: ```js run no-beautify -let let = 5; // can't name a variable "let", error! -let return = 5; // also can't name it "return", error! +let let = 5; // "let"을 변수명으로 사용할 수 없으므로 에러! +let return = 5; // "return"을 변수명으로 사용할 수 없으므로 에러! ``` ```` -````warn header="An assignment without `use strict`" +````warn header="`use strict` 없이 할당하기" -Normally, we need to define a variable before using it. But in the old times, it was technically possible to create a variable by a mere assignment of the value without using `let`. This still works now if we don't put `use strict` in our scripts to maintain compatibility with old scripts. +보통 변수를 사용하기 전에 먼저 변수를 정의해야 합니다. 그러나 예전에는 `let` 없이 단순한 값 할당에 의해 변수를 생성하는 것이 기술적으로 가능했습니다. `use strict`를 쓰지 않으면 지금도 가능한 일입니다. 과거 스크립트와의 호환성이 필요할 때 이 방식이 사용됩니다. ```js run no-strict -// note: no "use strict" in this example +// 주의: 이 예제에는 "use strict"가 없습니다. -num = 5; // the variable "num" is created if it didn't exist +num = 5; // 변수 "num"이 존재하지 않았다면 생성됩니다. alert(num); // 5 ``` -This is a bad practice and would cause an error in strict mode: +이것은 나쁜 관습입니다. 엄격 모드에서는 에러를 일으킬 것이기 때문이죠.: ```js "use strict"; *!* -num = 5; // error: num is not defined +num = 5; // 에러: num은 정의되지 않았습니다. */!* ``` ```` -## Constants +## 상수 -To declare a constant (unchanging) variable, use `const` instead of `let`: +변함없는 (변화하지 않는) 변수를 선언하기 위해서는 `let` 대신 `const`를 사용하면 됩니다.: ```js const myBirthday = '18.04.1982'; ``` -Variables declared using `const` are called "constants". They cannot be changed. An attempt to do so would cause an error: +`const`를 통해 선언된 변수를 "상수"라고 부릅니다. 상수는 변하지 않습니다. 상수를 변경하려고 하면 에러가 발생할 것입니다.: ```js run const myBirthday = '18.04.1982'; -myBirthday = '01.01.2001'; // error, can't reassign the constant! +myBirthday = '01.01.2001'; // 에러, 상수를 재할당할 수 없습니다! ``` -When a programmer is sure that a variable will never change, they can declare it with `const` to guarantee and clearly communicate that fact to everyone. +변수값이 절대 변경되지 않을 것이라고 프로그래머가 확신했을 때, 이 사실을 보장하고 그것을 모든 이에게 명확히 보여주기 위해 `const`를 사용할 수 있습니다. -### Uppercase constants +### 대문자로 된 상수 -There is a widespread practice to use constants as aliases for difficult-to-remember values that are known prior to execution. +기억하기 힘든 값들을 위해 미리 별칭으로 상수를 사용하는 일반적인 관습이 존재합니다. -Such constants are named using capital letters and underscores. +이런 상수들은 대문자와 언더스코어를 이용해 이름을 짓습니다. -Like this: +이렇게요.: ```js run const COLOR_RED = "#F00"; @@ -262,69 +265,70 @@ const COLOR_GREEN = "#0F0"; const COLOR_BLUE = "#00F"; const COLOR_ORANGE = "#FF7F00"; -// ...when we need to pick a color +// ...색상을 고르고 싶을 때 이렇게 사용합니다 let color = COLOR_ORANGE; alert(color); // #FF7F00 ``` -Benefits: +대문자로 된 상수를 사용하면 다음과 같은 장점이 있습니다.: -- `COLOR_ORANGE` is much easier to remember than `"#FF7F00"`. -- It is much easier to mistype `"#FF7F00"` than `COLOR_ORANGE`. -- When reading the code, `COLOR_ORANGE` is much more meaningful than `#FF7F00`. +- `COLOR_ORANGE`는 `"#FF7F00"`보다 기억하기가 훨씬 쉽습니다. +- `COLOR_ORANGE`보다 `"#FF7F00"`에서 오타를 낼 확률이 높습니다. +- 코드를 읽을 때, `COLOR_ORANGE`가 `#FF7F00`보다 훨씬 유의미합니다. -When should we use capitals for a constant and when should we name it normally? Let's make that clear. +그렇다면 언제 상수를 일반적으로 명명하고 언제 대문자를 사용해야 할까요? 명확히 짚고 넘어갑시다. -Being a "constant" just means that a variable's value never changes. But there are constants that are known prior to execution (like a hexadecimal value for red) and there are constants that are *calculated* in run-time, during the execution, but do not change after their initial assignment. +"상수"는 변수의 값이 절대 변하지 않는다는 것을 의미합니다. 그 중에는 (빨간색을 나타내는 16진수 값처럼) 코드 실행 전에 알려지는 상수도 있고 런타임에 *계산되지만* 할당 이후 값이 변하지 않는 상수도 있습니다. -For instance: +예를 들어: ```js -const pageLoadTime = /* time taken by a webpage to load */; +const pageLoadTime = /* 웹페이지를 로드하는데 걸린 시간 */; ``` -The value of `pageLoadTime` is not known prior to the page load, so it's named normally. But it's still a constant because it doesn't change after assignment. +`pageLoadTime` 값은 페이지가 로드되기 전에는 정해지지 않기 때문에 일반적으로 명명했습니다. 하지만 이 값은 할당 이후 변경되지 않으므로 여전히 상수입니다. -In other words, capital-named constants are only used as aliases for "hard-coded" values. +다시 말해, 대문자로 된 상수는 "코드로 작성하기 어려운" 값을 위한 별칭으로만 사용됩니다. -## Name things right +## 올바른 명명 규칙 -Talking about variables, there's one more extremely important thing. +변수에 관한 매우 중요한 사실이 한 가지 더 있습니다. -Please name your variables sensibly. Take time to think about this. +변수명을 신중하게 지어주세요. 변수명에 대해 생각할 시간을 좀 더 가져주세요. -Variable naming is one of the most important and complex skills in programming. A quick glance at variable names can reveal which code was written by a beginner versus an experienced developer. +변수의 이름을 짓는 것은 프로그래밍에서 가장 중요하고 복잡한 기술 중 하나입니다. 변수명만 슬쩍 봐도 코드를 초보자가 작성했는지 노련한 개발자가 작성했는지 알 수 있습니다. -In a real project, most of the time is spent modifying and extending an existing code base rather than writing something completely separate from scratch. When we return to some code after doing something else for a while, it's much easier to find information that is well-labeled. Or, in other words, when the variables have good names. +실제 프로젝트에서는 맨 처음부터 완전히 독립적인 코드를 작성하기보다 기존 코드의 틀을 변경하고 확장하면서 대부분 시간을 보냅니다. 우리가 작성했던 코드를 얼마 후에 다시 봤을 때, 알맞은 이름이 적힌 정보를 찾는 것이 훨씬 더 쉽습니다. 다시 말해, 변수가 올바른 이름을 가졌을 때 말이죠. -Please spend time thinking about the right name for a variable before declaring it. Doing so will repay you handsomely. +변수 선언에 앞서 변수의 올바른 이름에 대해 생각할 시간을 가져 주세요. -Some good-to-follow rules are: +참고하기 좋은 규칙을 알려드리겠습니다.: -- Use human-readable names like `userName` or `shoppingCart`. -- Stay away from abbreviations or short names like `a`, `b`, `c`, unless you really know what you're doing. -- Make names maximally descriptive and concise. Examples of bad names are `data` and `value`. Such names say nothing. It's only okay to use them if the context of the code makes it exceptionally obvious which data or value the variable is referencing. -- Agree on terms within your team and in your own mind. If a site visitor is called a "user" then we should name related variables `currentUser` or `newUser` instead of `currentVisitor` or `newManInTown`. +- `userName` 이나 `shoppingCart`처럼 사람이 읽을 수 있는 이름을 사용하세요. +- 여러분이 무엇을 하고 있는지 명확히 알지 않는 이상, 줄임말이나 `a`, `b`, `c`와 같이 짧은 이름은 피하세요. +- 최대한 서술적이고 간결한 이름을 사용하세요. 나쁜 이름의 예로는 `data`와 `value`가 있습니다. 이런 이름은 아무것도 설명해주지 않습니다. +코드의 문맥상 변수가 어떤 데이터나 값을 가리키는지가 아주 분명할 때에만 이런 이름을 사용하는 게 괜찮습니다. +- 자신만의 규칙이나 소속된 팀의 규칙을 따르세요. 만약 사이트 방문객을 "user"라고 부르기로 했다면 이와 관련된 변수를 `currentVisitor`나 `newManInTown`이 아닌 `currentUser`나 `newUser`라는 이름으로 지어야 합니다. -Sounds simple? Indeed it is, but creating descriptive and concise variable names in practice is not. Go for it. +간단해 보이나요? 그렇게 보이긴 합니다. 그러나 실전에서 서술적이고 간결한 변수명을 짓는 것은 간단하지 않습니다. 그럼, 화이팅! -```smart header="Reuse or create?" -And the last note. There are some lazy programmers who, instead of declaring new variables, tend to reuse existing ones. +```smart header="재사용 아니면 새로 만들기?" +이제 마지막 내용입니다. 프로그래머 중에는 새로운 변수를 선언하기보다 기존 변수를 재활용하는 게으른 자들이 있습니다. -As a result, their variables are like boxes into which people throw different things without changing their stickers. What's inside the box now? Who knows? We need to come closer and check. +결과적으로, 재사용된 변수는 과거의 이름 스티커를 그대로 붙인 채 다른 물건을 담고 있는 상자와 같습니다. 이제 상자 안에는 무엇이 들어 있나요? 누가 알고 있나요? 우리는 가까이 다가가 확인해야 합니다. -Such programmers save a little bit on variable declaration but lose ten times more on debugging. +변수를 재사용하는 프로그래머는 변수 선언을 조금 덜 하지만 디버깅에 열 배 더 많은 시간을 쏟아야 합니다. -An extra variable is good, not evil. +추가적인 변수는 좋습니다. 나쁘지 않아요. -Modern JavaScript minifiers and browsers optimize code well enough, so it won't create performance issues. Using different variables for different values can even help the engine optimize your code. +모던 자바스크립트의 압축기와 브라우저는 코드 최적화를 잘 하기 때문에 성능 이슈를 만들지 않습니다. 다른 값에 다른 변수를 사용하면 엔진의 코드 최적화에 도움이 될 수도 있습니다. ``` -## Summary +## 요약 -We can declare variables to store data by using the `var`, `let`, or `const` keywords. +데이터를 저장하기 위해 변수를 선언할 수 있습니다. `var`, `let`, `const`를 사용하면 됩니다. -- `let` -- is a modern variable declaration. The code must be in strict mode to use `let` in Chrome (V8). -- `var` -- is an old-school variable declaration. Normally we don't use it at all, but we'll cover subtle differences from `let` in the chapter , just in case you need them. -- `const` -- is like `let`, but the value of the variable can't be changed. +- `let` -- 현대적인 변수 선언입니다. 크롬 (V8)에서 `let`을 사용하기 위해서는 엄격 모드에서 코드를 작성해야 합니다. +- `var` -- 과거의 변수 선언입니다. 보통 전혀 사용하지 않는 방식이지만, 이후 주제에서 `var`과 `let`의 미묘한 차이점에 대해 다룰 때 살펴볼 것입니다. +- `const` -- `let`과 비슷하지만, 변수의 값을 변경할 수 없습니다. -Variables should be named in a way that allows us to easily understand what's inside them. +변수명은 변수의 값이 무엇인지 쉽게 이해할 수 있는 방식으로 지어져야 합니다. diff --git a/1-js/04-object-basics/01-object/article.md b/1-js/04-object-basics/01-object/article.md index 3b380683bd..efd01079ef 100644 --- a/1-js/04-object-basics/01-object/article.md +++ b/1-js/04-object-basics/01-object/article.md @@ -1,17 +1,17 @@ # 객체 (Objects) -우리가 챕터에서 배웠듯이, 자바스크립트에는 일곱 가지 데이터 타입이 존재합니다. 그 중 여섯 개의 타입은 오직 하나의 값(문자열, 숫자 등)만 담을 수 있기 때문에 "원시(primitive) 타입" 라고 불립니다. +우리가 챕터에서 배웠듯이, 자바스크립트에는 일곱 가지 데이터 타입이 존재합니다. 그중 여섯 개의 타입은 오직 하나의 값(문자열, 숫자 등)만 담을 수 있으므로 "기본 타입(primitive type)"이라고 불립니다. -이와 달리, 객체는 다양한 데이터와 더욱 복잡한 개체로 이루어진 이름을 가진 컬렉션(keyed collections)을 저장하기 위해 사용됩니다. 자바스크립트에서 객체는 penetrate almost every aspect of the language. 그러므로 우리는 다른 심도 깊은 내용으로 들어가기 전에 객체를 먼저 이해해야 합니다.(So we must understand them first before going in-depth anywhere else.) +이와 달리, 객체는 다양한 데이터와 복잡한 개체들의 키 컬렉션을 저장하기 위해 사용됩니다. 객체는 자바스크립트의 거의 모든 면에 스며들어 있습니다. 그러므로 우리는 다른 깊은 내용으로 들어가기 전에 먼저 객체를 이해해야 합니다. -객체는 중괄호 `{…}`를 통해 생성되는데, 부가적인 *프로퍼티(properties)* 리스트가 올 수도 있습니다. "키(key): 값(value)"의 쌍을 의미합니다. 여기서 `키`("프로퍼티 이름"으로도 불립니다.)는 문자열이며, `값`에는 무엇이든지 올 수 있습니다. +객체는 중괄호 `{…}`를 통해 생성되는데, 부가적으로 *프로퍼티(properties)* 리스트가 올 수도 있습니다. 프로퍼티는 "키(key): 값(value)"의 쌍을 의미합니다. 여기서 `키`("프로퍼티 이름"으로도 불립니다)는 문자열이며, `값`으로는 무엇이든지 올 수 있습니다. -We can imagine an object as a cabinet with signed files. Every piece of data is stored in its file by the key. It's easy to find a file by its name or add/remove a file. +우리는 각각 이름이 적힌 파일이 보관된 서랍장을 객체라고 생각할 수 있습니다. 모든 자료는 파일 안에 키로 저장되어 있습니다. 이름을 통해 파일을 찾거나 추가/삭제하는 일은 쉽습니다. ![](object.png) -빈 객체 ("empty cabinet") 는 두 구문 중 하나를 사용해 만들 수 있습니다.: +빈 객체("빈 서랍장")는 두 방식 중 하나를 사용해 만들 수 있습니다.: ```js let user = new Object(); // "객체 생성자" 구문 @@ -33,28 +33,28 @@ let user = { // 객체 }; ``` -프로퍼티는 `":"` 왼쪽에 ("이름" 또는 "identifier"라고도 불리는) 키를 갖고 있으며 오른쪽에는 값을 갖고 있습니다. +프로퍼티는 `":"` 왼쪽에 ("이름" 또는 "식별자"라고도 불리는) 키를 갖고 있으며 오른쪽에는 값을 갖고 있습니다. `user` 객체에는 두 프로퍼티가 존재합니다.: 1. 첫 번째 프로퍼티는 `"name"`이라는 이름과 `"John"`이라는 값을 갖고 있습니다. 2. 두 번째 프로퍼티는 `"age"`라는 이름과 `30`이라는 값을 갖고 있습니다. -결과적으로 `user` 객체는 can be imagined as a cabinet with two signed files labeled "name" and "age". +결과적으로 `user` 객체를 "name"과 "age"라는 이름의 파일들이 담긴 서랍장으로 생각할 수 있습니다. ![user object](object-user.png) -We can add, remove and read files from it any time. +우리는 이 서랍장으로부터 아무 때나 파일을 추가하고, 삭제하거나 읽을 수 있습니다. -dot notation 을 이용해 프로퍼티 값에 접근할 수 있습니다.: +프로퍼티 값은 마침표 표기법을 이용해 접근할 수 있습니다.: ```js -// get fields of the object: +// 객체의 필드 값 얻기: alert( user.name ); // John alert( user.age ); // 30 ``` -값은 어느 타입이나 될수 있습니다. 불리언 타입의 프로퍼티를 추가해봅시다.: +프로퍼티 값으로는 모든 데이터 타입이 가능합니다. 불린 타입의 프로퍼티를 추가해봅시다.: ```js user.isAdmin = true; @@ -62,7 +62,7 @@ user.isAdmin = true; ![user object 2](object-user-isadmin.png) -`delete` operator를 이용해 프로퍼티를 삭제할 수 있습니다.: +`delete` 연산자를 이용해 프로퍼티를 삭제할 수 있습니다.: ```js delete user.age; @@ -70,13 +70,13 @@ delete user.age; ![user object 3](object-user-delete.png) -We can also use multiword property names, but then they must be quoted: +여러 단어로 된 프로퍼티 이름을 사용할 수도 있지만, 반드시 따옴표로 묶여야 합니다.: ```js let user = { name: "John", age: 30, - "likes birds": true // multiword property name must be quoted + "likes birds": true // 여러 단어로 된 프로퍼티 이름은 따옴표로 묶여야 합니다. }; ``` @@ -90,20 +90,20 @@ let user = { age: 30*!*,*/!* } ``` -That is called a "trailing" or "hanging" comma. Makes it easier to add/remove/move around properties, because all lines become alike. +이것을 "trailing" 또는 "hanging" comma 라고 부릅니다. 이 comma를 통해 모든 줄이 비슷한 모습을 갖게 되어 프로퍼티를 쉽게 추가/삭제/이동할 수 있게 됩니다. ## 대괄호 -For multiword properties, the dot access doesn't work: +여러 단어로 된 프로퍼티 이름을 사용하면, 마침표 표기법을 사용할 수 없습니다.: ```js run -// this would give a syntax error +// 이 코드는 신택스 에러를 발생시킵니다. user.likes birds = true ``` -That's because the dot requires the key to be a valid variable identifier. That is: no spaces and other limitations. +프로퍼티 키가 유효한 변수 식별자일 때만 마침표 표기법을 사용할 수 있기 때문입니다. 즉, 스페이스를 포함한 다른 제약들이 없어야 합니다. -There's an alternative "square bracket notation" that works with any string: +어느 문자열과도 가능한 "대괄호 표기법" 이라는 대안이 존재합니다.: ```js run @@ -119,20 +119,20 @@ alert(user["likes birds"]); // true delete user["likes birds"]; ``` -Now everything is fine. Please note that the string inside the brackets is properly quoted (any type of quotes will do). +이제 모든 것이 제대로 작동합니다. 대괄호 안의 문자열이 따옴표로 묶인다는 사실에 주의하세요(따옴표 타입은 상관없습니다). -Square brackets also provide a way to obtain the property name as the result of any expression -- as opposed to a literal string -- like from a variable as follows: +또한 대괄호 표기법은 -- 문자열 리터럴이 아니라 -- 아래 코드에서 변수를 사용하는 것처럼 어느 표현식의 결과든지 프로퍼티 이름으로 사용할 수 있게 해줍니다.: ```js let key = "likes birds"; -// same as user["likes birds"] = true; +// user["likes birds"] = true; 와 같습니다. user[key] = true; ``` -Here, the variable `key` may be calculated at run-time or depend on the user input. And then we use it to access the property. That gives us a great deal of flexibility. The dot notation cannot be used in a similar way. +여기서 변수 `key`는 런타임에 계산되거나 사용자 입력값에 따라 달라질 수 있습니다. 그다음 우리는 프로퍼티에 접근하기 위해 이 변수를 사용합니다. 이것은 우리에게 상당한 유연성을 줍니다. 마침표 표기법은 이와 비슷한 방식으로 사용될 수 없습니다. -For instance: +예를 들어: ```js run let user = { @@ -142,45 +142,45 @@ let user = { let key = prompt("What do you want to know about the user?", "name"); -// access by variable +// 변수로 접근 alert( user[key] ); // John (if enter "name") ``` -### Computed properties +### 계산된 프로퍼티(Computed properties) -We can use square brackets in an object literal. That's called *computed properties*. +우리는 객체 리터럴 안에서 대괄호를 사용할 수 있습니다. 이것을 *계산된 프로퍼티(computed properties)* 라고 부릅니다. -For instance: +예를 들어: ```js run let fruit = prompt("Which fruit to buy?", "apple"); let bag = { *!* - [fruit]: 5, // the name of the property is taken from the variable fruit + [fruit]: 5, // fruit 변수로부터 프로퍼티 이름을 받아옵니다. */!* }; -alert( bag.apple ); // 5 if fruit="apple" +alert( bag.apple ); // 만약 fruit="apple" 이라면 5를 보여줍니다. ``` -The meaning of a computed property is simple: `[fruit]` means that the property name should be taken from `fruit`. +계산된 프로퍼티의 의미는 단순합니다. `[fruit]`은 프로퍼티 이름을 `fruit`으로부터 가져와야 한다는 것을 의미합니다. -So, if a visitor enters `"apple"`, `bag` will become `{apple: 5}`. +따라서, 만약 한 방문객이 `"apple"`을 입력한다면, `bag`은 `{apple: 5}`가 될 것입니다. -Essentially, that works the same as: +근본적으로 이와 같은 방식으로 실행됩니다.: ```js run let fruit = prompt("Which fruit to buy?", "apple"); let bag = {}; -// take property name from the fruit variable +// fruit 변수로부터 프로퍼티 이름을 가져옵니다. bag[fruit] = 5; ``` -...But looks nicer. +...하지만 앞서 봤던 코드가 더 근사해 보이네요. -We can use more complex expressions inside square brackets: +우리는 대괄호 안에 더욱 복잡한 문들을 사용할 수 있습니다.: ```js let fruit = 'apple'; @@ -189,16 +189,16 @@ let bag = { }; ``` -Square brackets are much more powerful than the dot notation. They allow any property names and variables. But they are also more cumbersome to write. +대괄호 표기법은 마침표 표기법보다 훨씬 더 강력합니다. 어떤 프로퍼티 이름이나 변수들을 사용할 수 있게 해줍니다. 하지만 작성하기에 더 번거로운 면이 있습니다. -So most of the time, when property names are known and simple, the dot is used. And if we need something more complex, then we switch to square brackets. +그래서 대부분의 경우 프로퍼티 이름이 이미 정해져 있고 간단할 때 마침표 표기법을 사용합니다. 만약 우리가 더 복잡한 무언가가 필요하게 되면 대괄호 표기법을 사용하면 됩니다. -````smart header="Reserved words are allowed as property names" -A variable cannot have a name equal to one of language-reserved words like "for", "let", "return" etc. +````smart header="예약어를 프로퍼티 이름으로 사용할 수 있습니다." +변수의 경우, "for", "let", "return" 등과 같은 자바스크립트의 예약어와 같은 이름을 사용할 수 없습니다. -But for an object property, there's no such restriction. Any name is fine: +하지만 객체 프로퍼티에는 이러한 제약이 없습니다. 어느 이름이나 가능합니다.: ```js run let obj = { @@ -210,37 +210,38 @@ let obj = { alert( obj.for + obj.let + obj.return ); // 6 ``` -Basically, any name is allowed, but there's a special one: `"__proto__"` that gets special treatment for historical reasons. For instance, we can't set it to a non-object value: +기본적으로 어느 이름이나 가능하지만 한 가지 예외사항이 존재합니다. `"__proto__"`은 역사적인 이유로 인해 특별한 취급을 받습니다. 예를 들어, 객체가 아닌 값에 이 이름을 사용할 수 없습니다.: ```js run let obj = {}; obj.__proto__ = 5; -alert(obj.__proto__); // [object Object], didn't work as intended +alert(obj.__proto__); // [object Object], 의도한 대로 작동하지 않습니다. ``` -As we see from the code, the assignment to a primitive `5` is ignored. +위 코드에서 볼 수 있듯이 기본값 `5`를 할당하는 것이 무시됩니다. -That can become a source of bugs and even vulnerabilities if we intend to store arbitrary key-value pairs in an object, and allow a visitor to specify the keys. +만약 우리가 임의의 키-값 쌍들을 어떤 객체 안에 저장하려고 한다면 이것은 버그나 취약성의 원인이 될 수 있으며 방문객이 그 키들을 지정하게 할 수도 있습니다. -In that case the visitor may choose "__proto__" as the key, and the assignment logic will be ruined (as shown above). +이 경우에 방문객은 키로 "__proto__"를 지정할 수도 있으며 이 할당 로직은 (위에서 봤듯이) 망가질 것입니다. + +객체들이 `__proto__`를 일반적인 프로퍼티로 취급하게 만드는 방법이 존재하며, 우리는 이것을 추후 다룰 것입니다. 그러나 먼저 우리는 객체에 대해 더 알아야 할 필요가 있습니다. +[Map](info:map-set-weakmap-weakset)이라는 또 다른 자료구조도 존재합니다. 우리는 임의의 키를 지원하는 에 대한 챕터에서 이에 대해 배울 것입니다. -There is a way to make objects treat `__proto__` as a regular property, which we'll cover later, but first we need to know more about objects. -There's also another data structure [Map](info:map-set-weakmap-weakset), that we'll learn in the chapter , which supports arbitrary keys. ```` -## Property value shorthand +## 프로퍼티 값 축약(Property value shorthand) -In real code we often use existing variables as values for property names. +실제 코드에서는 프로퍼티 이름에 대한 값으로 기존의 변수 이름을 자주 사용합니다. -For instance: +예를 들어: ```js run function makeUser(name, age) { return { name: name, age: age - // ...other properties + // ...등등 }; } @@ -248,103 +249,103 @@ let user = makeUser("John", 30); alert(user.name); // John ``` -In the example above, properties have the same names as variables. The use-case of making a property from a variable is so common, that there's a special *property value shorthand* to make it shorter. +위 예제에서, 프로퍼티들은 변수와 같은 이름을 갖고 있습니다. 변수로부터 프로퍼티를 만드는 사례는 매우 흔하며, 이를 더 쉽게 만들기 위해 특별히 *프로퍼티 값 축약(property value shorthand)*이 존재합니다. -Instead of `name:name` we can just write `name`, like this: +다음과 같이 `name:name` 대신 `name`만 적을 수 있게 됩니다.: ```js function makeUser(name, age) { *!* return { - name, // same as name: name - age // same as age: age + name, // name: name 와 같습니다. + age // age: age 와 같습니다. // ... }; */!* } ``` -We can use both normal properties and shorthands in the same object: +같은 객체 내에서 일반적인 표현과 축약 표현을 함께 사용할 수 있습니다.: ```js let user = { - name, // same as name:name + name, // name: name와 같습니다. age: 30 }; ``` -## Existence check +## 존재 확인 -A notable objects feature is that it's possible to access any property. There will be no error if the property doesn't exist! Accessing a non-existing property just returns `undefined`. It provides a very common way to test whether the property exists -- to get it and compare vs undefined: +어느 프로퍼티에나 접근 가능하다는 것은 객체의 중요한 특징입니다. 만약 프로퍼티가 존재하지 않는다고 해도 에러가 발생하지 않습니다! 존재하지 않는 프로퍼티에 접근하면 `undefined`를 반환할 뿐이지요. 이것은 프로퍼티의 존재 여부를 테스트하는 매우 일반적인 방법을 제공해 줍니다. -- 우선 접근해보고 undefined인지 확인해보면 되니까요.: ```js run let user = {}; -alert( user.noSuchProperty === undefined ); // true means "no such property" +alert( user.noSuchProperty === undefined ); // true는 "no such property"를 의미합니다. ``` -There also exists a special operator `"in"` to check for the existence of a property. +프로퍼티의 존재를 확인하기 위해서는 특별한 연산자인 `"in"`을 사용할 수도 있습니다. -The syntax is: +문법은 다음과 같습니다.: ```js "key" in object ``` -For instance: +예를 들어: ```js run let user = { name: "John", age: 30 }; -alert( "age" in user ); // true, user.age exists -alert( "blabla" in user ); // false, user.blabla doesn't exist +alert( "age" in user ); // true, user.age가 존재합니다. +alert( "blabla" in user ); // false, user.blabla가 존재하지 않습니다. ``` -Please note that on the left side of `in` there must be a *property name*. That's usually a quoted string. +`in`의 왼쪽에는 *프로퍼티 이름*이 있어야 한다는 사실을 주의하세요. 이 이름은 보통 따옴표로 묶인 문자열입니다. -If we omit quotes, that would mean a variable containing the actual name will be tested. For instance: +만약 따옴표를 생략하게 되면, 그 이름을 가진 변수의 존재를 확인해보라는 의미가 됩니다. 예를 들어: ```js run let user = { age: 30 }; let key = "age"; -alert( *!*key*/!* in user ); // true, takes the name from key and checks for such property +alert( *!*key*/!* in user ); // true, key로부터 가져온 값을 통해 프로퍼티의 존재를 확인합니다. ``` -````smart header="Using \"in\" for properties that store `undefined`" -Usually, the strict comparison `"=== undefined"` check works fine. But there's a special case when it fails, but `"in"` works correctly. +````smart header="`undefined` 값을 가진 프로퍼티에 \"in\" 사용하기" +일반적으로 일치를 확인하는 `"=== undefined"` 는 잘 작동합니다. 그러나 이것이 잘 작동하지 않는 특별한 경우도 있는데 반해 `"in"` 는 올바르게 작동합니다. -It's when an object property exists, but stores `undefined`: +바로 객체 프로퍼티가 존재하지만 `undefined` 값을 갖고 있는 상황일 때 해당됩니다.: ```js run let obj = { test: undefined }; -alert( obj.test ); // it's undefined, so - no such property? +alert( obj.test ); // undefined, 그런 프로퍼티가 존재하지 않는 걸까요? -alert( "test" in obj ); // true, the property does exist! +alert( "test" in obj ); // true, 프로퍼티는 존재합니다! ``` -In the code above, the property `obj.test` technically exists. So the `in` operator works right. +위 코드에서, `obj.test` 프로퍼티는 형식적으로 존재합니다. 그래서 `in` 연산자가 올바르게 작동합니다. -Situations like this happen very rarely, because `undefined` is usually not assigned. We mostly use `null` for "unknown" or "empty" values. So the `in` operator is an exotic guest in the code. +보통 `undefined` 값은 잘 할당되지 않기 때문에 이런 상황은 거의 일어나지 않습니다. 우리는 "알려지지 않았거나(unknown)" "비어 있는(empty)" 값에 주로 `null`을 사용합니다. 그래서 위 코드상의 `in` 연산자는 이국적인 손님과도 같습니다. ```` -## The "for..in" loop +## "for..in" 반복문 -To walk over all keys of an object, there exists a special form of the loop: `for..in`. This is a completely different thing from the `for(;;)` construct that we studied before. +객체의 모든 키를 탐색할 수 있도록 반복문의 특별한 형태인 `for..in`이 존재합니다. 이것은 우리가 이전에 배웠던 `for(;;)` 와는 완전히 다릅니다. -The syntax: +구문은 아래와 같습니다.: ```js for(key in object) { - // executes the body for each key among object properties + // 객체의 프로퍼티 중 각 키에 대해 바디(body)를 수행합니다. } ``` -For instance, let's output all properties of `user`: +예를 들어, `user`의 모든 프로퍼티를 출력해봅시다.: ```js run let user = { @@ -354,25 +355,25 @@ let user = { }; for(let key in user) { - // keys + // 키 alert( key ); // name, age, isAdmin - // values for the keys + // 키에 대한 값 alert( user[key] ); // John, 30, true } ``` -Note that all "for" constructs allow us to declare the looping variable inside the loop, like `let key` here. +여기서 `let key`와 같이 모든 "for" 구문은 반복문 안에서 반복문 변수를 선언할 수 있게 해줍니다. -Also, we could use another variable name here instead of `key`. For instance, `"for(let prop in obj)"` is also widely used. +또한, 우리는 `key` 대신에 다른 변수명을 사용할 수 있습니다. 예를 들어, `"for(let prop in obj)"`도 널리 사용되고 있습니다. -### Ordered like an object +### 객체의 정렬 방식 -Are objects ordered? In other words, if we loop over an object, do we get all properties in the same order they were added? Can we rely on this? +객체는 정렬되어 있나요? 다시 말해, 만약 우리가 객체에 대해 반복문을 돌면 객체에 추가된 순서대로 프로퍼티들을 얻게 되나요? 이걸 신뢰할 수 있을까요? -The short answer is: "ordered in a special fashion": integer properties are sorted, others appear in creation order. The details follow. +간단한 대답은 "특별한 방식으로 정렬되어 있다"는 것입니다. 다시 말해, 숫자형 프로퍼티들은 정렬되어 있으며 다른 프로퍼티들은 생성된 순서대로 나타납니다. 자세히 살펴보도록 하죠. -As an example, let's consider an object with the phone codes: +예를 들어, 전화번호 코드가 담긴 객체를 생각해봅시다.: ```js run let codes = { @@ -390,46 +391,46 @@ for(let code in codes) { */!* ``` -The object may be used to suggest a list of options to the user. If we're making a site mainly for German audience then we probably want `49` to be the first. +이 객체는 사용자에게 선택 목록을 제안하기 위해 사용될 수 있습니다. 만약 우리가 주로 독일 사용자를 위한 사이트를 만들고 있다면 아마 `49`가 맨 앞에 오기를 원할 것입니다. -But if we run the code, we see a totally different picture: +하지만 이 코드를 돌려보면 완전히 다른 모습을 보게 됩니다.: -- USA (1) goes first -- then Switzerland (41) and so on. +- USA (1)가 첫 번째로 등장합니다. +- 그 뒤로 Switzerland (41)가 등장하고 나머지가 뒤따릅니다. -The phone codes go in the ascending sorted order, because they are integers. So we see `1, 41, 44, 49`. +전화번호 코드는 숫자형이기 때문에 오름차순으로 정렬되어 나타납니다. 그래서 우리는 `1, 41, 44, 49`와 같은 결과를 보게 됩니다. -````smart header="Integer properties? What's that?" -The "integer property" term here means a string that can be converted to-and-from an integer without a change. +````smart header="숫자형 프로퍼티? 그게 무엇인가요?" +"숫자형 프로퍼티"는 변함없이 숫자로부터 변환되거나 숫자로 변환될 수 있는 문자열을 의미합니다. -So, "49" is an integer property name, because when it's transformed to an integer number and back, it's still the same. But "+49" and "1.2" are not: +그래서 "49"는 숫자형 프로퍼티 이름입니다. "49"가 정수로 변환되거나 정수에서 변환될 때 여전히 같은 모습을 갖고 있기 때문이죠. 하지만 "+49"와 "1.2"는 다릅니다.: ```js run -// Math.trunc is a built-in function that removes the decimal part -alert( String(Math.trunc(Number("49"))) ); // "49", same, integer property -alert( String(Math.trunc(Number("+49"))) ); // "49", not same "+49" ⇒ not integer property -alert( String(Math.trunc(Number("1.2"))) ); // "1", not same "1.2" ⇒ not integer property +// Math.trunc 는 소수부를 제거하는 내장 함수입니다 +alert( String(Math.trunc(Number("49"))) ); // "49", 같습니다, 숫자형 프로퍼티입니다. +alert( String(Math.trunc(Number("+49"))) ); // "49", "+49"와 다릅니다 ⇒ 숫자형 프로퍼티가 아닙니다. +alert( String(Math.trunc(Number("1.2"))) ); // "1", "1.2"와 다릅니다 ⇒ 숫자형 프로퍼티가 아닙니다. ``` ```` -...On the other hand, if the keys are non-integer, then they are listed in the creation order, for instance: +...반면에 만약 프로퍼티 키가 숫자형이 아니라면 생성된 순서대로 나열됩니다. 예를 들어: ```js run let user = { name: "John", surname: "Smith" }; -user.age = 25; // add one more +user.age = 25; // 프로퍼티를 하나 추가합니다. *!* -// non-integer properties are listed in the creation order +// 숫자형 프로퍼티가 아닌 것들은 생성된 순서로 나열됩니다. */!* for (let prop in user) { alert( prop ); // name, surname, age } ``` -So, to fix the issue with the phone codes, we can "cheat" by making the codes non-integer. Adding a plus `"+"` sign before each code is enough. +따라서, 전화번호 코드와 관련된 문제를 해결하기 위해서는 코드가 숫자형이 안되게 만드는 속임수를 쓸 수 있습니다. 각 코드 앞에 `"+"`를 추가하는 것으로 충분합니다. Like this: @@ -447,30 +448,30 @@ for(let code in codes) { } ``` -Now it works as intended. +이제 코드는 의도한 대로 작동합니다. -## Copying by reference +## 참조에 의한 복사 -One of the fundamental differences of objects vs primitives is that they are stored and copied "by reference". +객체와 기본 타입의 근본적인 차이 중 하나는 객체는 "참조에 의해" 저장되고 복사된다는 것입니다. -Primitive values: strings, numbers, booleans -- are assigned/copied "as a whole value". +기본값: 문자열, 숫자, 불린 -- 은 "온전한 값으로" 할당되고 복사됩니다. -For instance: +예를 들어: ```js let message = "Hello!"; let phrase = message; ``` -As a result we have two independent variables, each one is storing the string `"Hello!"`. +코드 실행 결과, 우리는 두 개의 서로 다른 변수를 갖고 있으며 각 변수는 `"Hello!"`라는 문자열을 저장하고 있습니다. ![](variable-copy-value.png) -Objects are not like that. +객체는 이와 다릅니다. -**A variable stores not the object itself, but its "address in memory", in other words "a reference" to it.** +**변수는 객체 자체를 저장하는 것이 아니라, 객체의 "메모리상의 주소", 즉 객체에 대한 "참조값"을 저장합니다.** -Here's the picture for the object: +여기 객체를 나타내는 그림이 있습니다.: ```js let user = { @@ -480,25 +481,25 @@ let user = { ![](variable-contains-reference.png) -Here, the object is stored somewhere in memory. And the variable `user` has a "reference" to it. +객체는 메모리의 어딘가에 저장되어 있습니다. 그리고 변수 `user`는 객체에 대한 참조값을 갖고 있습니다. -**When an object variable is copied -- the reference is copied, the object is not duplicated.** +**객체 변수가 복사될 때 -- 즉, 객체의 참조값이 복사될 때, 그 객체는 복제되지 않습니다.** -If we imagine an object as a cabinet, then a variable is a key to it. Copying a variable duplicates the key, but not the cabinet itself. +우리가 객체를 서랍장으로 생각한다면, 변수는 서랍장을 열기 위한 열쇠입니다. 변수를 복사하는 것은 그 열쇠를 복제하는 것이지 서랍장 자체를 복제하진 않습니다. -For instance: +예를 들어: ```js no-beautify let user = { name: "John" }; -let admin = user; // copy the reference +let admin = user; // 참조를 복사합니다. ``` -Now we have two variables, each one with the reference to the same object: +각 변수는 이제 같은 객체에 대한 참조값을 갖고 있습니다.: ![](variable-copy-reference.png) -We can use any variable to access the cabinet and modify its contents: +서랍장에 접근하거나 서랍장의 내용물을 변경하기 위해 둘 중 아무 변수나 사용하면 됩니다.: ```js run let user = { name: 'John' }; @@ -506,46 +507,46 @@ let user = { name: 'John' }; let admin = user; *!* -admin.name = 'Pete'; // changed by the "admin" reference +admin.name = 'Pete'; // "admin" 참조값에 의해 변경되고 */!* -alert(*!*user.name*/!*); // 'Pete', changes are seen from the "user" reference +alert(*!*user.name*/!*); // 'Pete', 변경사항이 "user" 참조값에서 확인됩니다. ``` -The example above demonstrates that there is only one object. As if we had a cabinet with two keys and used one of them (`admin`) to get into it. Then, if we later use the other key (`user`) we would see changes. +위 예제는 오직 하나의 객체만 존재한다는 사실을 보여주고 있습니다. 우리가 키가 두 개 있는 서랍장을 갖고 있으며 서랍장을 열기 위해 하나의 키(`admin`)를 사용한 것처럼 말이죠. 그러고 나서 나중에 우리가 다른 하나의 키(`user`)를 사용하면, 변경사항을 확인하게 될 것입니다. -### Comparison by reference +### 참조에 의한 비교 -The equality `==` and strict equality `===` operators for objects work exactly the same. +객체에 있어서 동등 연산자 `==` 와 일치 연산자 `===` 는 완전히 같은 방식으로 작동합니다. -**Two objects are equal only if they are the same object.** +**두 객체가 같은 객체일 때만 그들은 동등합니다.** -For instance, two variables reference the same object, they are equal: +예를 들어, 두 변수가 같은 객체를 참조하면 그들은 동등합니다.: ```js run let a = {}; -let b = a; // copy the reference +let b = a; // 참조에 의한 복사 -alert( a == b ); // true, both variables reference the same object +alert( a == b ); // true, 두 변수는 같은 객체를 참조합니다. alert( a === b ); // true ``` -And here two independent objects are not equal, even though both are empty: +여기서 독립된 두 객체는 둘 다 빈 객체일지라도 동등하지 않습니다.: ```js run let a = {}; -let b = {}; // two independent objects +let b = {}; // 독립된 두 객체 alert( a == b ); // false ``` -For comparisons like `obj1 > obj2` or for a comparison against a primitive `obj == 5`, objects are converted to primitives. We'll study how object conversions work very soon, but to tell the truth, such comparisons are necessary very rarely and usually are a result of a coding mistake. +`obj1 > obj2`와 같은 비교나 기본값에 대한 비교 `obj == 5`에서 객체는 기본값으로 변환됩니다. 우리는 머지않아 객체 변환이 어떻게 이뤄지는지 배우게 될 것입니다. 그러나 사실 이러한 비교는 거의 필요하지 않으며 보통 코딩 실수에 의한 결과라고 할 수 있습니다. -### Const object +### Const 객체 -An object declared as `const` *can* be changed. +`const`로 선언된 객체는 *변경될 수 있습니다.* -For instance: +예를 들어: ```js run const user = { @@ -559,9 +560,9 @@ user.age = 25; // (*) alert(user.age); // 25 ``` -It might seem that the line `(*)` would cause an error, but no, there's totally no problem. That's because `const` fixes the value of `user` itself. And here `user` stores the reference to the same object all the time. The line `(*)` goes *inside* the object, it doesn't reassign `user`. +`(*)` 행이 에러를 일으킬 것처럼 보이지만 사실 전혀 문제가 없습니다. 왜냐하면 `const`가 `user` 자체의 값을 고정하기 때문입니다. 그리고 여기서 `user`은 언제나 같은 객체에 대한 참조값을 저장하고 있습니다. `(*)` 행은 객체의 *내부로* 들어가며, `user`를 재할당하지 않습니다. -The `const` would give an error if we try to set `user` to something else, for instance: +만약 우리가 `user`를 다른 어떤 것으로 설정하고자 한다면 `const`가 에러를 발생시킬 것입니다. 예를 들어: ```js run const user = { @@ -569,26 +570,26 @@ const user = { }; *!* -// Error (can't reassign user) +// 에러 (user를 재할당할 수 없습니다.) */!* user = { name: "Pete" }; ``` -...But what if we want to make constant object properties? So that `user.age = 25` would give an error. That's possible too. We'll cover it in the chapter . +...그러나 만약 상수 객체 프로퍼티를 만들고 싶다면 어떻게 될까요? 그러면 `user.age = 25`가 에러를 일으킬 수도 있습니다. 챕터에서 이에 대한 내용을 다룰 예정입니다. -## Cloning and merging, Object.assign +## 복사와 병합, Object.assign -So, copying an object variable creates one more reference to the same object. +따라서, 객체 변수를 복사하는 것은 같은 객체에 대한 참조값을 하나 더 만들어 냅니다. -But what if we need to duplicate an object? Create an independent copy, a clone? +하지만 만약 우리가 객체를 복제해야 할 때는 어떻게 할까요? 독립적인 복사본, 복제를 만들고 싶다면요? -That's also doable, but a little bit more difficult, because there's no built-in method for that in JavaScript. Actually, that's rarely needed. Copying by reference is good most of the time. +물론 할 수는 있습니다만, 조금 더 어렵습니다. 왜냐하면 자바스크립트에는 이를 위한 내장 함수가 없기 때문입니다. 사실, 필요할 일이 거의 없긴 합니다. 대부분의 경우 참조에 의한 복사가 좋습니다. -But if we really want that, then we need to create a new object and replicate the structure of the existing one by iterating over its properties and copying them on the primitive level. +그러나 우리가 정말 복제를 하고 싶다면, 새로운 객체를 만든 다음 기존 객체의 프로퍼티들을 순회하고 그것들을 모두 복사하면서 기존 객체의 구조를 복제해야 합니다. -Like this: +이렇게 말이죠.: ```js run let user = { @@ -597,32 +598,32 @@ let user = { }; *!* -let clone = {}; // the new empty object +let clone = {}; // 새로운 빈 객체 -// let's copy all user properties into it +// 빈 객체에 모든 user 프로퍼티를 복사해 넣어봅시다. for (let key in user) { clone[key] = user[key]; } */!* -// now clone is a fully independent clone -clone.name = "Pete"; // changed the data in it +// 이제 clone은 완전히 독립적인 복사본입니다. +clone.name = "Pete"; // clone의 데이터를 변경했습니다. -alert( user.name ); // still John in the original object +alert( user.name ); // 원본 객체에는 여전히 John이 있습니다. ``` -Also we can use the method [Object.assign](mdn:js/Object/assign) for that. +또한 [Object.assign](mdn:js/Object/assign)를 사용하는 방법도 있습니다. -The syntax is: +문법은 다음과 같습니다.: ```js Object.assign(dest[, src1, src2, src3...]) ``` -- Arguments `dest`, and `src1, ..., srcN` (can be as many as needed) are objects. -- It copies the properties of all objects `src1, ..., srcN` into `dest`. In other words, properties of all arguments starting from the 2nd are copied into the 1st. Then it returns `dest`. +- 인자 `dest` 와 `src1, ..., srcN` (필요에 따라 얼마든지 올 수 있습니다)는 객체입니다. +- 모든 객체 `src1, ..., srcN` 의 프로퍼티를 `dest`에 복사합니다. 다시 말해, 두 번째 인자부터 모든 객체들의 프로퍼티가 첫 번째 인자 객체로 복사됩니다. 이후 `dest`를 반환합니다. -For instance, we can use it to merge several objects into one: +예를 들어, 우리는 여러 객체를 하나의 객체로 병합하기 위해 이것을 사용할 수 있습니다.: ```js let user = { name: "John" }; @@ -630,25 +631,25 @@ let permissions1 = { canView: true }; let permissions2 = { canEdit: true }; *!* -// copies all properties from permissions1 and permissions2 into user +// permissions1와 permissions2의 모든 프로퍼티를 user로 복사합니다. Object.assign(user, permissions1, permissions2); */!* -// now user = { name: "John", canView: true, canEdit: true } +// 그 결과, user = { name: "John", canView: true, canEdit: true } 가 됩니다. ``` -If the receiving object (`user`) already has the same named property, it will be overwritten: +만약 복사를 받는 객체 (`user`)가 이미 같은 이름의 프로퍼티를 갖고 있다면, 새로운 값으로 덮어쓰여집니다.: ```js let user = { name: "John" }; -// overwrite name, add isAdmin +// name을 덮어 쓰고 isAdmin을 추가합니다. Object.assign(user, { name: "Pete", isAdmin: true }); -// now user = { name: "Pete", isAdmin: true } +// 그 결과, user = { name: "Pete", isAdmin: true } ``` -We also can use `Object.assign` to replace the loop for simple cloning: +간단한 복사를 위한 반복문 대신 `Object.assign`를 사용할 수도 있습니다. ```js let user = { @@ -661,11 +662,11 @@ let clone = Object.assign({}, user); */!* ``` -It copies all properties of `user` into the empty object and returns it. Actually, the same as the loop, but shorter. +이 코드는 `user`의 모든 프로퍼티를 빈 객체에 복사한 뒤 돌려줍니다. 사실, 반복문을 돌리는 것과 같은 작업이지만 코드가 더 짧아집니다. -Until now we assumed that all properties of `user` are primitive. But properties can be references to other objects. What to do with them? +지금까지 우리는 `user`의 모든 프로퍼티가 기본값이라고 가정했습니다. 그러나 프로퍼티는 다른 객체에 대한 참조값이 될 수도 있습니다. 이 경우에 어떻게 하면 될까요? -Like this: +예제가 있습니다.: ```js run let user = { name: "John", @@ -678,9 +679,9 @@ let user = { alert( user.sizes.height ); // 182 ``` -Now it's not enough to copy `clone.sizes = user.sizes`, because the `user.sizes` is an object, it will be copied by reference. So `clone` and `user` will share the same sizes: +이제 `clone.sizes = user.sizes` 로 복사하는 것만으로는 충분하지 않습니다. `user.sizes` 는 객체이기 때문에 참조로 복사가 될 것입니다. 그러므로 `clone`과 `user`는 같은 sizes를 공유하게 됩니다.: -Like this: +이렇게요.: ```js run let user = { name: "John", @@ -692,49 +693,50 @@ let user = { let clone = Object.assign({}, user); -alert( user.sizes === clone.sizes ); // true, same object +alert( user.sizes === clone.sizes ); // true, 같은 객체입니다. -// user and clone share sizes -user.sizes.width++; // change a property from one place -alert(clone.sizes.width); // 51, see the result from the other one +// user와 clone는 sizes를 공유합니다. +user.sizes.width++; // 한 객체에서 프로퍼티를 변경합니다. +alert(clone.sizes.width); // 51, 다른 객체에서 프로퍼티 값이 달라졌습니다. ``` -To fix that, we should use the cloning loop that examines each value of `user[key]` and, if it's an object, then replicate its structure as well. That is called a "deep cloning". +이 문제를 해결하기 위해, 우리는 `user[key]`의 각 값을 검사하면서 만약 그 값이 객체라면 객체의 구조도 복사를 하는 복사 반복문을 사용해야 합니다. 이 과정을 "깊은 복사(deep cloning)"라고 합니다. -There's a standard algorithm for deep cloning that handles the case above and more complex cases, called the [Structured cloning algorithm](http://w3c.github.io/html/infrastructure.html#safe-passing-of-structured-data). In order not to reinvent the wheel, we can use a working implementation of it from the JavaScript library [lodash](https://lodash.com), the method is called [_.cloneDeep(obj)](https://lodash.com/docs#cloneDeep). +위 예제를 포함해 더 복잡한 케이스들을 처리하는 깊은 복사를 위해 표준 알고리즘 [Structured cloning algorithm](http://w3c.github.io/html/infrastructure.html#safe-passing-of-structured-data)이 존재합니다. 시간을 낭비하지 않기 위해, 이미 구현된 자바스크립트 라이브러리 [lodash](https://lodash.com)에서 [_.cloneDeep(obj)](https://lodash.com/docs#cloneDeep)라는 메서드를 사용할 수 있습니다. -## Summary +## 요약 -Objects are associative arrays with several special features. +객체는 여러 특별한 특징을 가진 연관 배열입니다. -They store properties (key-value pairs), where: -- Property keys must be strings or symbols (usually strings). -- Values can be of any type. +객체는 프로퍼티(키-값 형태)을 저장합니다.: +- 키는 문자열이나 심볼이어야 합니다 (보통 문자열을 사용합니다). +- 값은 어느 타입이나 가능합니다. -To access a property, we can use: -- The dot notation: `obj.property`. -- Square brackets notation `obj["property"]`. Square brackets allow to take the key from a variable, like `obj[varWithKey]`. +프로퍼티에 접근하기 위해서는 다음 방법을 사용할 수 있습니다.: +- 마침표 표기법: `obj.property`. +- 대괄호 표기법 `obj["property"]`. 대괄호 표기법을 사용하면 `obj[varWithKey]`처럼 변수로부터 키 값을 가져올 수 있습니다. -Additional operators: -- To delete a property: `delete obj.prop`. -- To check if a property with the given key exists: `"key" in obj`. -- To iterate over an object: `for(let key in obj)` loop. +추가적인 연산자: +- 프로퍼티 삭제: `delete obj.prop`. +- 주어진 키 값을 가진 프로퍼티의 존재 여부 확인: `"key" in obj`. +- 객체 순회: `for(let key in obj)` 반복문. -Objects are assigned and copied by reference. In other words, a variable stores not the "object value", but a "reference" (address in memory) for the value. So copying such a variable or passing it as a function argument copies that reference, not the object. All operations via copied references (like adding/removing properties) are performed on the same single object. +객체는 참조에 의해 할당되고 복사됩니다. 다시 말해, 변수는 "객체 값" 자체를 저장하지 않고 객체 값의 "참조" (메모리 상의 주소)를 저장합니다. 그래므로 +객체 변수를 복사하거나 함수의 인자로 넘겨주는 행위는 객체가 아닌 객체의 참조를 복사합니다. 복사된 참조를 통한 (프로퍼티 추가/삭제와 같은) 모든 작업들은 하나의 동일한 객체에 대해 수행됩니다. -To make a "real copy" (a clone) we can use `Object.assign` or [_.cloneDeep(obj)](https://lodash.com/docs#cloneDeep). +"진정한 복사본" (복제) 을 만들기 위해서는 `Object.assign`나 [_.cloneDeep(obj)](https://lodash.com/docs#cloneDeep)를 사용할 수 있습니다. -What we've studied in this chapter is called a "plain object", or just `Object`. +우리가 이 챕터에서 배운 것을 "순수 객체(plain object)" 또는 `객체(Object)`라고 합니다. -There are many other kinds of objects in JavaScript: +이외에도 자바스크립트에는 많은 종류의 객체가 있습니다.: -- `Array` to store ordered data collections, -- `Date` to store the information about the date and time, -- `Error` to store the information about an error. -- ...And so on. +- 정렬된 데이터 집합을 저장하기 위한 `Array` +- 날짜와 시간 정보를 저장하기 위한 `Date` +- 에러 정보를 저장하기 위한 `Error` +- ...기타 등등 -They have their special features that we'll study later. Sometimes people say something like "Array type" or "Date type", but formally they are not types of their own, but belong to a single "object" data type. And they extend it in various ways. +이 객체들은 각자만의 특별한 특징을 지니고 있으며 이후 우리가 배우게 될 것입니다. 사람들은 종종 "Array 타입"이나 "Data 타입"이라고 할 때가 있습니다. 하지만 공식적으로 Array와 Data는 온전한 타입이 아니라 단일한 "객체" 데이터 타입에 속합니다. 또한 이들은 다양한 방식으로 객체를 확장합니다. -Objects in JavaScript are very powerful. Here we've just scratched the surface of a topic that is really huge. We'll be closely working with objects and learning more about them in further parts of the tutorial. +자바스크립트의 객체는 매우 강력합니다. 여기서는 객체라는 정말 거대한 주제의 극히 일부만 다루었습니다. 튜토리얼의 이후 파트에서 우리는 객체들과 밀접한 작업을 하게 될 것이며 객체에 대해 더 많은 것을 배울 것입니다. diff --git a/1-js/04-object-basics/02-garbage-collection/article.md b/1-js/04-object-basics/02-garbage-collection/article.md index 27682ef40b..2ddee066cd 100644 --- a/1-js/04-object-basics/02-garbage-collection/article.md +++ b/1-js/04-object-basics/02-garbage-collection/article.md @@ -1,38 +1,38 @@ -# Garbage collection +# 가비지 컬렉션(Garbage Collection) -Memory management in JavaScript is performed automatically and invisibly to us. We create primitives, objects, functions... All that takes memory. +자바스크립트의 메모리 관리는 자동으로 수행되며 우리 눈에 보이지 않습니다. 우리가 기본값을 가진 변수나 객체, 함수 등을 만들 때 이 모든 것은 메모리를 차지합니다. -What happens when something is not needed any more? How does the JavaScript engine discover it and clean it up? +만약 어떤 것이 더 필요없게 된다면 어떻게 될까요? 자바스크립트 엔진은 어떻게 필요없는 것을 찾아내 삭제하는 걸까요? -## Reachability +## 도달 가능성(Reachability) -The main concept of memory management in JavaScript is *reachability*. +자바스크립트에서 메모리 관리의 주요 개념은 *도달 가능성(Reachability)*입니다. -Simply put, "reachable" values are those that are accessible or usable somehow. They are guaranteed to be stored in memory. +쉽게 말해, "도달 가능한" 값들은 어떻게든 접근할 수 있으며 사용할 수 있는 값들을 말합니다. 이 값들은 메모리에 유지되는 것이 보장됩니다. -1. There's a base set of inherently reachable values, that cannot be deleted for obvious reasons. +1. 본질적으로 도달 가능한 값들의 기본 집합이 있습니다. 이 값들은 명백한 이유로 삭제될 수 없습니다. - For instance: + 예를 들어: - - Local variables and parameters of the current function. - - Variables and parameters for other functions on the current chain of nested calls. - - Global variables. - - (there are some other, internal ones as well) + - 현재 함수의 지역 변수와 매개 변수 + - 중첩된 함수 호출로 실행된 경우 현재 스코프 체인에 있는 변수와 매개 변수 + - 전역 변수 + - (내부적인 다른 값들도 존재합니다.) - These values are called *roots*. + 이 값들은 *루트(roots)*라고 불립니다. -2. Any other value is considered reachable if it's reachable from a root by a reference or by a chain of references. +2. 루트에서 참조나 참조의 체인에 의해 도달 가능한 값이 있다면 그 값은 도달 가능합니다. - For instance, if there's an object in a local variable, and that object has a property referencing another object, that object is considered reachable. And those that it references are also reachable. Detailed examples to follow. + 예를 들어, 만약 지역 변수가 어떤 객체를 참조하고 있고 이 객체는 다른 객체를 참조하는 프로퍼티를 갖고 있다면, 그 객체는 도달 가능하다고 여겨집니다. 그리고 그 객체가 참조하는 값들 역시 도달 가능합니다. 아래에서 자세한 예시를 봅시다. -There's a background process in the JavaScript engine that is called [garbage collector](https://en.wikipedia.org/wiki/Garbage_collection_(computer_science)). It monitors all objects and removes those that have become unreachable. +자바스크립트 엔진에는 [가비지 컬렉터(garbage collector)](https://en.wikipedia.org/wiki/Garbage_collection_(computer_science)) 라는 백그라운드 프로세스가 있습니다. 가비지 컬렉터는 모든 객체를 모니터링하면서 객체가 도달할 수 없는 상태가 되었을 때 삭제합니다. -## A simple example +## 간단한 예제 -Here's the simplest example: +간단한 예제를 하나 살펴봅시다.: ```js -// user has a reference to the object +// user는 객체에 대한 참조를 갖고 있습니다. let user = { name: "John" }; @@ -40,9 +40,9 @@ let user = { ![](memory-user-john.png) -Here the arrow depicts an object reference. The global variable `"user"` references the object `{name: "John"}` (we'll call it John for brevity). The `"name"` property of John stores a primitive, so it's painted inside the object. +이 그림에서 화살표는 객체 참조를 나타냅니다. 전역 변수(``) `"user"` 는 `{name: "John"}` (줄여서 John이라고 부르겠습니다) 이라는 객체를 참조합니다. John의 `"name"` 프로퍼티는 기본값을 저장하고 있기 때문에 객체(`Object`) 안에 위치합니다. -If the value of `user` is overwritten, the reference is lost: +만약 `user` 값이 다른 값으로 덮어 쓰이면 기존의 참조를 잃게 됩니다.: ```js user = null; @@ -50,14 +50,14 @@ user = null; ![](memory-user-john-lost.png) -Now John becomes unreachable. There's no way to access it, no references to it. Garbage collector will junk the data and free the memory. +이제 John은 도달할 수 없게 되었습니다. John에 접근할 방법은 없으며, John에 대한 어떤 참조도 존재하지 않습니다. 가비지 컬렉터는 이 데이터를 삭제하고 메모리를 해제할 것입니다. -## Two references +## 두 개의 참조 -Now let's imagine we copied the reference from `user` to `admin`: +이제 우리가 `user`의 참조를 `admin`에 복사했다고 가정해봅시다.: ```js -// user has a reference to the object +// user는 객체에 대한 참조를 갖고 있습니다. let user = { name: "John" }; @@ -69,16 +69,16 @@ let admin = user; ![](memory-user-john-admin.png) -Now if we do the same: +이제 우리가 이 코드를 실행한다면: ```js user = null; ``` -...Then the object is still reachable via `admin` global variable, so it's in memory. If we overwrite `admin` too, then it can be removed. +...전역 변수 `admin`을 통해 여전히 객체에 접근할 수 있습니다. 따라서 객체는 메모리 안에 존재합니다. 만약 `admin`도 다른 값으로 덮어쓴다면, 객체는 삭제될 수 있습니다. -## Interlinked objects +## 서로 연결된 객체 -Now a more complex example. The family: +이제 더 복잡한 예제, family를 살펴봅시다.: ```js function marry(man, woman) { @@ -98,15 +98,15 @@ let family = marry({ }); ``` -Function `marry` "marries" two objects by giving them references to each other and returns a new object that contains them both. +`marry` 함수는 두 객체를 서로 참조하게 하면서 "결혼"시킵니다. 그 다음, 두 객체를 포함한 새로운 객체를 반환합니다. -The resulting memory structure: +결과적으로 메모리 구조는 이렇게 됩니다.: ![](family.png) -As of now, all objects are reachable. +모든 객체는 접근 가능하게 되었습니다. -Now let's remove two references: +이제 두 참조를 지워봅시다.: ```js delete family.father; @@ -115,98 +115,98 @@ delete family.mother.husband; ![](family-delete-refs.png) -It's not enough to delete only one of these two references, because all objects would still be reachable. +모든 객체는 여전히 접근 가능하므로 참조 하나를 지우는 것만으로는 충분하지 않습니다. -But if we delete both, then we can see that John has no incoming reference any more: +그러나 두 참조를 모두 지우면, John에 대한 참조는 더 이상 존재하지 않게 됩니다.: ![](family-no-father.png) -Outgoing references do not matter. Only incoming ones can make an object reachable. So, John is now unreachable and will be removed from the memory with all its data that also became unaccessible. +John에서 외부로 나가는 참조는 문제 되지 않습니다. 외부에서 들어오는 참조만이 객체를 도달 가능한 상태로 만듭니다. 따라서 John은 이제 도달할 수 없으며 접근 불가능한 John의 데이터는 메모리에서 제거될 것입니다. -After garbage collection: +가비지 컬렉션 수행 후 결과는 다음과 같습니다.: ![](family-no-father-2.png) -## Unreachable island +## 도달할 수 없는 섬 -It is possible that the whole island of interlinked objects becomes unreachable and is removed from the memory. +서로 연결된 객체들의 섬 전체가 도달할 수 없게 되어 메모리에서 제거될 수 있습니다. -The source object is the same as above. Then: +다음 예제에서 사용되는 객체는 위 예제와 같습니다.: ```js family = null; ``` -The in-memory picture becomes: +위 코드를 실행하면 메모리 내부는 다음 상태가 됩니다.: ![](family-no-family.png) -This example demonstrates how important the concept of reachability is. +이 예제는 도달 가능성의 개념이 얼마나 중요한지 보여줍니다. -It's obvious that John and Ann are still linked, both have incoming references. But that's not enough. +John과 Ann은 여전히 연결되어 있으며 둘 다 외부에서 들어오는 참조를 갖고 있다는 사실이 명백합니다. 하지만 이것만으로는 충분하지 않습니다. -The former `"family"` object has been unlinked from the root, there's no reference to it any more, so the whole island becomes unreachable and will be removed. +앞서 `"family"` 객체가 루트로부터 연결이 해제되었습니다. 그러므로 이 객체에 대한 참조는 존재하지 않으며 섬 전체가 도달할 수 없게 돼 메모리에서 제거될 것입니다. -## Internal algorithms +## 내부 알고리즘 -The basic garbage collection algorithm is called "mark-and-sweep". +가비지 컬렉션의 기본적인 알고리즘은 "마크 앤 스윕(mark-and-sweep)"이라고 불립니다. -The following "garbage collection" steps are regularly performed: +일반적으로 "가비지 컬렉션"은 다음 단계를 거쳐 수행됩니다.: -- The garbage collector takes roots and "marks" (remembers) them. -- Then it visits and "marks" all references from them. -- Then it visits marked objects and marks *their* references. All visited objects are remembered, so as not to visit the same object twice in the future. -- ...And so on until there are unvisited references (reachable from the roots). -- All objects except marked ones are removed. +- 가비지 컬렉터는 루트에 접근하여 그들을 "마크"(기억) 합니다. +- 그리고 루트가 참조하고 있는 모든 것들에 방문하여 "마크" 합니다. +- 이제 마크된 모든 객체에 방문하여 *그들의* 참조에도 마크합니다. 같은 객체를 다시 방문하지 않기 위해 방문한 모든 객체는 기억됩니다. +- ...(루트로부터 도달 가능하며) 방문하지 않은 참조가 있다면 위 과정을 반복 수행합니다. +- 마크되지 않은 모든 객체는 삭제됩니다. -For instance, let our object structure look like this: +예를 들어 다음과 같은 객체 구조가 있다고 해봅시다.: ![](garbage-collection-1.png) -We can clearly see an "unreachable island" to the right side. Now let's see how "mark-and-sweep" garbage collector deals with it. +오른편에 있는 "도달할 수 없는 섬"을 발견할 수 있습니다. 이제 가비지 컬렉터의 "마크 앤 스윕" 알고리즘이 이것을 어떻게 처리하는지 알아봅시다. -The first step marks the roots: +루트를 마크하는 첫 번째 단계입니다.: ![](garbage-collection-2.png) -Then their references are marked: +이후 루트가 참조하고 있는 것들을 마크합니다.: ![](garbage-collection-3.png) -...And their references, while possible: +...그리고 나서 그것들이 참조하고 있는 것들을 마크합니다. 가능한 범위에서 이 과정을 반복합니다.: ![](garbage-collection-4.png) -Now the objects that could not be visited in the process are considered unreachable and will be removed: +이 과정에서 방문할 수 없는 객체들은 도달 불가능한 것으로 여겨져 메모리에서 삭제될 것입니다.: ![](garbage-collection-5.png) -That's the concept of how garbage collection works. +이것이 바로 가비지 컬렉션이 작동하는 개념입니다. -JavaScript engines apply many optimizations to make it run faster and not affect the execution. +자바스크립트 엔진은 가비지 컬렉션의 실행에 영향을 주지 않으면서 이것이 빠르게 작동할 수 있도록 여러 가지 최적화를 적용합니다. -Some of the optimizations: +최적화의 예시: -- **Generational collection** -- objects are split into two sets: "new ones" and "old ones". Many objects appear, do their job and die fast, they can be cleaned up aggressively. Those that survive for long enough, become "old" and are examined less often. -- **Incremental collection** -- if there are many objects, and we try to walk and mark the whole object set at once, it may take some time and introduce visible delays in the execution. So the engine tries to split the garbage collection into pieces. Then the pieces are executed one by one, separately. That requires some extra bookkeeping between them to track changes, but we have many tiny delays instead of a big one. -- **Idle-time collection** -- the garbage collector tries to run only while the CPU is idle, to reduce the possible effect on the execution. +- **세대별 수집(Generational collection)** -- 객체는 "새로운 객체"와 "오래된 객체" 두 집합으로 나뉩니다. 많은 객체는 생겨난 다음 제 일을 수행하고 빠르게 죽습니다. 이 객체들은 인정사정없이 제거될 수 있습니다. 반면 충분히 오랫동안 살아남은 객체들은 "오래된 객체"가 되어 가비지 컬렉터에게 덜 검사를 받게 됩니다. +- **점진적 수집(Incremental collection)** -- 많은 객체가 있을 때 모든 객체 집합을 한 번에 방문해 마크하려고 한다면, 시간이 꽤 걸릴 것이며 수행 시간을 확연히 늦출 수 있습니다. 따라서 자바스크립트 엔진은 가비지 컬렉션을 여러 부분으로 나눠 수행하고자 합니다. 부분 작업은 하나씩 별도로 수행됩니다. 부분 작업 사이에서 발생한 변경사항을 추적하기 위해 추가적인 기록이 필요합니다. 그러나 한 번의 큰 지연 대신 여러 번의 작은 지연을 갖게 됩니다. +- **유휴 시간 수집(Idle-time collection)** -- 가비지 컬렉터는 실행에 끼칠 수 있는 영향을 줄이기 위해 CPU가 유휴 상태일 때에만 실행됩니다. -There are other optimizations and flavours of garbage collection algorithms. As much as I'd like to describe them here, I have to hold off, because different engines implement different tweaks and techniques. And, what's even more important, things change as engines develop, so going deeper "in advance", without a real need is probably not worth that. Unless, of course, it is a matter of pure interest, then there will be some links for you below. +이외에도 가비지 컬렉션의 여러 알고리즘과 최적화 기법이 존재합니다. 이에 관해 설명해드리고 싶지만 여기서 멈추는 게 좋을 것 같습니다. 다양한 엔진들은 저마다 다른 기술을 사용하기 때문입니다. 훨씬 더 중요한 것은, 엔진이 발전함에 따라 모든 것은 변화한다는 것입니다. 그러므로 실제로 필요하지 않는데도 "미리" 깊은 내용으로 들어가는 것은 그만한 가치가 없을 것입니다. 물론, 그게 아니라 순수한 관심이 있다면 아래에 있는 링크를 확인해보세요. -## Summary +## 요약 -The main things to know: +알아야 하는 핵심 사항은 다음과 같습니다.: -- Garbage collection is performed automatically. We cannot force or prevent it. -- Objects are retained in memory while they are reachable. -- Being referenced is not the same as being reachable (from a root): a pack of interlinked objects can become unreachable as a whole. +- 가비지 컬렉션은 자동으로 수행됩니다. 우리가 실행시키거나 막을 수 없습니다. +- 객체들은 도달 가능한 상태일 때 메모리에 저장돼 있습니다. +- 참조된다는 것은 (루트로부터) 도달 가능하다는 것이 아닙니다.: 서로 연결된 객체들의 pack은 전체적으로 도달 불가능해질 수도 있습니다. -Modern engines implement advanced algorithms of garbage collection. +현대의 엔진은 더욱 발전된 가비지 컬렉션 알고리즘을 구현합니다. -A general book "The Garbage Collection Handbook: The Art of Automatic Memory Management" (R. Jones et al) covers some of them. +"The Garbage Collection Handbook: The Art of Automatic Memory Management" (R. Jones et al) 책에서 이와 관련된 전반적인 내용을 다룹니다. -If you are familiar with low-level programming, the more detailed information about V8 garbage collector is in the article [A tour of V8: Garbage Collection](http://jayconrod.com/posts/55/a-tour-of-v8-garbage-collection). +만약 여러분이 로우 레벨 프로그래밍에 익숙하시다면, V8 가비지 컬렉터에 대한 더욱 자세한 내용은 이 글 [A tour of V8: Garbage Collection](http://jayconrod.com/posts/55/a-tour-of-v8-garbage-collection) 에서 확인하실 수 있습니다. -[V8 blog](http://v8project.blogspot.com/) also publishes articles about changes in memory management from time to time. Naturally, to learn the garbage collection, you'd better prepare by learning about V8 internals in general and read the blog of [Vyacheslav Egorov](http://mrale.ph) who worked as one of V8 engineers. I'm saying: "V8", because it is best covered with articles in the internet. For other engines, many approaches are similar, but garbage collection differs in many aspects. +[V8 blog](http://v8project.blogspot.com/)는 종종 메모리 관리의 변화에 대한 글들을 게재합니다. 자연스럽게 가비지 컬렉션을 공부하기 위해서는 V8의 내부구조를 공부하거나 V8의 엔지니어로 일했던 [Vyacheslav Egorov](http://mrale.ph) 의 블로그를 읽는 것이 좋습니다. 제가 "V8"을 언급하는 이유는 인터넷에 이에 관해 잘 다룬 글들이 있기 때문입니다. 다른 엔진들은 여러 접근 방법이 V8과 비슷하지만, 가비지 컬렉션에서는 많은 차이가 있습니다. -In-depth knowledge of engines is good when you need low-level optimizations. It would be wise to plan that as the next step after you're familiar with the language. +로우 레벨의 최적화가 필요한 상황이라면 엔진에 대한 깊은 지식은 좋습니다. 그렇지 않다면 우선 자바스크립트에 익숙해진 뒤에 그다음 단계로 엔진에 대해 공부하는 것이 좋습니다. \ No newline at end of file diff --git a/1-js/04-object-basics/03-symbol/article.md b/1-js/04-object-basics/03-symbol/article.md index b433676234..d0b94b6aeb 100644 --- a/1-js/04-object-basics/03-symbol/article.md +++ b/1-js/04-object-basics/03-symbol/article.md @@ -1,31 +1,31 @@ -# Symbol type +# 심볼 타입 -By specification, object property keys may be either of string type, or of symbol type. Not numbers, not booleans, only strings or symbols, these two types. +명세에 따르면 객체의 프로퍼티 키는 문자열 타입이나 심볼 타입이 될 수 있습니다. 숫자나 불리언 타입은 불가능하며 오직 문자열과 심볼 두 타입만 가능합니다. -Till now we've only seen strings. Now let's see the advantages that symbols can give us. +지금까지 우리는 오직 문자열만 봐왔습니다. 이제 심볼이 우리에게 가져다 줄 수 있는 이점들을 알아봅시다. -## Symbols +## 심볼(Symbols) -"Symbol" value represents a unique identifier. +"심볼(Symbol)" 값은 유일한 식별자(unique identifier)를 나타냅니다. -A value of this type can be created using `Symbol()`: +심볼 값은 `Symbol()`를 통해 만들어집니다.: ```js -// id is a new symbol +// id는 새로운 심볼입니다. let id = Symbol(); ``` -We can also give symbol a description (also called a symbol name), mostly useful for debugging purposes: +우리는 심볼에 설명(심볼 이름이라고도 불립니다)을 붙일 수도 있습니다. 주로 디버깅을 할 때 유용하게 쓰입니다.: ```js -// id is a symbol with the description "id" +// id는 "id"라는 설명을 가진 심볼입니다. let id = Symbol("id"); ``` -Symbols are guaranteed to be unique. Even if we create many symbols with the same description, they are different values. The description is just a label that doesn't affect anything. +심볼은 유일하다는 것이 보장됩니다. 우리가 같은 설명을 가진 많은 심볼을 만들지라도, 그 심볼들은 다른 값을 가집니다. 설명은 어떤 것에도 영향을 주지 않는 단지 라벨일 뿐입니다. -For instance, here are two symbols with the same description -- they are not equal: +예를 들어, 여기에 같은 설명을 가진 두 심볼이 있습니다. -- 이들은 같지 않습니다.: ```js run let id1 = Symbol("id"); @@ -36,12 +36,12 @@ alert(id1 == id2); // false */!* ``` -If you are familiar with Ruby or another language that also has some sort of "symbols" -- please don't be misguided. JavaScript symbols are different. +당신이 루비(Ruby)나 "심볼"과 비슷한 것을 가진 다른 언어와 친숙하다면 -- 잘못 이해하면 안됩니다. 자바스크립트의 심볼은 다릅니다. -````warn header="Symbols don't auto-convert to a string" -Most values in JavaScript support implicit conversion to a string. For instance, we can `alert` almost any value, and it will work. Symbols are special. They don't auto-convert. +````warn header="심볼은 문자열로 자동 변환되지 않습니다." +자바스크립트의 대부분의 값은 문자열로의 암시적 형 변환을 지원합니다. 예를 들어, 우리는 어느 값에나 `alert`를 사용할 수 있으며 이것은 잘 실행될 것입니다. 심볼은 특별합니다. 심볼은 자동 변환되지 않습니다. -For instance, this `alert` will show an error: +예를 들어, 이 코드의 `alert`는 에러를 일으킬 것입니다.: ```js run let id = Symbol("id"); @@ -50,22 +50,22 @@ alert(id); // TypeError: Cannot convert a Symbol value to a string */!* ``` -If we really want to show a symbol, we need to call `.toString()` on it, like here: +만약 우리가 정말로 심볼을 보여주고 싶다면, 다음과 같이 심볼에 `.toString()` 메서드를 호출해야 합니다.: ```js run let id = Symbol("id"); *!* -alert(id.toString()); // Symbol(id), now it works +alert(id.toString()); // Symbol(id), 이제 잘 실행됩니다. */!* ``` -That's a "language guard" against messing up, because strings and symbols are fundamentally different and should not occasionally convert one into another. +이것은 혼란을 막기 위한 "언어적 보호장치(language guard)"입니다. 문자열과 심볼은 근본적으로 다르며 서로의 타입으로 종종 변환돼서는 안되기 때문입니다. ```` -## "Hidden" properties +## "숨겨진" 프로퍼티 -Symbols allow us to create "hidden" properties of an object, that no other part of code can occasionally access or overwrite. +심볼은 객체의 "숨겨진" 프로퍼티를 생성할 수 있게 해줍니다. 다른 부분에 있는 어떤 코드도 간혹 숨겨진 프로퍼티에 접근을 하거나 덮어쓰기를 할 수 없습니다. -For instance, if we want to store an "identifier" for the object `user`, we can use a symbol as a key for it: +예를 들어 우리가 `user` 객체를 위해 "식별자"를 저장하고 싶다면, if we want to store an "identifier" for the object `user`, we can use a symbol as a key for it: ```js run let user = { name: "John" }; @@ -108,9 +108,9 @@ user.id = "Their id value" ### Symbols in a literal -If we want to use a symbol in an object literal, we need square brackets. +객체 리터럴에서 심볼을 사용하고 싶다면 대괄호를 사용하면 됩니다. -Like this: +이렇게 말이죠.: ```js let id = Symbol("id"); @@ -124,11 +124,11 @@ let user = { ``` That's because we need the value from the variable `id` as the key, not the string "id". -### Symbols are skipped by for..in +### 심볼은 for..in 에서 배재됩니다. -Symbolic properties do not participate in `for..in` loop. +심볼 프로퍼티는 `for..in` 반복문에 참여하지 않습니다. -For instance: +예를 들어: ```js run let id = Symbol("id"); @@ -253,9 +253,9 @@ For instance, `Symbol.toPrimitive` allows us to describe object to primitive con Other symbols will also become familiar when we study the corresponding language features. -## Summary +## 요약 -`Symbol` is a primitive type for unique identifiers. +`Symbol` 은 유일한 식별자를 위한 is a primitive type for unique identifiers. Symbols are created with `Symbol()` call with an optional description. @@ -263,7 +263,7 @@ Symbols are always different values, even if they have the same name. If we want Symbols have two main use cases: -1. "Hidden" object properties. +1. "숨겨진" 객체 프로퍼티 If we want to add a property into an object that "belongs" to another script or a library, we can create a symbol and use it as a property key. A symbolic property does not appear in `for..in`, so it won't be occasionally listed. Also it won't be accessed directly, because another script does not have our symbol, so it will not occasionally intervene into its actions. So we can "covertly" hide something into objects that we need, but others should not see, using symbolic properties.