diff options
author | Peter Bengtsson <mail@peterbe.com> | 2020-12-08 14:42:17 -0500 |
---|---|---|
committer | Peter Bengtsson <mail@peterbe.com> | 2020-12-08 14:42:17 -0500 |
commit | da78a9e329e272dedb2400b79a3bdeebff387d47 (patch) | |
tree | e6ef8aa7c43556f55ddfe031a01cf0a8fa271bfe /files/ko/learn/javascript | |
parent | 1109132f09d75da9a28b649c7677bb6ce07c40c0 (diff) | |
download | translated-content-da78a9e329e272dedb2400b79a3bdeebff387d47.tar.gz translated-content-da78a9e329e272dedb2400b79a3bdeebff387d47.tar.bz2 translated-content-da78a9e329e272dedb2400b79a3bdeebff387d47.zip |
initial commit
Diffstat (limited to 'files/ko/learn/javascript')
31 files changed, 11078 insertions, 0 deletions
diff --git a/files/ko/learn/javascript/asynchronous/async_await/index.html b/files/ko/learn/javascript/asynchronous/async_await/index.html new file mode 100644 index 0000000000..339a9dabdb --- /dev/null +++ b/files/ko/learn/javascript/asynchronous/async_await/index.html @@ -0,0 +1,383 @@ +--- +title: Making asynchronous programming easier with async and await +slug: Learn/JavaScript/Asynchronous/Async_await +translation_of: Learn/JavaScript/Asynchronous/Async_await +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/JavaScript/Asynchronous/Promises", "Learn/JavaScript/Asynchronous/Choosing_the_right_approach", "Learn/JavaScript/Asynchronous")}}</div> + +<p class="summary">Javascript에 대한 최신 추가 사항은 ECMAScript 2017 JavaScript 에디션의 일부인 <a href="/en-US/docs/Web/JavaScript/Reference/Statements/async_function">async functions</a> 그리고 <code><a href="/en-US/docs/Web/JavaScript/Reference/Operators/await">await</a></code> 키워드 입니다.(<a href="/en-US/docs/Web/JavaScript/New_in_JavaScript/ECMAScript_Next_support_in_Mozilla">ECMAScript Next support in Mozilla</a>를 참조하세요). 이러한 기능들은 Promise기반 코드를 좀 더 쓰기 쉽고 읽기 쉽게 만들어줍니다. 이 기능을 사용하면 비동기 코드를 구식 동기 코드처럼 보여주기 때문에 충분히 배울 가치가 있습니다.이번 문서에서 위의 기능을 어떻게 사용하는지 배울 것 입니다.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Prerequisites:</th> + <td>Basic computer literacy, a reasonable understanding of JavaScript fundamentals, an understanding of async code in general and promises.</td> + </tr> + <tr> + <th scope="row">Objective:</th> + <td>To understand promises and how to use them.</td> + </tr> + </tbody> +</table> + +<h2 id="The_basics_of_asyncawait">The basics of async/await</h2> + +<p>async/await 코드는 두 가지 부분으로 나눠져있습니다.</p> + +<h3 id="The_async_keyword">The async keyword</h3> + +<p>먼저 비 동기 함수를 <a href="/en-US/docs/Web/JavaScript/Reference/Statements/async_function">async function</a>으로 만들기 위하여 function()앞에 <code>async</code> keyword를 추가합니다. async function()은 <code>await</code> 키워드가 비동기 코드를 호출할 수 있게 해주는 함수 입니다.</p> + +<p>브라우저의 JavaScript 콘솔에서 아래와 같이 입력해보세요. :</p> + +<pre class="brush: js notranslate">function hello() { return "Hello" }; +hello();</pre> + +<p>위의 함수는 "Hello"를 반환합니다. — 특별할게 없죠?</p> + +<p>그러면 함수 앞에 async 키워드를 추가하면 어떻게 될까요?? 아래처럼 작성해봅시다.:</p> + +<pre class="brush: js notranslate">async function hello() { return "Hello" }; +hello();</pre> + +<p>이제 코드가 Promise를 반환합니다. 이것이 async 기능의 특징 중 하나 입니다. — 이 키워드를 사용하면 반환받는 값은 Promise가 됩니다..</p> + +<p><a href="/en-US/docs/Web/JavaScript/Reference/Operators/async_function">async function expression</a>을 사용하여 아래와 같이 만들 수도 있습니다. :</p> + +<pre class="brush: js notranslate">let hello = async function() { return "Hello" }; +hello();</pre> + +<p>화살표 함수를 사용하면 아래처럼 쓸 수 있습니다. :</p> + +<pre class="brush: js notranslate">let hello = async () => { return "Hello" };</pre> + +<p>기본적으로 두 가지는 모두 같습니다.</p> + +<p>실제로는 fulfil Promise가 반환되기 때문에 반환된 값을 사용하기 위해선 <code>.then()</code> 블럭을 사용해야 합니다. :</p> + +<pre class="brush: js notranslate">hello().then((value) => console.log(value))</pre> + +<p>짧개 표현하면 아래와 같이 쓸 수 있습니다.</p> + +<pre class="brush: js notranslate">hello().then(console.log)</pre> + +<p>이전에 봤던 내용과 비슷하죠?.</p> + +<p>정리하면, <code>async</code> 를 함수와 같이 사용하면 결과를 직접 반환하는게 아니라 Promise를 반환하게 합니다. 또한 동기식 함수는 <code>await</code>사용을 위한 지원과 함께 실행되는 잠재적인 오버헤드를 피할 수 있습니다. 함수가 <code>async</code>라고 선언될 때 필요한 핸들링만 추가하면 JavaScript엔진이 우리가 만든 프로그램을 최적화 할 수 있습니다. 끝내주죠?</p> + +<h3 id="The_await_keyword">The await keyword</h3> + +<p>비동기 함수를 <a href="/en-US/docs/Web/JavaScript/Reference/Operators/await">await</a> 키워드와 함께 쓰면 그 장점이 확실히 보입니다. 이것은 어떠한 Promise기반 함수 앞에 놓을 수 있습니다. 그리고 우리의 코드의 Promise가 fulfil될 때 까지 잠시 중단하고, 결과를 반환합니다. 그리고 실행을 기다리는 다른 코드들을 중지시키지 않고 그대로 실행되게 합니다.</p> + +<p><code>await</code> 키워드는 웹 API를 포함하여 Promise를 반환하는 함수를 호출할 때 사용할 수 있습니다.</p> + +<p>여기 간단한 예가 있습니다. :</p> + +<pre class="brush: js notranslate">async function hello() { + return greeting = await Promise.resolve("Hello"); +}; + +hello().then(alert);</pre> + +<p>물론 위의 예시는 그다지 쓸모있진 않습니다. 다만 어떻게 구문을 작성해야 하는지는 잘 나타내줍니다. 이제 실제 사례를 살펴봅시다.</p> + +<h2 id="Rewriting_promise_code_with_asyncawait">Rewriting promise code with async/await</h2> + +<p>이전 문서에서 봤던 간단한 fetch() 예제를 살펴봅시다. :</p> + +<pre class="brush: js notranslate">fetch('coffee.jpg') +.then(response => response.blob()) +.then(myBlob => { + let objectURL = URL.createObjectURL(myBlob); + let image = document.createElement('img'); + image.src = objectURL; + document.body.appendChild(image); +}) +.catch(e => { + console.log('There has been a problem with your fetch operation: ' + e.message); +});</pre> + +<p>지금 시점에서 우리는 Promise가 어떻게 작동하는지 잘 이해하고 있습니다. 그렇다면 지금부터 이 예제를 async/await 를 사용하여 더 간단하게 만들어봅시다. :</p> + +<pre class="brush: js notranslate">async function myFetch() { + let response = await fetch('coffee.jpg'); + let myBlob = await response.blob(); + + let objectURL = URL.createObjectURL(myBlob); + let image = document.createElement('img'); + image.src = objectURL; + document.body.appendChild(image); +} + +myFetch() +.catch(e => { + console.log('There has been a problem with your fetch operation: ' + e.message); +});</pre> + +<p>바꾸고 나니 더 이해하기 쉬워졌습니다. — 더 이상의 <code>.then()</code> 블럭은 찾아 볼 수 없습니다.</p> + +<p><code>async</code> 키워드가 함수를 Promise로 바꾸었기, 이제 promise 와 await의 하이브리드 접근방식을 사용하기 위해 코드를 리팩토링 할 수 있으며, 두 번째 <code>.then()</code>블럭을 함수 내부의 블럭으로 가져와 더 유연하게 만들 수 있습니다.</p> + +<pre class="brush: js notranslate">async function myFetch() { + let response = await fetch('coffee.jpg'); + return await response.blob(); +} + +myFetch().then((blob) => { + let objectURL = URL.createObjectURL(blob); + let image = document.createElement('img'); + image.src = objectURL; + document.body.appendChild(image); +}).catch(e => console.log(e));</pre> + +<p>예제를 직접 만들어보거나, 여기서 결과를 확인할 수 있습니다. <a href="https://mdn.github.io/learning-area/javascript/asynchronous/async-await/simple-fetch-async-await.html">live example</a> (see also the <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/async-await/simple-fetch-async-await.html">source code</a>).</p> + +<h3 id="But_how_does_it_work">But how does it work?</h3> + +<p>함수 안에 코드를 작성했고, <code>function</code> 키워드 앞에 <code>async</code> 키워드를 썼다는 것을 알 수 있습니다. 꼭 이렇게 써야합니다!! 비동기 코드를 실행할 블럭을 정의하려면 비동기 함수를 생성해야 합니다. <code>await</code>는 <code>async function</code> 안에서만 쓸 수 있습니다.</p> + +<div class="blockIndicator note"> +<p><strong>Note:</strong> It's worth saying again, in a box with an eye-catching background color: <code>await</code> only works inside async functions.</p> +</div> + +<p><code>myFetch()</code> 함수 내에 코드가 이전의 Promise버전과 매우 유사하지만, 다른점이 있습니다. <code>.then()</code>블럭을 사용하여 작업을 이어가는 대신 메서드 호출 전에 <code>await</code> 키워드를 사용하여 반환된 결과를 변수에 할당합니다. <code>await</code> 키워드는 JavaScript 런타임이 이 라인에서 비동기 코드를 일시 중지하여 비동기 함수 호출이 결과를 반환할 때 까지 기다리게 합니다. 그러나 외부의 다른 동기 코드는 실행될 수 있도록 합니다. 작업이 완료되면 코드는 계속 이어져서 실행됩니다. 예를들면 아래와 같습니다. :</p> + +<pre class="brush: js notranslate">let response = await fetch('coffee.jpg');</pre> + +<p>fullfilled된 <code>fetch()</code> Promise에서 반환된 응답은 해당 응답이 사용할 수 있게 되면 <code>response</code> 변수에 할당됩니다. 그리고 parser는 해당 응답이 발생할 때 까지 이 라인에서 일시 중지됩니다. response가 사용 가능하게 되면, parser 는 다음 라인으로 이동하게 되고 그 라인에서 <code><a href="/en-US/docs/Web/API/Blob">Blob</a></code> 을 생성하게 됩니다. 이라인도 Promise기반 비동기 메서드를 호출하므로, 여기서도<code>await</code> 을 사용합니다. 비동기 작업 결과가 반환되면, <code>myFetch()</code> 함수가 그 결과를 반환합니다.</p> + +<p><code>myFetch()</code> 함수를 호출하면, Promise를 반환하므로, 따라서 화면에 Blob을 표시해주는 <code>.then()</code> 코드 블럭 체이닝 할 수 있습니다.</p> + +<p>여기까지 왔으면 이 방법이 멋있다고 생각해야합니다! 왜냐하면 <code>.then()</code> 블럭이 줄어들고 대부분이 동기 코드처럼 보이기 때문에 정말 직관적입니다.</p> + +<h3 id="Adding_error_handling">Adding error handling</h3> + +<p>그리고 오류 처리를 하려면 몇 가지 옵션이 있습니다.</p> + +<p>동기식 코드에서 쓰는 <code><a href="/en-US/docs/Web/JavaScript/Reference/Statements/try...catch">try...catch</a></code> 구문을 <code>async</code>/<code>await</code>구조에서 사용할 수 있습니다. 이 예제는 위에서 설명한 첫 번째 코드를 수정한 것 입니다. :</p> + +<pre class="brush: js notranslate">async function myFetch() { + try { + let response = await fetch('coffee.jpg'); + let myBlob = await response.blob(); + + let objectURL = URL.createObjectURL(myBlob); + let image = document.createElement('img'); + image.src = objectURL; + document.body.appendChild(image); + } catch(e) { + console.log(e); + } +} + +myFetch();</pre> + +<p><code>catch() {}</code> 블록은 <code>e</code> 라고 부르는 에러 오브젝트를 통과시킵니다. 이제 콘솔에 코드가 던져준 에러 메시지를 출력할 수 있습니다.</p> + +<p>아래 코드는 처음 예제를 리팩토링한 두 번째 버전의 코드 입니다. 이 하이브리드 접근법을 사용하는 코드에서 에러를 탐지하고 싶으면 <code>.catch()</code> 블럭을 <code>.then()</code> 호출의 마지막에 작성합니다. :</p> + +<pre class="brush: js notranslate">async function myFetch() { + let response = await fetch('coffee.jpg'); + return await response.blob(); +} + +myFetch().then((blob) => { + let objectURL = URL.createObjectURL(blob); + let image = document.createElement('img'); + image.src = objectURL; + document.body.appendChild(image); +}) +.catch((e) => + console.log(e) +);</pre> + +<p>이는 <code>.catch()</code> 블럭이 async 함수 호출과 Promise 체인 모두에서 발생하는 오류를 잡을 수 있기 때문입니다. 여기서 <code>try</code>/<code>catch</code> 블럭을 사용했더라도, <code>myFetch()</code> 에서 발생한 unhandled에러를 잡아낼 수 있습니다.</p> + +<p>위의 예제 모두를 GitHub에서 찾아볼 수 있습니다. :</p> + +<ul> + <li><a href="https://mdn.github.io/learning-area/javascript/asynchronous/async-await/simple-fetch-async-await-try-catch.html">simple-fetch-async-await-try-catch.html</a> (see <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/async-await/simple-fetch-async-await-try-catch.html">source code</a>)</li> + <li><a href="https://mdn.github.io/learning-area/javascript/asynchronous/async-await/simple-fetch-async-await-promise-catch.html">simple-fetch-async-await-promise-catch.html</a> (see <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/async-await/simple-fetch-async-await-promise-catch.html">source code</a>)</li> +</ul> + +<h2 id="Awaiting_a_Promise.all">Awaiting a Promise.all()</h2> + +<p>async/await는 <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise">promises</a>의 상위에 만들어져 있기 때문에 Promise의 모든 기능을 사용할 수 있습니다. <code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all">Promise.all()</a></code> 을 포함해서 말이죠 — 아래 보이는 코드처럼 <code>Promise.all()</code> 앞에 <font face="consolas, Liberation Mono, courier, monospace"><span style="background-color: rgba(220, 220, 220, 0.5);">async</span></font>키워드를 사용하여 동기식 코드처럼 작성할 수 있습니다. 이전 문서를 확인해봅시다. <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/promises/promise-all.html">an example we saw in our previous article</a>. 새로운 버전과 비교하기 위해 탭을 분리 해보세요.</p> + +<p>Aasync/await 스타일로 변경한 코드는 아래와 같습니다. (see <a href="https://mdn.github.io/learning-area/javascript/asynchronous/async-await/promise-all-async-await.html">live demo</a> and <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/async-await/promise-all-async-await.html">source code</a>) :</p> + +<pre class="brush: js notranslate">async function fetchAndDecode(url, type) { + let response = await fetch(url); + + let content; + + if(type === 'blob') { + content = await response.blob(); + } else if(type === 'text') { + content = await response.text(); + } + + return content; +} + +async function displayContent() { + let coffee = fetchAndDecode('coffee.jpg', 'blob'); + let tea = fetchAndDecode('tea.jpg', 'blob'); + let description = fetchAndDecode('description.txt', 'text'); + + let values = await Promise.all([coffee, tea, description]); + + let objectURL1 = URL.createObjectURL(values[0]); + let objectURL2 = URL.createObjectURL(values[1]); + let descText = values[2]; + + let image1 = document.createElement('img'); + let image2 = document.createElement('img'); + image1.src = objectURL1; + image2.src = objectURL2; + document.body.appendChild(image1); + document.body.appendChild(image2); + + let para = document.createElement('p'); + para.textContent = descText; + document.body.appendChild(para); +} + +displayContent() +.catch((e) => + console.log(e) +);</pre> + +<p>몇 가지 사항을 조금 수정했을 뿐인데 <code>fetchAndDecode()</code>함수를 쉽게 비동기 함수로 변환했습니다. <code>Promise.all()</code> 라인을 살펴보세요:</p> + +<pre class="brush: js notranslate">let values = await Promise.all([coffee, tea, description]);</pre> + +<p>여기에 <code>await</code> 을 사용하여 세 가지 Promise의 결과가 반환되었을 때 <code>values</code> 배열에 담을 수 있습니다. 그리고 마치 동기화 코드처럼 보이죠. 우리가 작업한건 <code>displayContent()</code>에 <font face="consolas, Liberation Mono, courier, monospace"><span style="background-color: rgba(220, 220, 220, 0.5);">async</span></font>키워드를 추가하고, 모든 코드를<code>.then()</code> 블럭 바깥으로 빼냈습니다. 또한 아주 적은양의 코드 수정도 했죠. 이렇게 하니 더 단순하고, 유용하고 읽기 쉬운 프로그램이 되었습니다.</p> + +<p>마지막으로 에러를 다루기 위해 <code>.catch()</code> 블럭을 <code>displayContent()</code> 함수를 호출하는 곳에 추가했습니다. 이렇게 하면 두 함수에서 발생하는 에러를 처리할 수 있습니다.</p> + +<div class="blockIndicator note"> +<p><strong>Note</strong>: It is also possible to use a sync <code><a href="/en-US/docs/Web/JavaScript/Reference/Statements/try...catch#The_finally_clause">finally</a></code> block within an async function, in place of a <code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/finally">.finally()</a></code> async block, to show a final report on how the operation went — you can see this in action in our <a href="https://mdn.github.io/learning-area/javascript/asynchronous/async-await/promise-finally-async-await.html">live example</a> (see also the <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/async-await/promise-finally-async-await.html">source code</a>).</p> +</div> + +<h2 id="The_downsides_of_asyncawait">The downsides of async/await</h2> + +<p>앞서 봤듯이 async/await 은매우 유용하지만 고려해야 할 몇 가지 단점이 있습니다.</p> + +<p>Async/await 는 우리의 코드를 마치 동기식 코드처럼 보이게 합니다. 그리고 어떤 면에서는 정말로 동기적으로 행동합니다. 함수 블럭에 여러 개의 <code>await</code> 키워드를 사용하면 Promise가 fulfilled되기 전 까지 다음 <code>await</code> 을 차단합니다. 그 동안 다른 태스크는 계속 실행이 되지만 정의한 함수 내에서는 동기적으로 작동할 것 입니다.</p> + +<p>이 말은 우리가 작성한 코드가 바로 이어지는 수 많은 Promise에 의해 느려질 수 있다는 것을 의미합니다. 각 <code>await</code> 는 이전의 작업이 끝날 때 까지 기다립니다(Promise 체이닝과 혼동하지 마세요). 그런데 우리가 원하는건 기다리는게 아니고 일제히 실행되는 것 입니다.</p> + +<p>이 문제를 완화할 수 있는 패턴이 있습니다. — 모든 <code>Promise</code> 오브젝트를 변수에 저장하여 미리 실행되게 하고 변수가 사용 가능할 때 꺼내서 쓰는 것 입니다. 어떻게 작동하는지 한번 살펴봅시다.</p> + +<p>두 가지 예시를 보여주겠습니다. — 느린 비동기 작업 <a href="https://mdn.github.io/learning-area/javascript/asynchronous/async-await/slow-async-await.html">slow-async-await.html</a> (see <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/async-await/slow-async-await.html">source code</a>) 그리고 빠른 비동기 작업 <a href="https://mdn.github.io/learning-area/javascript/asynchronous/async-await/fast-async-await.html">fast-async-await.html</a> (see <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/async-await/fast-async-await.html">source code</a>)입니다. 두 예제에서 마치 비동기 작업인 것 처럼 보이기 위해 <code><a href="/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setTimeout">setTimeout()</a></code> 을 사용했습니다. :</p> + +<pre class="brush: js notranslate">function timeoutPromise(interval) { + return new Promise((resolve, reject) => { + setTimeout(function(){ + resolve("done"); + }, interval); + }); +};</pre> + +<p>그리고 세 가지 <code>timeoutPromise()</code> 함수를 호출하는 <code>timeTest()</code>함수를 만들었습니다.</p> + +<pre class="brush: js notranslate">async function timeTest() { + ... +}</pre> + +<p>그리고 두 개 예제 모두 시작 시간을 기록하고, <code>timeTest()</code> Promise가 fulfilled된 시간을 저장하여 두 시간의 차를 계산해 작업이 얼마나 걸렸는지 사용자에게 보여줍니다. :</p> + +<pre class="brush: js notranslate">let startTime = Date.now(); +timeTest().then(() => { + let finishTime = Date.now(); + let timeTaken = finishTime - startTime; + alert("Time taken in milliseconds: " + timeTaken); +})</pre> + +<p><code>timeTest()</code> 함수만 두 예제에서 차이가 있습니다.</p> + +<p><code>slow-async-await.html</code> 예제이서, <code>timeTest()</code> 함수는 아래와 같이 생겼습니다. :</p> + +<pre class="brush: js notranslate">async function timeTest() { + await timeoutPromise(3000); + await timeoutPromise(3000); + await timeoutPromise(3000); +}</pre> + +<p>아주 간단하게 <code>timeoutPromise()</code> 함수를 직접 호출했습니다. 각 작업은 3초씩 걸립니다. 그리고 <font face="consolas, Liberation Mono, courier, monospace"><span style="background-color: rgba(220, 220, 220, 0.5);">await</span></font> 키워드를 사용했기 때문에 이전 await 작업이 끝나야 다음으로 진행됩니다. — 첫 번째 예제를 실행하면, alert 박스에서 약 9초(9000밀리초)가 걸렸음을 확인할 수 있습니다.</p> + +<p>다음으로 <code>fast-async-await.html</code> 예제이서, <code>timeTest()</code> 은 아래와 같이 생겼습니다. :</p> + +<pre class="brush: js notranslate">async function timeTest() { + const timeoutPromise1 = timeoutPromise(3000); + const timeoutPromise2 = timeoutPromise(3000); + const timeoutPromise3 = timeoutPromise(3000); + + await timeoutPromise1; + await timeoutPromise2; + await timeoutPromise3; +}</pre> + +<p>여기선 세 가지 <code>Promise</code> 오브젝트를 변수에 저장하여 동시에 작업을 시작하도록 했습니다.</p> + +<p>그리고 그 변수에 await을 사용하여 결과를 호출합니다. — 작업이 거의 동시에 시작됐기 때문에, Promise도 거의 동시에 fulfilled될 것 입니다. 두 번째 예제를 실행하면 거의 3초(3000밀리초) 만에 작업이 끝났음을 확인할 수 있습니다.</p> + +<p>코드를 주의깊게 테스트 하고, 성능이 떨어지기 시작하면 위의 상황을 의심해봐야 합니다.</p> + +<p>다른 아주 사소한 단점은 비동기로 실행될 Promise가 있다면 async함수 안에 항상 await을 써야한다는 것 입니다.</p> + +<h2 id="Asyncawait_class_methods">Async/await class methods</h2> + +<p>마지막으로 보여줄 내용은 <code>async</code> 키워드를 class/object의 메서드에 사용하여 Promise를 반환하게 만들 수 있다는 것 입니다. 그리고 <code>await</code> 를 그 안에 넣을 수도 있습니다. 다음 문서를 살펴보세요 > <a href="/en-US/docs/Learn/JavaScript/Objects/Inheritance#ECMAScript_2015_Classes">ES class code we saw in our object-oriented JavaScript article</a>, 그리고 보이는 코드를<code>async</code> 메서드로 수정한 아래의 내용과 비교 해보세요 :</p> + +<pre class="brush: js notranslate">class Person { + constructor(first, last, age, gender, interests) { + this.name = { + first, + last + }; + this.age = age; + this.gender = gender; + this.interests = interests; + } + + async greeting() { + return await Promise.resolve(`Hi! I'm ${this.name.first}`); + }; + + farewell() { + console.log(`${this.name.first} has left the building. Bye for now!`); + }; +} + +let han = new Person('Han', 'Solo', 25, 'male', ['Smuggling']);</pre> + +<p>이제 클래스의 첫 번째 메서드를 아래와 같이 사용할 수 있습니다. :</p> + +<pre class="brush: js notranslate">han.greeting().then(console.log);</pre> + +<h2 id="Browser_support">Browser support</h2> + +<p>One consideration when deciding whether to use async/await is support for older browsers. They are available in modern versions of most browsers, the same as promises; the main support problems come with Internet Explorer and Opera Mini.</p> + +<p>If you want to use async/await but are concerned about older browser support, you could consider using the <a href="https://babeljs.io/">BabelJS</a> library — this allows you to write your applications using the latest JavaScript and let Babel figure out what changes if any are needed for your user’s browsers. On encountering a browser that does not support async/await, Babel's polyfill can automatically provide fallbacks that work in older browsers.</p> + +<h2 id="Conclusion">Conclusion</h2> + +<p>And there you have it — async/await provide a nice, simplified way to write async code that is simpler to read and maintain. Even with browser support being more limited than other async code mechanisms at the time of writing, it is well worth learning and considering for use, both for now and in the future.</p> + +<p>{{PreviousMenuNext("Learn/JavaScript/Asynchronous/Promises", "Learn/JavaScript/Asynchronous/Choosing_the_right_approach", "Learn/JavaScript/Asynchronous")}}</p> + +<h2 id="In_this_module">In this module</h2> + +<ul> + <li><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Concepts">General asynchronous programming concepts</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Introducing">Introducing asynchronous JavaScript</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Timeouts_and_intervals">Cooperative asynchronous JavaScript: Timeouts and intervals</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Promises">Graceful asynchronous programming with Promises</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Async_await">Making asynchronous programming easier with async and await</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Choosing_the_right_approach">Choosing the right approach</a></li> +</ul> diff --git a/files/ko/learn/javascript/asynchronous/concepts/index.html b/files/ko/learn/javascript/asynchronous/concepts/index.html new file mode 100644 index 0000000000..443487fefb --- /dev/null +++ b/files/ko/learn/javascript/asynchronous/concepts/index.html @@ -0,0 +1,159 @@ +--- +title: 일반적인 비동기 프로그래밍 개념 +slug: Learn/JavaScript/Asynchronous/Concepts +tags: + - 비동기 + - 비동기 프로그래밍 + - 자바스크립트 +translation_of: Learn/JavaScript/Asynchronous/Concepts +--- +<div>{{LearnSidebar}}{{NextMenu("Learn/JavaScript/Asynchronous/Introducing", "Learn/JavaScript/Asynchronous")}}</div> + +<p>이 문서에서는 비동기적 프로그래밍과 관련된 몇개의 개념들을 살펴볼 것입니다. 그리고 이것들이 웹브라우저와 자바스크립트에서 어떻게 보이는지도 살펴볼 것입니다. 이 모듈의 다른 문서들을 공부하기 전에, 이 문서에 나와있는 개념들을 먼저 학습하십시오.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">선행 조건:</th> + <td>기초적인 컴퓨터 언어 능력, Javascript에 대한 기초적인 이해가 필요합니다. </td> + </tr> + <tr> + <th scope="row">학습 목적: </th> + <td>비동기적 프로그래밍이 작동하는 기초적인 원리에 대해 이해하는 것입니다. 그리고 이 개념이 어떻게 웹브라우저와 자바스크립트에서 압도적인 지위를 차지하기 되었는지 알아봅니다. </td> + </tr> + </tbody> +</table> + +<h2 id="비동기적Asynchronous_이란">'비동기적'(Asynchronous) 이란?</h2> + +<p>일반적으로, 프로그램의 코드는 순차적으로 진행됩니다. 한번에 한가지 사건만 발생하면서 말입니다. 만약 어떤 함수의 결과가 다른 함수에 영향을 받는다면, 그 함수는 다른 함수가 끝나고 값을 산출할 때까지 기다려야 합니다. 그리고 그 과정이 끝날 때 까지, 유저의 입장에서 보자면, 전체 프로그램이 모두 멈춘 것처럼 보입니다. </p> + +<p>예를들면, 맥 유저라면 종종 회전하는 무지개색 커서(비치볼)를 본 적이 있을 것입니다. 이 커서는 오퍼레이팅 시스템이 이렇게 말하고 있는 것입니다. "당신이 지금 사용하고 있는 시스템은 지금 멈춰서서 뭔가가 끝나기를 기다려야만 합니다. 그리고 이 과정은 당신이 지금 무슨 일이 일어나고있는지 궁금해 할 만큼 오래 걸리고 있습니다."</p> + +<p><img alt="Multi-colored macOS beachball busy spinner" src="https://mdn.mozillademos.org/files/16577/beachball.jpg" style="display: block; float: left; height: 256px; margin: 0px 30px 0px 0px; width: 250px;"></p> + +<p>이것은 당황스러운 경험이며, 특히 요즘과 같이 컴퓨터가 여러개 프로세서를 돌리는 시대에는 컴퓨터 성능을 효율적으로 쓰지 못하는 처사입니다. 당신이 다른 코어 프로세서에 다른 작업들을 움직이게 하고 작업이 완료되면 알려줄 수 있을 때, 무언가를 기다리는 것은 의미가 없습니다 .그 동안 다른 작업을 수행할 수 있고, 이것이 비동기 프로그래밍의 기본입니다. 이러한 작업을 비동기적으로 실행할 수 있는 API를 제공하는 것은 당신이 사용하고 있는 프로그래밍 환경(웹 개발의 경우 웹브라우저) 에 달려 있습니다.</p> + +<h2 id="Blocking_code">Blocking code</h2> + +<p>비동기 기법은 특히 웹 프로그래밍에 매우 유용합니다. 웹 앱이 브라우저에서 특정 코드를 실행하느라 브라우저에게 제어권을 돌려주지 않으면 브라우저는 마치 정지된 것처럼 보일 수 있습니다. 이러한 현상을 <strong>blocking </strong>이라고 부릅니다. 자세히 정의하자면, 사용자의 입력을 처리하느라 웹 앱이 프로세서에 대한 제어권을 브라우저에게 반환하지 않는 현상 입니다..</p> + +<p>Blocking의 몇 가지 예를 살펴보겠습니다.</p> + +<p>여기 <a href="https://github.com/mdn/learning-area/tree/master/javascript/asynchronous/introducing">simple-sync.html</a> 예시가 있습니다. (<a href="https://mdn.github.io/learning-area/javascript/asynchronous/introducing/simple-sync.html">see it running live</a>), 하나의 버튼에 클릭 이벤트리스너를 지정하여 시간이 오래 걸리는 처리를 하도록하였습니다. (날짜를 천만번 계산하고 마지막에 콘솔에 날짜를 출력합니다.) 그리고 처리가 끝나면 페이지에 간단한 문장을 한 줄 출력합니다. :</p> + +<pre class="brush: js notranslate">const btn = document.querySelector('button'); +btn.addEventListener('click', () => { + let myDate; + for(let i = 0; i < 10000000; i++) { + let date = new Date(); + myDate = date + } + + console.log(myDate); + + let pElem = document.createElement('p'); + pElem.textContent = 'This is a newly-added paragraph.'; + document.body.appendChild(pElem); +});</pre> + +<p>이 예제를 실행할 때 JavaScript 콘솔을 열고 버튼을 클릭하면, 콘솔에 메시지가 출력되기 전 까지 페이지에 문장이 나타나지 않는다는 것을 알 수 있습니다. 코드는 위에서 아래로 순차적으로 실행되며, 아래쪽 코드는 위쪽 코드의 처리가 끝날 때 까지 실행되지 않습니다.</p> + +<div class="blockIndicator note"> +<p><strong>Note</strong>: 앞의 예제는 매우 비현실적입니다. 실제 웹 앱에서 날짜를 천만번 계산할 일은 없습니다. 실제로 보여주기 위해 극단적인 예시를 들었을 뿐입니다..</p> +</div> + +<p>두 번째 예제를 살펴보겠습니다. <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/introducing/simple-sync-ui-blocking.html">simple-sync-ui-blocking.html</a> (<a href="https://mdn.github.io/learning-area/javascript/asynchronous/introducing/simple-sync-ui-blocking.html">see it live</a>), 페이지에 UI가 모두 표시되기 전 까지 사용자의 입력을 막는 좀 더 현실적인 예시입니다. 이번 예시에는 두 가지 버튼을 사용합니다. :</p> + +<ul> + <li>"Fill canvas" 버튼을 클릭하면 {{htmlelement("canvas")}} 태그에 100만개의 파란색 원을 채웁니다. (실행하면 원이 너무 많아서 원이 아니라 배경이 그냥 파란색으로 채워집니다.)</li> + <li>"Click me for alert" 버튼은 사용자에게 메시지를 출력합니다.</li> +</ul> + +<pre class="brush: js notranslate">function expensiveOperation() { + for(let i = 0; i < 1000000; i++) { + ctx.fillStyle = 'rgba(0,0,255, 0.2)'; + ctx.beginPath(); + ctx.arc(random(0, canvas.width), random(0, canvas.height), 10, degToRad(0), degToRad(360), false); + ctx.fill() + } +} + +fillBtn.addEventListener('click', expensiveOperation); + +alertBtn.addEventListener('click', () => + alert('You clicked me!') +);</pre> + +<p>첫 번째 버튼을 클릭한 후 두 번째 버튼을 바로 클릭하면 경고 박스가 나타나지 않는 것을 확인할 수 있습니다. 첫 번째 버튼은 이벤트가 끝나기 전 까지 다음 작동을 막아버립니다.</p> + +<div class="blockIndicator note"> +<p><strong>Note</strong>: OK, in our case, it is ugly and we are faking the blocking effect, but this is a common problem that developers of real apps fight to mitigate all the time.</p> +</div> + +<p>왜 이런 현상이 발생할까요? 답은 자바스크립트는 기본적으로 <strong>single threaded</strong>이기 때문입니다. 이 시점에서 <strong>threads</strong>의 개념을 소개할 필요가 있겠군요</p> + +<h2 id="Threads">Threads</h2> + +<p><strong>Thread</strong> 는 기본적으로 프로그램이 작업을 완료하는데 사용할 수 있는 단일 프로세스 입니다. 각 스레드는 한 번에 하나의 작업만 수행할 수 있습니다. :</p> + +<pre class="notranslate">Task A --> Task B --> Task C</pre> + +<p>위의 예시처럼 각 작업은 순차적으로 실행되며, 다음 작업을 시작하려면 앞의 작업이 완료되어야 합니다.</p> + +<p>앞서 말했듯이, 많은 컴퓨터들이 현재 여러 개의 CPU코어를 가지고 있기 때문에, 한 번에 여러가지 일을 수행할 수 있습니다. Multiple thread를 지원하는 프로그래밍 언어는 멀티코어 컴퓨터의 CPU를 사용하여 여러 작업을 동시에 처리할 수 있습니다. :</p> + +<pre class="notranslate">Thread 1: Task A --> Task B +Thread 2: Task C --> Task D</pre> + +<h3 id="JavaScript_is_single_threaded">JavaScript is single threaded</h3> + +<p>자바스크립트는 전통적으로 싱글 thread입니다. 컴퓨터가 여러 개의 CPU를 가지고 있어도 <strong>main thread</strong>라 불리는 단일 thread에서만 작업을 실행할 수 있습니다. 위의 예시는 아래처럼 실행됩니다. :</p> + +<pre class="notranslate">Main thread: Render circles to canvas --> Display alert()</pre> + +<p>JavaScript는 이러한 문제를 해결하기 위해 몇 가지 툴을 도입했습니다. <a href="https://wiki.developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API">Web workers</a>는 여러 개의 JavaScript 청크를 동시에 실행할 수 있도록 worker라고 불리는 별도의 스레드로 보낼 수 있습니다. 따라서 시간이 오래 걸리는 처리는 woker를 사용해 처리하면 blocking 발생을 막을 수 있습니다..</p> + +<pre class="notranslate"> Main thread: Task A --> Task C +Worker thread: Expensive task B</pre> + +<p>위의 내용을 잘 기억하시고 다음 예제를 살펴보세요. <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/introducing/simple-sync-worker.html">simple-sync-worker.html</a> (<a href="https://mdn.github.io/learning-area/javascript/asynchronous/introducing/simple-sync-worker.html">see it running live</a>), JavaScript 콘솔을 함께 열어주세요. 이전 예시는 날짜를 천만 번 계산하고 페이지에 문장을 출력했지만, 이번엔 천만번 계산 전 문장을 페이지에 출력해줍니다. 더이상 첫 번째 작업이 두 번째 작업을 차단하지 않습니다.</p> + +<h2 id="Asynchronous_code">Asynchronous code</h2> + +<p>Web worker는 꽤 유용하지만 이들도 한계가 있습니다. 주요한 내용은 Web worker는 {{Glossary("DOM")}} 에 접근할 수 없습니다. — UI를 업데이트하도록 worker에게 어떠한 지시도 직접 할 수 없습니다. 두 번째 예시에서 worker는 100만개의 파란색 원을 만들 수 없습니다. 단순히 숫자만 계산합니다.</p> + +<p>두 번째 문제는 worker에서 실행되는 코드는 차단되지 않지만 동기적으로 실행된다는 것 입니다. 이러한 문제는 함수를 사용할 때 발생합니다. 어떤 함수가 일의 처리를 위해 이전의 여러 프로세스의 결과를 return 받아야 할 경우 입니다. 동기적으로 실행되면 함수 실행에 필요한 매개변수를 받아올 수 없는 경우가 생기므로 함수는 사용자가 원하는 기능을 제대로 실행할 수 없습니다.</p> + +<pre class="notranslate">Main thread: Task A --> Task B</pre> + +<p>이 예시에서 Task A는 서버로부터 이미지를 가져오고 Task B는 그 이미지에 필터를 적용하는 것과 같은 작업을 수행한다고 가정합니다. Task A를 실행하고 결과를 반환할 시간도 없이 Task B를 실행해버리면 에러가 발생할 것 입니다. 왜냐햐면 Task A에서 이미지를 완전히 가져온 상태가 아니기 때문이죠.</p> + +<pre class="notranslate"> Main thread: Task A --> Task B --> |Task D| +Worker thread: Task C -----------> | |</pre> + +<p>이번 예시에선 Task D가 Task B와 Task C의 결과를 모두 사용한다고 가정합니다. Task B와 Task C가 동시에 아주 빠르게 결과를 반환하면 매우 이상적이겠지만, 현실은 그렇지 않습니다. Task D가 사용될 때 Task B, Task C 둘 중 어느 값이라도 입력이 되지 않을경우 에러가 발생합니다.</p> + +<p>이러한 문제를 해결하기 위해 브라우저를 통해 특정 작업을 비동기적으로 실행할 수 있습니다. 바로 <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise">Promises</a> 를 사용하는것 입니다. 아래 예시처럼 Task A가 서버에서 이미지를 가져오는 동안 Task B를 기다리게 할 수 있습니다. :</p> + +<pre class="notranslate">Main thread: Task A Task B + Promise: |__async operation__|</pre> + +<p>위의 작업은 다른 곳에서 처리가 되므로, 비동기 작업이 진행되는 동안 main thread가 차단되지 않습니다.</p> + +<p>이번 문서에서 다룬 내용은 매우 중요한 내용입니다. 다음 문서에선 비동기 코드를 어떻게 쓸 수 있는지 살펴볼 계획이므로 끝까지 읽어주시면 좋겠습니다.</p> + +<h2 id="결론">결론</h2> + +<p>현대의 소프트웨어 설계는 프로그램이 한 번에 두 가지 이상의 일을 할 수 있도록 비동기 프로그래밍을 중심으로 돌아가고 있습니다. 보다 새롭고 강력한 API를 이용하면서, 비동기로 작업해야만 하는 사례가 많아질 것입니다. 예전에는 비동기 코드를 쓰기가 힘들었습니다. 여전히 아직 어렵지만, 훨씬 쉬워졌습니다. 이 모듈의 나머지 부분에서는 비동기 코드가 왜 중요한지, 위에서 설명한 일부 문제들을 방지하는 코드 설계 방법에 대해 자세히 알아봅시다.</p> + +<h2 id="이번_module_에서는..">이번 module 에서는..</h2> + +<ul> + <li><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Concepts">일반적인 비동기 프로그래밍 개념</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Introducing">비동기 자바스크립트 소개</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Timeouts_and_intervals">협동하는 비동기 자바스크립트: Timeouts and intervals</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Promises">Promises와 함께하는 우아한 비동기 프로그래밍</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Async_await">비동기 프로그래밍을 쉽게 만드는 방법: async and await</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Choosing_the_right_approach">올바른 접근 방식 선택하기</a></li> +</ul> diff --git a/files/ko/learn/javascript/asynchronous/index.html b/files/ko/learn/javascript/asynchronous/index.html new file mode 100644 index 0000000000..bcf2abdd45 --- /dev/null +++ b/files/ko/learn/javascript/asynchronous/index.html @@ -0,0 +1,59 @@ +--- +title: Asynchronous JavaScript +slug: Learn/JavaScript/Asynchronous +tags: + - Beginner + - CodingScripting + - Guide + - JavaScript + - Landing + - NeedsTranslation + - Promises + - TopicStub + - async + - asynchronous + - await + - callbacks + - requestAnimationFrame + - setInterval + - setTimeout +translation_of: Learn/JavaScript/Asynchronous +--- +<div>{{LearnSidebar}}</div> + +<p class="summary"><span class="seoSummary">In this module we take a look at {{Glossary("asynchronous")}} {{Glossary("JavaScript")}}, why it is important, and how it can be used to effectively handle potential blocking operations such as fetching resources from a server.</span></p> + +<h2 id="Prerequisites">Prerequisites</h2> + +<p>Asynchronous JavaScript is a fairly advanced topic, and you are advised to work through <a href="/en-US/docs/Learn/JavaScript/First_steps">JavaScript first steps</a> and <a href="/en-US/docs/Learn/JavaScript/Building_blocks">JavaScript building blocks</a> modules before attempting this.</p> + +<p>If you are not familiar with the concept of asynchronous programming, you should definitely start with the <a href="/en-US/docs/Learn/JavaScript/Asynchronous/Concepts">General asynchronous programming concepts</a> article in this module. If you are, then you can probably skip to the <a href="/en-US/docs/Learn/JavaScript/Asynchronous/Introducing">Introducing asynchronous JavaScript</a> module.</p> + +<div class="note"> +<p><strong>Note</strong>: If you are working on a computer/tablet/other device where you don't have the ability to create your own files, you can try out (most of) the code examples in an online coding program such as <a href="http://jsbin.com/">JSBin</a> or <a href="https://thimble.mozilla.org/">Thimble</a>.</p> +</div> + +<h2 id="Guides">Guides</h2> + +<dl> + <dt><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Concepts">General asynchronous programming concepts</a></dt> + <dd> + <p>In this article we'll run through a number of important concepts relating to asynchronous programming, and how this looks in web browsers and JavaScript. You should understand these concepts before working through the other articles in the module.</p> + </dd> + <dt><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Introducing">Introducing asynchronous JavaScript</a></dt> + <dd>In this article we briefly recap the problems associated with sychronous JavaScript, and take a first look at some of the different asynchronous JavaScript techniques you'll encounter, showing how they can help us solve such problems.</dd> + <dt><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Loops_and_intervals">Cooperative asynchronous JavaScript: Timeouts and intervals</a></dt> + <dd>Here we look at the traditional methods JavaScript has available for running code asychronously after a set time period has elapsed, or at a regular interval (e.g. a set number of times per second), talk about what they are useful for, and look at their inherent issues.</dd> + <dt><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Promises">Handling async operations gracefully with Promises</a></dt> + <dd>Promises are a comparatively new feature of the JavaScript language that allow you to defer further actions until after the previous action has completed, or respond to its failure. This is really useful for setting up a sequence of operations to work correctly. This article shows you how promises work, where you'll see them in use in WebAPIs, and how to write your own.</dd> + <dt><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Async_await">Making asynchronous programming easier with async and await</a></dt> + <dd>Promises can be somewhat complex to set up and understand, and so modern browsers have implemented <code>async</code> functions and the <code>await</code> operator — the former allows standard functions to implicitly behave asynchronously with promises, whereas the latter can be used inside <code>async</code> functions to wait for promises before the function continues, making chaining of promises easier. This article explains <code>async</code>/<code>await</code>.</dd> + <dt><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Choosing_the_right_approach">Choosing the right approach</a></dt> + <dd>To finish this module off, we'll consider the different coding techniques and features we've discussed throughout, looking at which ones you should use when, with recommendations and reminders of common pitfalls where appropriate.</dd> +</dl> + +<h2 id="See_also">See also</h2> + +<ul> + <li><a href="https://eloquentjavascript.net/11_async.html">Asynchronous Programming</a> from the fantastic <a href="https://eloquentjavascript.net/">Eloquent JavaScript</a> online book by Marijn Haverbeke.</li> +</ul> diff --git a/files/ko/learn/javascript/asynchronous/introducing/index.html b/files/ko/learn/javascript/asynchronous/introducing/index.html new file mode 100644 index 0000000000..a63eb66158 --- /dev/null +++ b/files/ko/learn/javascript/asynchronous/introducing/index.html @@ -0,0 +1,281 @@ +--- +title: Introducing asynchronous JavaScript +slug: Learn/JavaScript/Asynchronous/Introducing +translation_of: Learn/JavaScript/Asynchronous/Introducing +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/JavaScript/Asynchronous/Concepts", "Learn/JavaScript/Asynchronous/Timeouts_and_intervals", "Learn/JavaScript/Asynchronous")}}</div> + +<p class="summary">이 문서에선 JavaScript의 동기식 처리와 관련된 문제를 간략하게 요약하고, 앞으로 접하게 될 다른 비동기 기술들을 살펴보며, 어떻게 우리에게 도움이 될 수 있는지 살펴봅니다.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">준비:</th> + <td>Basic computer literacy, a reasonable understanding of JavaScript fundamentals.</td> + </tr> + <tr> + <th scope="row">목표:</th> + <td> + <p>비동기 자바스크립트에 대해 더 알기 위해, 동기 스크립트와 어떤 부분이 다른지 그리고 사용 사례를 알 수 있다.</p> + </td> + </tr> + </tbody> +</table> + +<h2 id="Synchronous_JavaScript">Synchronous JavaScript</h2> + +<p><strong>{{Glossary("asynchronous")}}</strong> JavaScript가 무엇인지 이해하려면, 우리는 <strong>{{Glossary("synchronous")}}</strong> JavaScript가 무엇인지 알아야 합니다. 이 문서에선 이전 문서에서 본 정보의 일부를 요약하겠습니다.</p> + +<p>이전의 학습 모듈에서 살펴본 많은 기능들은 동기식 입니다. — 약간의 코드를 실행하면, 브라우저가 할 수 있는 한 빠르게 결과를 보여줍니다. 다음 예제를 살펴볼까요 (<a href="https://mdn.github.io/learning-area/javascript/asynchronous/introducing/basic-function.html">see it live here</a>, and <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/introducing/basic-function.html">see the source</a>):</p> + +<pre class="brush: js notranslate">const btn = document.querySelector('button'); +btn.addEventListener('click', () => { + alert('You clicked me!'); + + let pElem = document.createElement('p'); + pElem.textContent = 'This is a newly-added paragraph.'; + document.body.appendChild(pElem); +}); +</pre> + +<p>이 블럭에서 코드는 위에서 아래로 차례대로 실행됩니다. :</p> + +<ol> + <li>DOM에 미리 정의된 {{htmlelement("button")}} element 를 참조합니다.</li> + <li><code><a href="/en-US/docs/Web/API/Element/click_event">click</a></code> 이벤트 리스너를 만들어 버튼이 클릭됐을 때 아래 기능을 차례로 실행합니다. : + <ol> + <li><code><a href="/en-US/docs/Web/API/Window/alert">alert()</a></code> 메시지가 나타납니다.</li> + <li>메시지가 사라지면 {{htmlelement("p")}} element를 만듭니다.</li> + <li>그리고 text content를 만듭니다.</li> + <li>마지막으로 docuent body에 문장을 추가합니다.</li> + </ol> + </li> +</ol> + +<p>각 작업이 처리되는 동안 렌더링은 일시 중지됩니다. <a href="/en-US/docs/Learn/JavaScript/Asynchronous/Introducing">앞에서 말한 문서와 같이</a>, <a href="/en-US/docs/Learn/JavaScript/Asynchronous/Concepts#JavaScript_is_single_threaded">JavaScript 는 single threaded</a>이기 때문입니다. 한 번에 한 작업만, 하나의 main thread에서 처리될 수 있습니다. 그리고 다른 작업은 앞선 작업이 끝나야 수행됩니다.</p> + +<p>따라서 앞의 예제는 사용자가 OK 버튼을 누를 때까지 문장이 나타나지 않습니다. :</p> + +<div class="hidden"> +<pre class="brush: html notranslate"><<span class="pl-ent">button</span>>Click me</<span class="pl-ent">button</span>></pre> +</div> + +<p>{{EmbedLiveSample('Synchronous_JavaScript', '100%', '70px')}}</p> + +<div class="blockIndicator note"> +<p><strong>Note</strong>: 기억해두세요. <code><a href="/en-US/docs/Web/API/Window/alert">alert()</a></code> 는 동기 블럭을 설명하는데 아주 유용하지만, 실제 어플리케이션에서 사용하기엔 아주 끔찍합니다.</p> +</div> + +<h2 id="Asynchronous_JavaScript">Asynchronous JavaScript</h2> + +<p>앞서 설명된 이유들 (e.g. related to blocking) 때문에 많은 웹 API기능은 현재 비동기 코드를 사용하여 실행되고 있습니다. 특히 외부 디바이스에서 어떤 종류의 리소스에 액세스 하거나 가져오는 기능들에 많이 사용합니다. 예를 들어 네트워크에서 파일을 가져오거나, 데이터베이스에 접속해 특정 데이터를 가져오는 일, 웹 캠에서 비디오 스트림에 엑세스 하거나, 디스플레이를 VR 헤드셋으로 브로드캐스팅 하는것 입니다.</p> + +<p>동기적 코드를 사용하여 작업을 처리하는데 왜 이렇게 어려울까요? 다음 예제를 살펴보겠습니다. 서버에서 이미지를 가져오면 네트워크 환경, 다운로드 속도 등의 영향을 받아 이미지를 즉시 확인할 수 없습니다. 이 말은 아래 코드가 (pseudocode) 실행되지 않는다는 의미 입니다. :</p> + +<pre class="brush: js notranslate">let response = fetch('myImage.png'); +let blob = response.blob(); +// display your image blob in the UI somehow</pre> + +<p>왜냐하면 앞서 설명했듯이 이미지를 다운로드 받는데 얼마나 걸릴지 모르기 때문입니다. 그래서 두 번째 줄을 실행하면 에러가 발생할 것 입니다. (이미지의 크키가 아주 작다면 에러가 발생하지 않을 수도 있습니다. 반대로 이미지의 크기가 크면 매번 발생할 것 입니다.) 왜냐하면 <code>response</code> 가 아직 제공되지 않았기 때문입니다. 따라서 개발자는 <code>response</code> 가 반환되기 전 까지 기다리게 처리를 해야합니다.</p> + +<p>JavaScript에서 볼 수 있는 비동기 스타일은 두 가지 유형이 있습니다, 예전 방식인 callbacks 그리고 새로운 방식인 promise-style 코드 입니다. 이제부터 차례대로 살펴보겠습니다.</p> + +<h2 id="Async_callbacks">Async callbacks</h2> + +<p>Async callbacks은 백그라운드에서 코드 실행을 시작할 함수를 호출할 때 인수로 지정된 함수입니다. 백그라운드 코드 실행이 끝나면 callback 함수를 호출하여 작업이 완료됐음을 알리거나, 다음 작업을 실행하게 할 수 있습니다. callbacks을 사용하는 것은 지금은 약간 구식이지만, 여전히 다른 곳에서 사용이 되고있음을 확인할 수 있습니다.</p> + +<p>Async callback 의 예시는 {{domxref("EventTarget.addEventListener", "addEventListener()")}} 'click' 옆의 두 번째 매개변수 입니다. :</p> + +<pre class="brush: js notranslate">btn.addEventListener('click', () => { + alert('You clicked me!'); + + let pElem = document.createElement('p'); + pElem.textContent = 'This is a newly-added paragraph.'; + document.body.appendChild(pElem); +});</pre> + +<p>첫 번째 매개 변수는 이벤트 리스너 유형이며, 두 번째 매개 변수는 이벤트가 실행 될 때 호출되는 콜백 함수입니다.</p> + +<p>callback 함수를 다른 함수의 인수로 전달할 때, 함수의 참조를 인수로 전달할 뿐이지 즉시 실행되지 않고, 함수의 body에서 “called back”됩니다. 정의된 함수는 때가 되면 callback 함수를 실행하는 역할을 합니다.</p> + +<p><a href="/en-US/docs/Web/API/XMLHttpRequest"><code>XMLHttpRequest</code> API</a> (<a href="https://mdn.github.io/learning-area/javascript/asynchronous/introducing/xhr-async-callback.html">run it live</a>, and <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/introducing/xhr-async-callback.html">see the source</a>)를 불러오는 예제를 통해 callback 함수를 쉽게 사용해봅시다. :</p> + +<pre class="brush: js notranslate">function loadAsset(url, type, callback) { + let xhr = new XMLHttpRequest(); + xhr.open('GET', url); + xhr.responseType = type; + + xhr.onload = function() { + callback(xhr.response); + }; + + xhr.send(); +} + +function displayImage(blob) { + let objectURL = URL.createObjectURL(blob); + + let image = document.createElement('img'); + image.src = objectURL; + document.body.appendChild(image); +} + +loadAsset('coffee.jpg', 'blob', displayImage);</pre> + +<p><code>displayImage()</code>함수는 Object URL로 전달되는 Blob을 전달받아, URL이 나탸내는 이미지를 만들어 <code><body></code>에 그립니다. 그러나, 우리는 <code>loadAsset()</code> 함수를 만들고 "url", "type" 그리고 "callback"을 매개변수로 받습니다. <code>XMLHttpRequest</code> (줄여서 "XHR") 를 사용하여 전달받은 URL에서 리소스를 가져온 다음 callback으로 응답을 전달하여 작업을 수행합니다. 이 경우 callback은 callback 함수로 넘어가기 전, 리소스 다운로드를 완료하기 위해 XHR 요청이 진행되는 동안 대기합니다. (<code><a href="/en-US/docs/Web/API/XMLHttpRequestEventTarget/onload">onload</a></code> 이벤트 핸들러 사용)</p> + +<p>Callbacks은 다재다능 합니다. 함수가 실행되는 순서, 함수간에 어떤 데이터가 전달되는지를 제어할 수 있습니다. 또한 상황에 따라 다른 함수로 데이터를 전달할 수 있습니다. 따라서 응답받은 데이터에 따라 (<code>processJSON()</code>, <code>displayText()</code>등) 어떤 작업을 수행할지 지정할 수 있습니다.</p> + +<p>모든 callback이 비동기인 것은 아니라는 것에 유의하세요 예를 들어 {{jsxref("Array.prototype.forEach()")}} 를 사용하여 배열의 항목을 탐색할 때가 있습니다. (<a href="https://mdn.github.io/learning-area/javascript/asynchronous/introducing/foreach.html">see it live</a>, and <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/introducing/foreach.html">the source</a>):</p> + +<pre class="brush: js notranslate">const gods = ['Apollo', 'Artemis', 'Ares', 'Zeus']; + +gods.forEach(function (eachName, index){ + console.log(index + '. ' + eachName); +});</pre> + +<p>이 예제에선 그리스 신들의 배열을 탐색하여 인덱스 넘버와 그 값을 콘솔에 출력합니다. <code>forEach()</code> 매개변수는 callback 함수이며, callback 함수는 배열 이름과 인덱스 총 두 개의 매개변수가 있습니다. 그러나, 여기선 비동기로 처리되지 않고 즉시 실행됩니다..</p> + +<h2 id="Promises">Promises</h2> + +<p>Promises 모던 Web APIs에서 보게 될 새로운 코드 스타일 입니다. 좋은 예는 <code><a href="/en-US/docs/Web/API/WindowOrWorkerGlobalScope/fetch">fetch()</a></code> API 입니다. <code><a href="/en-US/docs/Web/API/WindowOrWorkerGlobalScope/fetch">fetch()</a></code>는 {{domxref("XMLHttpRequest")}}보다 좀 더 현대적인 버전 입니다. 아래 <a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Fetching_data">Fetching data from the server</a> 예제에서 빠르게 살펴볼까요? :</p> + +<pre class="brush: js notranslate">fetch('products.json').then(function(response) { + return response.json(); +}).then(function(json) { + products = json; + initialize(); +}).catch(function(err) { + console.log('Fetch problem: ' + err.message); +});</pre> + +<div class="blockIndicator note"> +<p><strong>Note</strong>: You can find the finished version on GitHub (<a href="https://github.com/mdn/learning-area/blob/master/javascript/apis/fetching-data/can-store-xhr/can-script.js">see the source here</a>, and also <a href="https://mdn.github.io/learning-area/javascript/apis/fetching-data/can-store-xhr/">see it running live</a>).</p> +</div> + +<p><code>fetch</code><code>()</code> 는 단일 매개변수만 전달받습니다. — 네트워크에서 가지고 오고 싶은 리소스의 URL — 그리고 <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise">promise</a>로 응답합니다. promise 는 비동기 작업이 성공 했는지 혹은 실패했는지를 나타내는 하나의 오브젝트 입니다. 즉 성공/실패 의 분기점이 되는 중간의 상태라고 표현할 수 있죠. 왜 promise라는 이름이 붙었는지 잠깐 살펴보자면.. "내가 할수 있는 한 빨리 너의 요청의 응답을 가지고 돌아간다고 약속(promise)할게" 라는 브라우저의 표현방식 이어서 그렇습니다.</p> + +<p>이 개념에 익숙해 지기 위해서는 연습이 필요합니다.; 마치 {{interwiki("wikipedia", "Schrödinger's cat")}}(슈뢰딩거의 고양이) 처럼 느껴질 수 있습니다. 위의 예제에서도 발생 가능한 결과 중 아직 아무것도 발생하지 않았기 때문에, 미래에 어떤 시점에서 <code>fetch()</code>작업이 끝났을때 어떤 작업을 수행 시키기 위해 두 가지 작업이 필요합니다. 예제에선 <code>fetch()</code> 마지막에 세 개의 코드 블럭이 더 있는데 이를 살펴보겠습니다. :</p> + +<ul> + <li>두 개의 <code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/then">then()</a></code> 블럭: 두 함수 모두 이전 작업이 성공했을때 수행할 작업을 나타내는 callback 함수 입니다. 그리고 각 callback함수는 인수로 이전 작업의 성공 결과를 전달받습니다. 따라서 성공했을때의 코드를 callback 함수 안에 작성하면 됩니다. 각 <code>.then()</code> 블럭은 서로 다른 promise를 반환합니다. 이 말은 <code>.then()</code> 을 여러개 사용하여 연쇄적으로 작업을 수행하게 할 수 있음을 말합니다. 따라서 여러 비동기 작업을 차례대로 수행할 수 있습니다.</li> + <li><code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/catch">catch()</a></code> 블럭은 <code>.then()</code> 이 하나라도 실패하면 동작합니다. — 이는 동기 방식의 <code><a href="/en-US/docs/Web/JavaScript/Reference/Statements/try...catch">try...catch</a></code> 블럭과 유사합니다. error 오브젝트는 <code>catch()</code>블럭 안에서 사용할 수 있으며, 발생한 오류를 보고하는 용도로 사용할 수 있습니다. 그러나 <code>try...catch</code> 는 나중에 배울 <a href="/en-US/docs/Learn/JavaScript/Asynchronous/Async_await">async/await</a>에서는 동작하지만, promise와 함께 동작할 수 없음을 알아두세요.</li> +</ul> + +<div class="blockIndicator note"> +<p><strong>Note</strong>: You'll learn a lot more about promises later on in the module, so don't worry if you don't understand them fully yet.</p> +</div> + +<h3 id="The_event_queue">The event queue</h3> + +<p>promise와 같은 비동기 작업은 <strong>event queue</strong>에 들어갑니다. 그리고 main thread가 끝난 후 실행되어 후속 JavaScript 코드가 차단되는것을 방지합니다. queued 작업은 가능한 빨리 완료되어 JavaScript 환경으로 결과를 반환해줍니다.</p> + +<h3 id="Promises_vs_callbacks">Promises vs callbacks</h3> + +<p>Promises 는 old-style callbacks과 유사한 점이 있습니다. 기본적으로 callback을 함수로 전달하는 것이 아닌 callback함수를 장착하고 있는 returned된 오브젝트 입니다.</p> + +<p>그러나 Promise는 비동기 작업을 처리함에 있어서 old-style callbacks 보다 더 많은 이점을 가지고 있습니다. :</p> + +<ul> + <li>여러 개의 연쇄 비동기 작업을 할 때 앞서 본 예제처럼 <code>.then()</code> 을 사용하여 결과값을 다음 작업으로 넘길 수 있습니다. callbacks으로 이를 사용하려면 더 어렵습니다. 또한 "파멸의 피라미드" (<a href="http://callbackhell.com/">callback hell</a>로 잘 알려진)을 종종 마주칠 수 있습니다.</li> + <li>Promise callbacks은 event queue에 배치되는 엄격한 순서로 호출됩니다.</li> + <li>에러 처리가 더 간결해집니다. — 모든 에러를 코드 블럭의 마지막 부분에 있는 단 한개의 <code>.catch()</code> 블럭으로 처리할 수 있습니다. 이 방법은 피라미드의 각 단계에서 에러를 핸들링하는 것 보다 더 간단합니다..</li> + <li>구식 callback은 써드파티 라이브러리에 전달될 때 함수가 어떻게 실행되어야 하는 방법을 상실하는 반면 Promise는 그렇지 않습니다.</li> +</ul> + +<h2 id="The_nature_of_asynchronous_code">The nature of asynchronous code</h2> + +<p>코드 실행 순서를 완전히 알지 못할 때 발생하는 현상과 비동기 코드를 동기 코드처럼 취급하려고 하는 문제를 살펴보면서 비동기 코드의 특성을 더 살펴봅시다 아래 예제는 이전에 봤던 예제와 유사합니다. (<a href="https://mdn.github.io/learning-area/javascript/asynchronous/introducing/async-sync.html">see it live</a>, and <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/introducing/async-sync.html">the source</a>). 한가지 다른 점은 코드가 실행순서를 보여주기 위해 {{domxref("console.log()")}} 를 추가했습니다.</p> + +<pre class="brush: js notranslate">console.log ('Starting'); +let image; + +fetch('coffee.jpg').then((response) => { + console.log('It worked :)') + return response.blob(); +}).then((myBlob) => { + let objectURL = URL.createObjectURL(myBlob); + image = document.createElement('img'); + image.src = objectURL; + document.body.appendChild(image); +}).catch((error) => { + console.log('There has been a problem with your fetch operation: ' + error.message); +}); + +console.log ('All done!');</pre> + +<p>브라우저는 코드를 실행하기 시작할 것이고, 맨 처음 나타난 (<code>Starting</code>) 글씨가 써진 <code>console.log()</code> 후 <code>image</code> 변수를 만들 것 입니다.</p> + +<p>다음으로 <code>fetch()</code> block 으로 이동하여 코드를 실행하려고 할 것 입니다. <code>fetch()</code> 덕분에 blocking없이 비동기 적으로 코드가 실행되겠죠. 블럭 내에서 promise와 관련된 작업이 끝나면 다음 작업으로 이어질 것 입니다. 그리고 마지막으로 (<code>All done!</code>) 가 적혀있는 <code>console.log()</code> 에서 메시지를 출력할 것 입니다.</p> + +<p><code>fetch()</code> 블럭 작업이 작업을 완전히 끝내고 마지막 <code>.then()</code> 블럭에 도달해야 <code>console.log()</code> 의 (<code>It worked :)</code>) 메시지가 나타납니다. 그래서 메시지의 순서는 코드에 적혀있는 대로 차례대로 나타나는게 아니라 순서가 약간 바뀌어서 나타납니다 :</p> + +<ul> + <li>Starting</li> + <li>All done!</li> + <li>It worked :)</li> +</ul> + +<p>이 예가 어렵다면 아래의 다른 예를 살펴보세요 :</p> + +<pre class="brush: js notranslate">console.log("registering click handler"); + +button.addEventListener('click', () => { + console.log("get click"); +}); + +console.log("all done");</pre> + +<p>이전 예제와 매우 유사한 예제 입니다. — 첫 번째와 세 번째<code>console.log()</code> 메시지는 콘솔창에 바로 출력됩니다. 그러나 두 번째 메시지는 누군가가 버튼을 클릭하기 전엔 콘솔에 표시되지 않죠. 위의 예제의 차이라면 두 번쩨 메시지가 어떻게 잠시 blocking이 되는지 입니다. 첫 예제는 Promise 체이닝 때문에 발생하지만 두 번째 메시지는 클릭 이벤트를 대기하느라고 발생합니다.</p> + +<p>less trivial 코드 예제에서 이러한 설정을 문제를 유발할 수 있습니다. — 비동기 코드 블럭에서 반환된 결과를 동기화 코드 블럭에 사용할 수 없습니다. 위의 에시에서 <font face="consolas, Liberation Mono, courier, monospace"><span style="background-color: rgba(220, 220, 220, 0.5);">image</span></font> 변수가 그 예시 입니다. 브라우저가 동기화 코드 블럭을 처리하기 전에 비동기 코드 블럭 작업이 완료됨을 보장할 수 없습니다.</p> + +<p>어떤 의미인지 확인을 하려면 <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/introducing/async-sync.html">our example</a>을 컴퓨터에 복사한 후 마지막 <code>console.log()</code> 를 아래처럼 고쳐보세요:</p> + +<pre class="brush: js notranslate">console.log ('All done! ' + image.src + 'displayed.');</pre> + +<p>고치고 나면 콘솔창에서 아래와 같은 에러가 뜨는것을 확인할 수 있습니다. :</p> + +<pre class="notranslate"><span class="message-body-wrapper"><span class="message-flex-body"><span class="devtools-monospace message-body">TypeError: image is undefined; can't access its "src" property</span></span></span></pre> + +<p>브라우저가 마지막 <code>console.log()</code> 를 처리할 때, <code>fetch()</code> 블럭이 완료되지 않아 <code>image</code> 변수에 결과가 반환되지 않았기 때문입니다.</p> + +<div class="blockIndicator note"> +<p><strong>Note</strong>: For security reasons, you can't <code>fetch()</code> files from your local filesystem (or run other such operations locally); to run the above example locally you'll have to run the example through a <a href="/en-US/docs/Learn/Common_questions/set_up_a_local_testing_server">local webserver</a>.</p> +</div> + +<h2 id="Active_learning_make_it_all_async!">Active learning: make it all async!</h2> + +<p>위의 <code>fetch()</code> 예시에서 마지막<code>console.log()</code>도 순서대로 나타나도록 고칠 수 있습니다. 마지막 <code>console.log()</code> 도 비동기로 작동시키면 됩니다. 마지막 <code>.then()</code> 블럭의 마지막에 다시 작성하거나, 새로운 블럭을 만들면 콘솔에 순서대로 나타날 것 입니다. 지금 바로 고쳐보세요!</p> + +<div class="blockIndicator note"> +<p><strong>Note</strong>: If you get stuck, you can <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/introducing/async-sync-fixed.html">find an answer here</a> (see it <a href="https://mdn.github.io/learning-area/javascript/asynchronous/introducing/async-sync-fixed.html">running live</a> also). You can also find a lot more information on promises in our <a href="/en-US/docs/Learn/JavaScript/Asynchronous/Promises">Graceful asynchronous programming with Promises</a> guide, later on in the module.</p> +</div> + +<h2 id="Conclusion">Conclusion</h2> + +<p>In its most basic form, JavaScript is a synchronous, blocking, single-threaded language, in which only one operation can be in progress at a time. But web browsers define functions and APIs that allow us to register functions that should not be executed synchronously, and should instead be invoked asynchronously when some kind of event occurs (the passage of time, the user's interaction with the mouse, or the arrival of data over the network, for example). This means that you can let your code do several things at the same time without stopping or blocking your main thread.</p> + +<p>Whether we want to run code synchronously or asynchronously will depend on what we're trying to do.</p> + +<p>There are times when we want things to load and happen right away. For example when applying some user-defined styles to a webpage you'll want the styles to be applied as soon as possible.</p> + +<p>If we're running an operation that takes time however, like querying a database and using the results to populate templates, it is better to push this off the main thread and complete the task asynchronously. Over time, you'll learn when it makes more sense to choose an asynchronous technique over a synchronous one.</p> + +<ul> +</ul> + +<p>{{PreviousMenuNext("Learn/JavaScript/Asynchronous/Concepts", "Learn/JavaScript/Asynchronous/Timeouts_and_intervals", "Learn/JavaScript/Asynchronous")}}</p> + +<h2 id="In_this_module">In this module</h2> + +<ul> + <li><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Concepts">General asynchronous programming concepts</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Introducing">Introducing asynchronous JavaScript</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Timeouts_and_intervals">Cooperative asynchronous JavaScript: Timeouts and intervals</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Promises">Graceful asynchronous programming with Promises</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Async_await">Making asynchronous programming easier with async and await</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Choosing_the_right_approach">Choosing the right approach</a></li> +</ul> diff --git a/files/ko/learn/javascript/asynchronous/promises/index.html b/files/ko/learn/javascript/asynchronous/promises/index.html new file mode 100644 index 0000000000..bf7a5a0f04 --- /dev/null +++ b/files/ko/learn/javascript/asynchronous/promises/index.html @@ -0,0 +1,588 @@ +--- +title: Graceful asynchronous programming with Promises +slug: Learn/JavaScript/Asynchronous/Promises +translation_of: Learn/JavaScript/Asynchronous/Promises +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/JavaScript/Asynchronous/Timeouts_and_intervals", "Learn/JavaScript/Asynchronous/Async_await", "Learn/JavaScript/Asynchronous")}}</div> + +<p class="summary"><span class="seoSummary"><strong>Promises</strong> 는 이전 작업이 완료될 때 까지 다음 작업을 연기 시키거나, 작업실패를 대응할 수 있는 비교적 새로운 JavaScript 기능입니다.</span> Promise는 비동기 작업 순서가 정확하게 작동되게 도움을 줍니다. 이번 문서에선 Promise가 어떻게 동작하는지, 웹 API와 어떻게 사용할 수 있는지 그리고 직접 코드를 만들어 볼것 입니다. </p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Prerequisites:</th> + <td>Basic computer literacy, a reasonable understanding of JavaScript fundamentals.</td> + </tr> + <tr> + <th scope="row">Objective:</th> + <td>To understand promises and how to use them.</td> + </tr> + </tbody> +</table> + +<h2 id="What_are_promises">What are promises?</h2> + +<p>앞서서 <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise">Promises</a> 를 미리 봤지만, 지금부턴 좀더 깊이있게 들여다 볼 차례 입니다..</p> + +<p>Promise는 어떤 작업의 중간상태를 나타내는 오브젝트 입니다. — 미래에 어떤 종류의 결과가 반환됨을 <em>promise</em> (약속) 해주는 오브젝트라고 보면 됩니다. Promise는 작업이 완료되어 결과를 반환해주는 정확한 시간을 보장해주지는 않지만, 사용할 수 있는 결과를 반환했을때 프로그래머의 의도대로 다음 코드를 진행 시키거나, 에러가 발생했을 때 그 에러를 우아하게/깔끔하게 처리할 수 있습니다.</p> + +<p>일반적으로 우리는 비동기 작업이 결과를 반환하는데 얼마의 시간이 걸리는지 보다는(<em>작업 시간이 매우 오래 걸리지 않는 한</em>) 그 결과를 사용할 수 있는지 여부에 더 관심이 있습니다. 물론 나머지 코드 블럭을 막지 않는다는 것에 있어서 매우 좋습니다.</p> + +<p>우리가 Promise로 가장 많이 할 작업중 하나는 Promise를 반환하는 웹API를 사용하는 것 입니다. 가상의 비디오 채팅 애플리케이션이 있다고 해봅시다. 애플리케이션에는 친구 목록이 있고 각 친구 목록 옆의 버튼을 클릭하면 해당 친구와 비디오 채팅을 시작합니다.</p> + +<p>그 버튼은 사용자 컴퓨터의 카메라와 마이크를 사용하기 위해 {{domxref("MediaDevices.getUserMedia", "getUserMedia()")}} 를 호출합니다. <code>getUserMedia()</code> 는 사용자가 이러한 장치를 사용할 수 있는 권한을 가지고 있는지 확인해야 하고, 어떤 마이크와 카메라를 사용할 것인지 (혹은 음성 통화인지, 아니면 다른 옵션들이 있는지)를 체크해야하기 때문에 모든 결정이 내려질 때 까지 다음 작업을 차단할 수 있습니다. 또한 카메라와 마이크가 작동하기 전 까지 다음 작업을 차단할수도 있습니다.</p> + +<p><code>getUserMedia()</code> 는 브라우저의 main thread에서 실행되므로 <code>getUserMedia()</code> 결과가 반환되기 전 까지 후행 작업이 모두 차단됩니다. 이러한 blocking은 우리가 바라는게 아닙니다. Promise가 없으면 이러한 결정이 내려지기 전 까지 브라우저의 모든 것을 사용할 수 없게됩니다. 따라서 사용자가 선택한 장치를 활성화하고 소스에서 선택된 스트림에 대해{{domxref("MediaStream")}} 직접 반환하는 대신 <code>getUserMedia()</code> 는 모든 장치가 사용 가능한 상태가 되면 {{domxref("MediaStream")}}이 포함된 {{jsxref("promise")}}를 반환합니다.</p> + +<p>비디오 채팅 애플리케이션의 코드는 아래처럼 작성할 수 있습입니다. :</p> + +<pre class="brush: js notranslate">function handleCallButton(evt) { + setStatusMessage("Calling..."); + navigator.mediaDevices.getUserMedia({video: true, audio: true}) + .then(chatStream => { + selfViewElem.srcObject = chatStream; + chatStream.getTracks().forEach(track => myPeerConnection.addTrack(track, chatStream)); + setStatusMessage("Connected"); + }).catch(err => { + setStatusMessage("Failed to connect"); + }); +} +</pre> + +<p>이 기능은 상태 메시지에 "Calling..."을 출력하는 <code>setStatusMessage()</code> 함수로 시작하며 통화가 시도되고 있음을 나타냅니다. 그런 다음 <code>getUserMedia()</code>을 호출하여 비디오와 오디오 트랙이 모두 있는 스트림 요청을 합니다. 그리고 스트림을 획득하면 카메라에서 나오는 스트림을 "self view,"로 표시하기 위해 video엘리먼트를 설정합니다. 그리고 각 스트림의 트랙을 가져가 다른 사용자와의 연결을 나타내는 <a href="/en-US/docs/Web/API/WebRTC_API">WebRTC</a> {{domxref("RTCPeerConnection")}}에 추가합니다. 그리고 마지막으로 상태 메시지를 "Connected"로 업데이트 합니다.</p> + +<p><code>getUserMedia()</code> 가 실패하면, <code>catch</code> 블럭이 실행되며, <code>setStatusMessage()</code> 를 사용하여 상태창에 오류 메시지를 표시합니다.</p> + +<p>여기서 중요한건 <code>getUserMedia()</code>는 카메라 스트림이 아직 확보되지 않았음에도 거의 즉시 반환을 해줬다는 것 입니다. <code>handleCallButton()</code> 함수가 자신을 호출한 코드로 결과를 이미 반환을 했더라도 <code>getUserMedia()</code>의 작업이 종료되면 프로그래머가 작성한 다음 핸들러를 호출할 것 입니다. 앱이 스트리밍을 했다고 가정하지 않는 한 계속 실행될 수 있습니다.</p> + +<div class="blockIndicator note"> +<p><strong>Note:</strong> You can learn more about this somewhat advanced topic, if you're interested, in the article <a href="/docs/Web/API/WebRTC_API/Signaling_and_video_calling">Signaling and video calling</a>. Code similar to this, but much more complete, is used in that example.</p> +</div> + +<h2 id="The_trouble_with_callbacks">The trouble with callbacks</h2> + +<p>Promise가 왜 좋은지 이해하기 위해 구식 callbacks을 살펴보고 어떤게 문제인지 파악 해보겠습니다.</p> + +<p>피자를 주문한다고 생각해봅시다. 피자를 잘 주문하려면 몇 가지 단계를 진행해야 합니다. 토핑 위에 도우를 올리고 치즈를 뿌리는 등 각 단계가 뒤죽박죽 이거나 혹은 도우를 반죽하고 있는데 그 위에 토마토소스를 바르는 등 이전 작업이 끝나지 않고 다음 작업을 진행하는 것은 말이 안 됩니다. :</p> + +<ol> + <li>먼저 원하는 토핑을 고릅니다. 결정 장애가 심할 경우 토핑을 고르는데 오래 걸릴 수 있습니다. 또한 마음을 바꿔 피자 대신 카레를 먹으려고 가게를 나올 수 있습니다.</li> + <li>그다음 피자를 주문합니다. 식당이 바빠서 피자가 나오는 데 오래 걸릴 수 있고, 마침 재료가 다 떨어졌으면 피자를 만들 수 없다고 할 것 입니다.</li> + <li>마지막으로 피자를 받아서 먹습니다. 그런데! 만약 지갑을 놓고 와서 돈을 내지 못한다면 피자를 먹지 못할 수 있습니다.</li> +</ol> + +<p>구식 <a href="/en-US/docs/Learn/JavaScript/Asynchronous/Introducing#Callbacks">callbacks</a>을 사용하면 아래와 같은 모습의 코드가 나타날것 입니다. :</p> + +<pre class="brush: js notranslate">chooseToppings(function(toppings) { + placeOrder(toppings, function(order) { + collectOrder(order, function(pizza) { + eatPizza(pizza); + }, failureCallback); + }, failureCallback); +}, failureCallback);</pre> + +<p>이런 코드는 읽기도 힘들 뿐 아니라 (종종 "콜백 지옥" 이라 불림), <code>failureCallback()</code> 을 여러 번 작성해야 하며 또한 다른 문제점도 가지고 있습니다.</p> + +<h3 id="Improvements_with_promises">Improvements with promises</h3> + +<p>위의 상황에서 Promise를 사용하면 읽기, 작성, 실행 모두 다 쉬워집니다. callback 대신 비동기 Promise를 사용하면 아래처럼 작성할 수 있습니다. :</p> + +<pre class="brush: js notranslate">chooseToppings() +.then(function(toppings) { + return placeOrder(toppings); +}) +.then(function(order) { + return collectOrder(order); +}) +.then(function(pizza) { + eatPizza(pizza); +}) +.catch(failureCallback);</pre> + +<p>보기에 훨씬 더 좋군요! — 이렇게 작성하면 앞으로 어떤 일이 일어날지 쉽게 예측 가능합니다. 그리고 단 한개의 <code>.catch()</code> 을 사용하여 모든 에러를 처리합니다. 그리고 main thread를 차단하지 않습니다. (그래서 피자를 주문하고 기다리는 동안 하던 게임을 마저 할 수 있습니다.), 또한 각 함수가 실행되기 전 이전 작업이 끝날때까지 기다립니다. 이런식으로 여러 개의 비동기 작업을 연쇄적으로 처리할 수 있습니다. 왜냐햐면 각 <code>.then()</code> 블럭은 자신이 속한 블럭의 작업이 끝났을 때의 결과를 새로운 Promise 반환해주기 때문입니다. 어때요, 참 쉽죠?</p> + +<p>화살표 함수를 사용하면 코드를 조금 더 간단하게 고칠 수 있습니다. :</p> + +<pre class="brush: js notranslate">chooseToppings() +.then(toppings => + placeOrder(toppings) +) +.then(order => + collectOrder(order) +) +.then(pizza => + eatPizza(pizza) +) +.catch(failureCallback);</pre> + +<p>혹은 아래처럼 표현할 수 있습니다. :</p> + +<pre class="brush: js notranslate">chooseToppings() +.then(toppings => placeOrder(toppings)) +.then(order => collectOrder(order)) +.then(pizza => eatPizza(pizza)) +.catch(failureCallback);</pre> + +<p>화살표 함수의 <code>() => x</code> 표현은 <code>() => { return x; }</code>의 약식 표현이므로 잘 작동합니다.</p> + +<p>함수는 arguments를 직접 전달 하므로 함수처럼 표현하지 않고 아래와 같이 작성할 수도 있습니다. :</p> + +<pre class="brush: js notranslate">chooseToppings().then(placeOrder).then(collectOrder).then(eatPizza).catch(failureCallback);</pre> + +<p>그런데 이렇게 작성하면 읽기가 쉽지 않습니다. 사용자의 코드가 지금의 예제보다 더 복잡하다면 위의 방법은 사용하기 힘듭니다.</p> + +<div class="blockIndicator note"> +<p><strong>Note</strong>: 다음 장에서 배울 <code>async</code>/<code>await</code> 문법으로 좀 더 간결화 할 수 있습니다.</p> +</div> + +<p>Promise는 이벤트 리스너와 유사하지만 몇 가지 다른점이 있습니다. :</p> + +<ul> + <li>Promise는 한번에 성공/실패 중 하나의 결과값을 가집니다. 하나의 요청에 두 번 성공하고나 실패할 수 없습니다. 또한 이미 성공한 작업이 다시 실패로 돌아갈 수 없고 실패한 작업이 성공으로 돌아갈 수 없습니다.</li> + <li>If a promise has succeeded or failed and you later add a success/failure callback, the correct callback will be called, even though the event took place earlier.</li> +</ul> + +<h2 id="Explaining_basic_promise_syntax_A_real_example">Explaining basic promise syntax: A real example</h2> + +<p>모던 웹 API는 잠재적으로 긴 작업을 수행하는 함수에 Promise를 사용하므로 Promise가 무엇인지 이해하는것은 매우 중요합니다. 현대적인 웹 기술을 사용하려면 Promise를 사용해야합니다. 챕터의 후반부에서 직접 Promise를 만들어보겠지만, 지금은 일단 웹 API에서 접할 수 있는 몇 가지 예제를 살펴보겠습니다.</p> + +<p>첫 번째로, 웹에서 이미지를 가져오기 위하여 <code><a href="/en-US/docs/Web/API/WindowOrWorkerGlobalScope/fetch">fetch()</a></code> 메서드를 사용할 때 입니다.{{domxref("Body.blob", "blob()")}} 메서드는 fetch가 응답한 원시 body컨텐츠를 {{domxref("Blob")}} 오브젝트로 변환시켜주고{{htmlelement("img")}} 엘리먼트에 표현합니다. 이예제는 <a href="/en-US/docs/Learn/JavaScript/Asynchronous/Introducing#Asynchronous_JavaScript">first article of the series</a>유사합니다. 다만 Promise를 사용하기 위해 약간의 변경을 하겠습니다.</p> + +<div class="blockIndicator note"> +<p><strong>Note</strong>: The following example will not work if you just run it directly from the file (i.e. via a <code>file://</code> URL). You need to run it through a <a href="/en-US/docs/Learn/Common_questions/set_up_a_local_testing_server">local testing server</a>, or use an online solution such as <a href="https://glitch.com/">Glitch</a> or <a href="/en-US/docs/Learn/Common_questions/Using_Github_pages">GitHub pages</a>.</p> +</div> + +<ol> + <li> + <p>먼저 <a href="https://github.com/mdn/learning-area/blob/master/html/introduction-to-html/getting-started/index.html">simple HTML template</a> 와 fetch할 이미지인 <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/promises/coffee.jpg">sample image file</a> 을 다운받습니다.</p> + </li> + <li> + <p>HTML {{htmlelement("body")}} 하단에 {{htmlelement("script")}} 엘리먼트를 삽입합니다.</p> + </li> + <li> + <p>{{HTMLElement("script")}} 엘리먼트 안에 아래와 같이 코드를 작성합니다. :</p> + + <pre class="brush: js notranslate">let promise = fetch('coffee.jpg');</pre> + + <p><code>fetch()</code> 메서드를 호출하여, 네트워크에서 fetch할 이미지의 URL을 매개변수로 전달합니다. 두 번째 매개변수를 사용할 수 있지만, 지금은 우선 간단하게 하나의 매개변수만 사용하겠습니다. 코드를 더 살펴보면 <code>promise</code>변수에 <code>fetch()</code> 작업으로 반환된 Promise 오브젝트를 저장하고 있습니다. 이전에 말했듯이, 지금 오브젝트는 성공도 아니고 실패도 아닌 중간 상태를 저장하고 있습니다. 공식적으로는 <strong>pending</strong>상태라고 부릅니다.</p> + </li> + <li> + <p>작업이 성공적으로 진행될 때를 대응하기 위해 (이번 예제에선 {{domxref("Response")}} 가 반환될 때 입니다. ), 우리는 Promise 오브젝트의 <code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/then">.then()</a></code> 메서드를 호출합니다. <code>.then()</code> 블럭 안의 callback은 (<strong>executor </strong>라고 부름) Promise가 성공적으로 완료되고{{domxref("Response")}} 오브젝트를 반환할 때만 실행합니다. — 이렇게 성공한 Promise의 상태를 <strong>fulfilled</strong>라고 부릅니다. 그리고 반환된 {{domxref("Response")}} 오브젝트를 매개변수로 전달합니다.</p> + + <div class="blockIndicator note"> + <p><strong>Note</strong>: The way that a <code>.then()</code> block works is similar to when you add an event listener to an object using <code>AddEventListener()</code>. It doesn't run until an event occurs (when the promise fulfills). The most notable difference is that a .then() will only run once for each time it is used, whereas an event listener could be invoked multiple times.</p> + </div> + + <p>그리고 즉시 <code>blob()</code> 메서드를 실행하여 Response Body가 완전히 다운로드 됐는지 확인합니다. 그리고 Response Body가 이용 가능할 때 추가 작업을 할 수 있는 <code>Blob</code> 오브젝트로 변환시킵니다. 해당 코드는 아래와 같이 작성할 수 있습니다. :</p> + + <pre class="brush: js notranslate">response => response.blob()</pre> + + <p>위의 코드는 아래의 코드를 축약한 형태입니다. </p> + + <pre class="brush: js notranslate">function(response) { + return response.blob(); +}</pre> + + <p>이제 추가 설명은 충븐하므로, JavaScript의 첫 번째 줄 아래에 다음과 같은 라인을 추가하세요.</p> + + <pre class="brush: js notranslate">let promise2 = promise.then(response => response.blob());</pre> + </li> + <li> + <p>각 <code>.then()</code> 을 호출하면 새로운 Promise를 만드는데, 이는 매우 유용합니다. 왜냐하면 <code>blob()</code> 메서드도 Promise를 반환하기 때문에, 두 번째 Promise의 <code>.then()</code> 메서드를 호출함으로써 이행시 반환되는 <code>Blob</code> 오브젝트를 처리할 수 있습니다. 한 가지 메서드를 실행하여 결과를 반환하는 것보다 Blob에 좀 더 복잡한 일을 추가하고 싶습니다. 이럴때는 중괄호{ }로 묶습니다. (그렇지 않으면 에러가 발생합니다.).</p> + + <p>이어서 아래와 같은 코드를 추가합니다.:</p> + + <pre class="brush: js notranslate">let promise3 = promise2.then(myBlob => { + +})</pre> + </li> + <li> + <p>이제 executor 함수를 아래와 같이 채워넣습니다. 중괄호 안에 작성하면 됩니다. :</p> + + <pre class="brush: js notranslate">let objectURL = URL.createObjectURL(myBlob); +let image = document.createElement('img'); +image.src = objectURL; +document.body.appendChild(image);</pre> + + <p>여기서 우리는 두 번째 Promise가 fulfills일 때 반횐된 Blob을 매개변수로 전달받는 {{domxref("URL.createObjectURL()")}} 메서드를 실행하고 있습니다. 이렇게 하면 오브젝트가 가지고있는 URL이 반환됩니다. 그 다음 {{htmlelement("img")}} 엘리먼트를 만들고, 반환된 URL을 <code>src</code> 속성에 지정하여 DOM에 추가합니다. 이렇게 하면 페이지에 그림이 표시됩니다.</p> + </li> +</ol> + +<p>If you save the HTML file you've just created and load it in your browser, you'll see that the image is displayed in the page as expected. Good work!</p> + +<div class="blockIndicator note"> +<p><strong>Note</strong>: You will probably notice that these examples are somewhat contrived. You could just do away with the whole <code>fetch()</code> and <code>blob()</code> chain, and just create an <code><img></code> element and set its <code>src</code> attribute value to the URL of the image file, <code>coffee.jpg</code>. We did, however, pick this example because it demonstrates promises in a nice simple fashion, rather than for its real-world appropriateness.</p> +</div> + +<h3 id="Responding_to_failure">Responding to failure</h3> + +<p>현재 에러가 발생했을 때 어떻게 처리를 해야할 지 작성된 코드가 없기때문에 코드를 조금만 더 추가하여 좀 더 완벽하게 작성해봅시다. (Promise에서 에러가 발생한 상태를 <strong>rejects</strong>라 부릅니다). 이전에 봤던대로 <code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/catch">.catch()</a></code> 블럭을 추가하여 오류를 핸들링 할 수 있습니다. 아래처럼 말이죠 :</p> + +<pre class="brush: js notranslate">let errorCase = promise3.catch(e => { + console.log('There has been a problem with your fetch operation: ' + e.message); +});</pre> + +<p>에러 메시지를 확인하고 싶으면 잘못된 url을 지정해보세요, 개발자 도구 콘솔에서 에러를 확인할 수 있을것 입니다.</p> + +<p>물론 <code>.catch()</code> 블록 없이 코드를 작동시킬 수 있습니다. 하지만 좀 더 깊게 생각해보면 <code>.catch()</code> 블록이 없으면 어떤 에러가 발생했는지, 어떻게 해결해야 하는지 디버깅이 어렵습니다. 실제 앱에서 <code>.catch()</code> 을 사용하여 이미지 가져오기를 다시 실행하거나, 기본 이미지를 표시하는 등 작업을 지시할 수 있습니다.</p> + +<div class="blockIndicator note"> +<p><strong>Note</strong>: You can see <a href="https://mdn.github.io/learning-area/javascript/asynchronous/promises/simple-fetch.html">our version of the example live</a> (see the <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/promises/simple-fetch.html">source code</a> also).</p> +</div> + +<h3 id="Chaining_the_blocks_together">Chaining the blocks together</h3> + +<p>위에서 사용한 코드는 작업이 어떻게 처리되는지 명확하게 보여주기 위해 매우 길게 코드를 작성했습니다. 이전 글에서 봤듯이, <code>.then()</code> 블럭을 사용하여 연쇄 작업을 진행할 수 있습니다. (또한 <code>.catch()</code> 블럭을 사용하여 에러 처리도 했지요). 앞선 예제의 코드는 아래와 같이 작성할 수도 있습니다. (see also <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/promises/simple-fetch-chained.html">simple-fetch-chained.html</a> on GitHub):</p> + +<pre class="brush: js notranslate">fetch('coffee.jpg') +.then(response => response.blob()) +.then(myBlob => { + let objectURL = URL.createObjectURL(myBlob); + let image = document.createElement('img'); + image.src = objectURL; + document.body.appendChild(image); +}) +.catch(e => { + console.log('There has been a problem with your fetch operation: ' + e.message); +});</pre> + +<p>fulfilled promise 결과에 의해 반환된 값이 다음 <code>.then()</code> 블록의 executor 함수가 가진 파라미터로 전달 된다는 것을 꼭 기억하세요.</p> + +<div class="blockIndicator note"> +<p><strong>Note</strong>: <code>.then()</code>/<code>.catch()</code> blocks in promises are basically the async equivalent of a <code><a href="/en-US/docs/Web/JavaScript/Reference/Statements/try...catch">try...catch</a></code> block in sync code. Bear in mind that synchronous <code>try...catch</code> won't work in async code.</p> +</div> + +<h2 id="Promise_terminology_recap">Promise terminology recap</h2> + +<p>위의 섹션에서 다룬 내용은 정말 많습니다. 매우 중요한 내용을 다뤘으므로 개념을 명확히 이해하기 위해 몇번이고 다시 읽어보는게 좋습니다.</p> + +<ol> + <li>Promise가 생성되면 그 상태는 성공도 실패도 아닌 <strong>pending</strong>상태라고 부릅니다..</li> + <li>Promise결과가 반환되면 결과에 상관 없이 <strong>resolved</strong>상태라고 부릅니다.. + <ol> + <li>성공적으로 처리된 Promise는 <strong>fulfilled</strong>상태이다. 이 상태가 되면 Promise 체인의 다음 <code>.then()</code> 블럭에서 사용할 수 있는 값을 반환합니다.. 그리고 <code>.then()</code> 블럭 내부의 executor 함수에 Promise에서 반환된 값이 파라미터로 전달됩니다..</li> + <li>실패한 Promise는 <strong>rejected</strong>상태이다. 이때 어떤 이유(<strong>reason)</strong> 때문에 Promise가 rejected 됐는지를 나타내는 에러 메시지를 포함한 결과가 반환됩니다. Promise 체이닝의 제일 마지막 <code>.catch()</code> 에서 상세한 에러 메시지를 확인할 수 있습니다.</li> + </ol> + </li> +</ol> + +<h2 id="Running_code_in_response_to_multiple_promises_fulfilling">Running code in response to multiple promises fulfilling</h2> + +<p>위의 예제에서 Promise사용의 기초를 확인했습니다. 이제 고급 기능들을 한번 보겠습니다. 제일 먼저 확인해볼 예제는 다음과 같습니다. 연쇄적으로 일어나는 작업은 좋습니다. 그런데 모든 Promise가 fulfilled일 경우 코드를 실행하고 싶은 경우가 있을것 입니다.</p> + +<p>해당 기능을 <code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all">Promise.all()</a></code> 이라는 스테틱 메서드를 사용하여 만들 수 있습니다. 이 메서드는 Promise의 배열을 매개변수로 삼고, 배열의 모든 Promise가 fulfil일 때만 새로운 fulfil <code>Promise</code> 오브젝트를 반환합니다. 아래처럼 말이죠 :</p> + +<pre class="brush: js notranslate">Promise.all([a, b, c]).then(values => { + ... +});</pre> + +<p>배열의 모든 Promise가 fulfil 이면, <code>.then()</code> 블럭의 executor 함수로의 매개변수로 Promise 결과의 배열을 전달합니다. <code>Promise.all()</code> 의 Promise의 배열 중 하나라도 reject라면, 전체 결과가 reject가 됩니다.</p> + +<p>이 방법은 매우 유용합니다. 웹 UI의 컨텐츠를 동적인 방법으로 채운다고 생각 해보겠습니다. 대부분 경우에 듬성듬성 내용을 채우기보단, 완전한 내용을 채울것 입니다.</p> + +<p>다른 예제를 만들어서 실행해 보겠습니다.</p> + +<ol> + <li> + <p>이미 만들어진 <a href="https://github.com/mdn/learning-area/blob/master/html/introduction-to-html/getting-started/index.html">page template</a>을 다운받으세요 그리고 <code></body></code> 뒤에 <code><script></code> 엘리먼트를 만들어주세요.</p> + </li> + <li> + <p>이미지 그리고 텍스트 파일(<a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/promises/coffee.jpg">coffee.jpg</a>, <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/promises/tea.jpg">tea.jpg</a>, and <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/promises/description.txt">description.txt</a>)을 다운받고 <a href="https://github.com/mdn/learning-area/blob/master/html/introduction-to-html/getting-started/index.html">page template</a> 와 같은 경로에 저장해주세요.</p> + </li> + <li> + <p>먼저 Promise를 반환하는 몇 가지 함수를 만들어 <code>Promise.all()</code>로 결과를 반환합니다. 세 개의 <code>fetch()</code> 작업이 끝나고 다음 요청을 진행하고 싶다면 아래 코드처럼 <code>Promise.all()</code>블럭을 작성합니다. :</p> + + <pre class="brush: js notranslate">let a = fetch(url1); +let b = fetch(url2); +let c = fetch(url3); + +Promise.all([a, b, c]).then(values => { + ... +});</pre> + + <p>Promise가 fulfilled가 됐을 때, fulfilment handler 핸들러로 전달된 <font face="consolas, Liberation Mono, courier, monospace"><span style="background-color: rgba(220, 220, 220, 0.5);">values</span></font> 매개변수에는 각 <code>fetch()</code> 의 결과로 발생한 세 개의 <code>Response</code> 오브젝트가 들어있습니다 .</p> + + <p>하지만 우리는 단순히 결과만 넘겨주고 싶지 않습니다. 우리는<code>fetch()</code> 언제 끝나는지 보다 불러온 데이터에 더 관심이 있습니다. 그말은 브라우저에 표현할 수 있는 Blob과 텍스트 문자열이 불러와 졌을 때 <code>Promise.all()</code> 블럭을 실행하고 싶다는 것 입니다. <code><script></code> 엘리먼트에 아래와 같이 작성합니다. :</p> + + <pre class="brush: js notranslate">function fetchAndDecode(url, type) { + return fetch(url).then(response => { + if (type === 'blob') { + return response.blob(); + } else if (type === 'text') { + return response.text(); + } + }) + .catch(e => { + console.log('There has been a problem with your fetch operation: ' + e.message); + }); +}</pre> + + <p>살짝 복잡해 보이므로 하나하나 살펴봅시다. :</p> + + <ol> + <li>먼저 fetchAndDecode() 함수를 정의했고 함수의 매개변수로 컨텐츠의 URL과 가져오는 리소스의 타입을 지정합니다.</li> + <li>함수 내부에 첫 번째 예에서 본 것과 유사한 구조를 가진 코드가 있습니다. — <code>fetch()</code> 함수를 호출하여 전달받은 URL에서 리소스를 받아오도록 했습니다. 그리고 다음 Promise를 연쇄적으로 호출하여 디코딩된 (혹은 "읽은") Response Body를 반환하게 합니다. 이전 예에선 Blob만을 가져오기 때문에 <code>blob()</code> 메서드만 썼습니다.</li> + <li>여기에선 이전과 다른 두 가지가 있습니다. : + <ul> + <li>먼저 두 번째 Promise에서는 불러올 리소스의 <code>type</code> 이 무엇인지에 따라 반환받는 데이터가 다릅니다. executor 함수 내부에, 간단한 <code>if ... else if</code> 구문을 사용하여 어떤 종류의 파일을 디코딩해야 하는지에 따라 다른 Promise를 반환하게 했습니다. (이 경우 <code>blob</code> 이나 <code>text</code>밖에 없지만, 이것을 잘 활용하여 다른 코드에 확장하여 적용할 수 있습니다.).</li> + <li>두 번째로, <code>fetch()</code> 호출 앞에 <code>return</code> 키워드를 추가했습니다. 이렇게 하면 Promise 체이닝의 마지막 결과값을 함수의 결과로 반환해 줄 수 있습니다. (이 경우 <code>blob()</code> 혹은 <code>text()</code>메서드에 의해 반환된 Promise 입니다.) 사실상 <code>fetch()</code> 앞의 <code>return</code> 구문은 체이닝 결과를 다시 상단으로 전달하는 행위 입니다.</li> + </ul> + </li> + <li> + <p>블럭의 마지막에는 <code>.catch()</code> 블럭을 추가하여 작업중 발생한 에러를 <code>.all()</code>의 배열로 전달합니다. 아무 Promise에서 reject가 발생하면, catch 블럭은 어떤 Promise에서 에러가 발생했는지 알려줄 것 입니다. <code>.all()</code> (아래쪽에 있는) 블럭의 리소스에 문제가 있지 않는 이상 항상 fulfil일것 입니다. <code>.all</code> 블럭의 마지막 체이닝에 <code>.catch()</code> 블럭을 추가하여 reject됐을때 확인을 할 수 있습니다.</p> + </li> + </ol> + + <p>함수의 body 안에 있는 코드는 비동기적이고 Promise 기반이므로, 전체 함수는 Promise로 작동합니다. — 편리하죠?.</p> + </li> + <li> + <p>다음으로 fetchAndDecode() 함수를 세 번 호출하여 이미지와 텍스트를 가져오고 디코딩 하는 과정을 시작합니다. 그리고 반환된 Promise를 각각의 변수에 저장합니다. 이전 코드에 이어서 아래 코드를 추가하세요. :</p> + + <pre class="brush: js notranslate">let coffee = fetchAndDecode('coffee.jpg', 'blob'); +let tea = fetchAndDecode('tea.jpg', 'blob'); +let description = fetchAndDecode('description.txt', 'text');</pre> + </li> + <li> + <p>다음으로 위의 세 가지 코드가 모두 fulfilled가 됐을 때 원하는 코드를 실행하기 위해 <code>Promise.all()</code> 블럭을 만듭니다. 우선, <code>.then()</code> call 안에 비어있는 executor 를 추가하세요 :</p> + + <pre class="brush: js notranslate">Promise.all([coffee, tea, description]).then(values => { + +});</pre> + + <p>위에서 Promise를 포함하는 배열을 매개 변수로 사용하는 것을 확인할 수 있습니다. executor는 세 가지 Promise가 resolve될 때만 실행될 것 입니다. 그리고 executor가 실행될 때 개별적인 Promise의 결과를 포함하는 [coffee-results, tea-results, description-results] 배열을 매개 변수로 전달받을 것 입니다. (여기선 디코딩된 Response Body 입니다.).</p> + </li> + <li> + <p>마지막으로 executor 함수를 작성합니다. 예제에선 반환된 결과를 별도의 변수로 저장하기 위해 간단한 동기화 코드를 사용합니다. (Blob에서 오브젝트 URLs 생성), 그리고 페이지에 텍스트와 이미지를 표시합니다.</p> + + <pre class="brush: js notranslate">console.log(values); +// Store each value returned from the promises in separate variables; create object URLs from the blobs +let objectURL1 = URL.createObjectURL(values[0]); +let objectURL2 = URL.createObjectURL(values[1]); +let descText = values[2]; + +// Display the images in <img> elements +let image1 = document.createElement('img'); +let image2 = document.createElement('img'); +image1.src = objectURL1; +image2.src = objectURL2; +document.body.appendChild(image1); +document.body.appendChild(image2); + +// Display the text in a paragraph +let para = document.createElement('p'); +para.textContent = descText; +document.body.appendChild(para);</pre> + </li> + <li> + <p>코드를 저장하고 창을 새로고치면 보기엔 좋지 않지만, UI 구성 요소가 모두 표시된 것을 볼 수 있습니다.</p> + </li> +</ol> + +<p>여기서 제공한 코드는 매우 기초적이지만, 내용을 전달하기에는 아주 좋습니다..</p> + +<div class="blockIndicator note"> +<p><strong>Note</strong>: If you get stuck, you can compare your version of the code to ours, to see what it is meant to look like — <a href="https://mdn.github.io/learning-area/javascript/asynchronous/promises/promise-all.html">see it live</a>, and see the <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/promises/promise-all.html">source code</a>.</p> +</div> + +<div class="blockIndicator note"> +<p><strong>Note</strong>: If you were improving this code, you might want to loop through a list of items to display, fetching and decoding each one, and then loop through the results inside <code>Promise.all()</code>, running a different function to display each one depending on what the type of code was. This would make it work for any number of items, not just three.</p> + +<p>Also, you could determine what the type of file is being fetched without needing an explicit <code>type</code> property. You could, for example, check the {{HTTPHeader("Content-Type")}} HTTP header of the response in each case using <code><a href="/en-US/docs/Web/API/Headers/get">response.headers.get("content-type")</a></code>, and then react accordingly.</p> +</div> + +<h2 id="Running_some_final_code_after_a_promise_fulfillsrejects">Running some final code after a promise fulfills/rejects</h2> + +<p>Promise의 결과가 fulfilled 인지 rejected인지 관계 없이 Promise가 완료된 후 최종 코드 블럭을 실행하려는 경우가 있을 것입니다. 이전에는 아래 예시처럼 <code>.then()</code> 블럭과<code>.catch()</code> 블럭의 callbacks에 아래와 같이 runFinalCode()를 넣었었습니다. :</p> + +<pre class="brush: js notranslate">myPromise +.then(response => { + doSomething(response); + runFinalCode(); +}) +.catch(e => { + returnError(e); + runFinalCode(); +});</pre> + +<p>보다 최근의 현대 브라우저에서는 <code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/finally">.finally()</a></code> 메서드를 사용할 수 있습니다. 이 메서드를 Promise 체이닝의 끝에 배치하여 코드 반복을 줄이고 좀 더 우아하게 일을 처리할 수 있습니다. 아래와 같이 마지막 블럭에 적용할 수 있습니다. :</p> + +<pre class="brush: js notranslate">myPromise +.then(response => { + doSomething(response); +}) +.catch(e => { + returnError(e); +}) +.finally(() => { + runFinalCode(); +});</pre> + +<p>실제 예시는 <a href="https://mdn.github.io/learning-area/javascript/asynchronous/promises/promise-finally.html">promise-finally.html demo</a> 에 나와있습니다. (see the <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/promises/promise-finally.html">source code</a> also). 이 예시는 위에서 만들어본 <code>Promise.all()</code> 데모와 똑같이 작동합니다. 다만 이번에는 <code>fetchAndDecode()</code> 함수에 다음 연쇄 작업으로 <code>finally()</code> 를 호출합니다.:</p> + +<pre class="brush: js notranslate">function fetchAndDecode(url, type) { + return fetch(url).then(response => { + if(type === 'blob') { + return response.blob(); + } else if(type === 'text') { + return response.text(); + } + }) + .catch(e => { + console.log(`There has been a problem with your fetch operation for resource "${url}": ` + e.message); + }) + .finally(() => { + console.log(`fetch attempt for "${url}" finished.`); + }); +}</pre> + +<p>이 로그는 각 fetch시도가 완료되면 콘솔에 메시지를 출력하여 사용자에게 알려줍니다.</p> + +<div class="blockIndicator note"> +<p><strong>Note</strong>: <code>then()</code>/<code>catch()</code>/<code>finally()</code> is the async equivalent to <code>try</code>/<code>catch</code>/<code>finally</code> in sync code.</p> +</div> + +<h2 id="Building_your_own_custom_promises">Building your own custom promises</h2> + +<p>여기까지 오느라 수고하셨습니다. 여기까지 오면서 우리는 Promise를 직접 만들어봤습니다. 여러 개의 Promise를 <code>.then()</code> 을 사용하여 체이닝 하거나 사용자 정의함수를 조합하여, 비동기 Promise기반 함수를 만들었습니다. 이전에 만든 <code>fetchAndDecode()</code> 함수가 이를 잘 보여주고있죠.</p> + +<p>다양한 Promise 기반 API를 결합하여 사용자 정의 함수를 만드는 것은, Promise와 함께 원하는 기능을 만드는 가장 일반적인 방법이며, 대부분 모던 API는 이와 같은 원리를 기반으로 만들어지고 있습니다. 그리고 또 다른 방법이 있습니다.</p> + +<h3 id="Using_the_Promise_constructor">Using the Promise() constructor</h3> + +<p><code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise">Promise()</a></code> constructor를 사용하여 사용자 정의 Promise를 만들 수 있습니다. 주로 Promise기반이 아닌 구식 비동기 API코드를 Promise기반 코드로 만들고 싶을 경우 사용합니다. 이 방법은 구식 프로젝트 코드, 라이브러리, 혹은 프레임워크를 지금의 Promise 코드와 함께 사용할 때 유용합니다.</p> + +<p>간단한 예를 들어 살펴보겠습니다. — 여기 Promise와 함께 사용되는 <code><a href="/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setTimeout">setTimeout()</a></code> 호출이 있습니다. — 이 함수는 2초 후에 "Success!"라는 문자열과 함께 resolve됩니다. (통과된 <code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/resolve">resolve()</a></code> 호출에 의해);</p> + +<pre class="brush: js notranslate">let timeoutPromise = new Promise((resolve, reject) => { + setTimeout(function(){ + resolve('Success!'); + }, 2000); +});</pre> + +<p><code>resolve()</code> 와<code>reject()</code> 는 Promise의 fulful / reject일때의 일을 수행하기 위해 호출한 함수입니다. 이번의 경우 Promise는 "Success!"문자와 함께 fulfill 됐습니다.</p> + +<p>따라서 이 Promise를 호출할 때, 그 끝에 <code>.then()</code> 블럭을 사용하면 "Success!" 문자열이 전달될 것입니다. 아래 코드는 간단한 alert메시지를 출력하는 방법 입니다. :</p> + +<pre class="brush: js notranslate">timeoutPromise +.then((message) => { + alert(message); +})</pre> + +<p>혹은 아래처럼 쓸 수 있죠</p> + +<pre class="brush: js notranslate">timeoutPromise.then(alert); +</pre> + +<p>Try <a href="https://mdn.github.io/learning-area/javascript/asynchronous/promises/custom-promise.html">running this live</a> to see the result (also see the <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/promises/custom-promise.html">source code</a>).</p> + +<p>위의 예시는 유연하게 적용된 예시가 아닙니다. — Promise는 항산 하나의 문자열로만 fulfil됩니다. 그리고 <code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/reject">reject()</a></code> 조건도 정의되어있지 않습니다. (사실, <code>setTimeout()</code> 은 실패 조건이 필요없습니다, 그러니 이 예제에서는 없어도 됩니다.).</p> + +<div class="blockIndicator note"> +<p><strong>Note</strong>: Why <code>resolve()</code>, and not <code>fulfill()</code>? The answer we'll give you, for now, is <em>it's complicated</em>.</p> +</div> + +<h3 id="Rejecting_a_custom_promise">Rejecting a custom promise</h3> + +<p><code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/reject">reject()</a></code> 메서드를 사용하여 Promise가 reject상태일 때 전달할 값을 지정할 수 있습니다. — <code>resolve()</code>와 똑같습니다. 여기엔 하나의 값만 들어갈 수 있습니다. Promise가 reject 되면 에러는 <code>.catch()</code> 블럭으로 전달됩니다.</p> + +<p>이전 예시를 좀 더 확장하여 <code>reject()</code> 을 추가하고, Promise가 fulfil일 때 다른 메시지도 전달할 수 있게 만들어봅시다.</p> + +<p>이전 예시 <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/promises/custom-promise.html">previous example</a>를 복사한 후 이미 있는 <code>timeoutPromise()</code> 함수를 아래처럼 정의해주세요. :</p> + +<pre class="brush: js notranslate">function timeoutPromise(message, interval) { + return new Promise((resolve, reject) => { + if (message === '' || typeof message !== 'string') { + reject('Message is empty or not a string'); + } else if (interval < 0 || typeof interval !== 'number') { + reject('Interval is negative or not a number'); + } else { + setTimeout(function(){ + resolve(message); + }, interval); + } + }); +};</pre> + +<p>함수를 살펴보면 두 가지 매개변수가 있습니다. — 출력할 메시지와(<font face="consolas, Liberation Mono, courier, monospace"><span style="background-color: rgba(220, 220, 220, 0.5);">message</span></font>) 메시지를 출력할 때 까지 기다릴 시간(<code>interval</code>)입니다. 맨 위에 <code>Promise</code> 오브젝트를 반환하도록 되어있습니다. 따라서 함수를 실행하면 우리가 사용하고 싶은 Promise가 반환될 것 입니다..</p> + +<p>Promise constructor 안에는 몇가지 사항을 확인하기 위해 <code>if ... else</code> 구문이 있습니다. :</p> + +<ol> + <li>첫번째로 메시지의 유효성을 검사합니다. 메시지가 비어있거나 문자가 아닌 경우, 에러 메시지와 함께 Promise를 reject합니다.</li> + <li>그 다음으로 interval의 유효성을 검사합니다. 숫자가 아니거나 음수일 경우, 에러 메시지와 함께 Promise를 reject합니다.</li> + <li>마지막은 항목은, 두 매개변수를 확인하여 유효할 경우 <code>setTimeout()</code>함수에 지정된 interval에 맞춰 Promise를 resolve합니다.</li> +</ol> + +<p><code>timeoutPromise()</code> 함수는 <code>Promise</code>를 반환하므로, <code>.then()</code>, <code>.catch()</code>, 기타등등 을 사용해 Promise 체이닝을 만들 수 있습니다. 아래와 같이 작성해봅시다. — 기존에 있는 <code>timeoutPromise</code> 를 삭제하고 아래처럼 바꿔주세요. :</p> + +<pre class="brush: js notranslate">timeoutPromise('Hello there!', 1000) +.then(message => { + alert(message); +}) +.catch(e => { + console.log('Error: ' + e); +});</pre> + +<p>이 코드를 저장하고 브라우저를 새로 고침하면 1초 후에 'Hello there!' alert가 출력될 것 입니다. 이제 메시지 내용을 비우거나 interval을 음수로 지정해보세요 그렇게 하면 Promise가 reject되며 에러 메시지를 콘솔에 출력해 줄 것입니다. 또한 resolved 메시지를 다르게 만들어 줄 수도 있습니다.</p> + +<div class="blockIndicator note"> +<p><strong>Note</strong>: You can find our version of this example on GitHub as <a href="https://mdn.github.io/learning-area/javascript/asynchronous/promises/custom-promise2.html">custom-promise2.html</a> (see also the <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/promises/custom-promise2.html">source code</a>).</p> +</div> + +<h3 id="A_more_real-world_example">A more real-world example</h3> + +<p>위의 예제는 개념을 이해하기 쉽게 단순하게 만들었지만, 실제로 그다지 비동기적이지는 않습니다. 억지로 비동기적 작업을 구현하기 위해 <code>setTimeout()</code>을 사용하여 함수를 만들었지만 사용자 정의 Promise를 만들고 에러를 다루기엔 충분한 예제였습니다.</p> + +<p>좀 더 공부해볼 추가내용을 소개해주고 싶습니다. 바로 <a href="https://github.com/jakearchibald/idb/">Jake Archibald's idb library</a>입니다 이 라이브러리는 <code>Promise()</code> constructor의 비동기작업 응용을 보여주는 유용한 라이브러리 입니다. 클라이언트측에서 데이터를 저장하고 검색하기 위한 구식 callback 기반 API로 Promise와 함께 사용하는 <a href="/en-US/docs/Web/API/IndexedDB_API">IndexedDB API</a>입니다. <a href="https://github.com/jakearchibald/idb/blob/master/lib/idb.js">main library file</a>을 살펴보면 우리가 지금까지 다뤄본것과 같은 종류의 테크닉을 볼 수 있습니다. 아래 코드 블록은 basic request model이 Promise를 사용하게끔 변환해 주는 IndexedDB 메서드 입니다. :</p> + +<pre class="brush: js notranslate">function promisifyRequest(request) { + return new Promise(function(resolve, reject) { + request.onsuccess = function() { + resolve(request.result); + }; + + request.onerror = function() { + reject(request.error); + }; + }); +}</pre> + +<p>우리가 했던것 처럼 적절한 타이밍에 Promise를 fulfil하고 reject하는 이벤트 핸들러를 두 개 추가했습니다. :</p> + +<ul> + <li><code><a href="/en-US/docs/Web/API/IDBRequest">request</a></code>의 <a href="/en-US/docs/Web/API/IDBRequest/success_event"><code>success</code> event</a>가 실행될 때, <code><a href="/en-US/docs/Web/API/IDBRequest/onsuccess">onsuccess</a></code> 핸들러에 의해 fulfill된 Promise의 request <code><a href="/en-US/docs/Web/API/IDBRequest/result">result</a></code>를 반환한다.</li> + <li>반면 <code><a href="/en-US/docs/Web/API/IDBRequest">request</a></code>'s <a href="/en-US/docs/Web/API/IDBRequest/error_event"><code>error</code> event</a>가 실행되면 <code><a href="/en-US/docs/Web/API/IDBRequest/onerror">onerror</a></code> 핸들러에 의해 reject된 Promise의 request <code><a href="/en-US/docs/Web/API/IDBRequest/error">error</a></code>를 반환한다.</li> +</ul> + +<h2 id="Conclusion">Conclusion</h2> + +<p>Promises are a good way to build asynchronous applications when we don’t know the return value of a function or how long it will take to return. They make it easier to express and reason about sequences of asynchronous operations without deeply nested callbacks, and they support a style of error handling that is similar to the synchronous <code>try...catch</code> statement.</p> + +<p>Promises work in the latest versions of all modern browsers; the only place where promise support will be a problem is in Opera Mini and IE11 and earlier versions.</p> + +<p>We didn't touch on all promise features in this article, just the most interesting and useful ones. As you start to learn more about promises, you'll come across further features and techniques.</p> + +<p>Most modern Web APIs are promise-based, so you'll need to understand promises to get the most out of them. Among those APIs are <a href="/en-US/docs/Web/API/WebRTC_API">WebRTC</a>, <a href="/en-US/docs/Web/API/Web_Audio_API">Web Audio API</a>, <a href="/en-US/docs/Web/API/Media_Streams_API">Media Capture and Streams</a>, and many more. Promises will be more and more important as time goes on, so learning to use and understand them is an important step in learning modern JavaScript.</p> + +<h2 id="See_also">See also</h2> + +<ul> + <li><code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise">Promise()</a></code></li> + <li><a href="/en-US/docs/Web/JavaScript/Guide/Using_promises">Using promises</a></li> + <li><a href="https://pouchdb.com/2015/05/18/we-have-a-problem-with-promises.html">We have a problem with promises</a> by Nolan Lawson</li> +</ul> + +<p>{{PreviousMenuNext("Learn/JavaScript/Asynchronous/Timeouts_and_intervals", "Learn/JavaScript/Asynchronous/Async_await", "Learn/JavaScript/Asynchronous")}}</p> + +<h2 id="In_this_module">In this module</h2> + +<ul> + <li><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Concepts">General asynchronous programming concepts</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Introducing">Introducing asynchronous JavaScript</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Timeouts_and_intervals">Cooperative asynchronous JavaScript: Timeouts and intervals</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Promises">Graceful asynchronous programming with Promises</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Async_await">Making asynchronous programming easier with async and await</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Choosing_the_right_approach">Choosing the right approach</a></li> +</ul> diff --git a/files/ko/learn/javascript/asynchronous/timeouts_and_intervals/index.html b/files/ko/learn/javascript/asynchronous/timeouts_and_intervals/index.html new file mode 100644 index 0000000000..1f3d4f2a6a --- /dev/null +++ b/files/ko/learn/javascript/asynchronous/timeouts_and_intervals/index.html @@ -0,0 +1,598 @@ +--- +title: 'Cooperative asynchronous JavaScript: Timeouts and intervals' +slug: Learn/JavaScript/Asynchronous/Timeouts_and_intervals +translation_of: Learn/JavaScript/Asynchronous/Timeouts_and_intervals +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/JavaScript/Asynchronous/Introducing", "Learn/JavaScript/Asynchronous/Promises", "Learn/JavaScript/Asynchronous")}}</div> + +<p class="summary">이 장에서는 자바스크립트가 설정된 시간이 경과하거나 혹은 정해진 시간 간격(예 : 초당 설정된 횟수)으로 비동기 코드를 작동하는 전형적인 방법을 살펴본다. 그리고 이 방법들이 어떤 것에 유용한지 얘기해 보고, 그 본질적인 문제에 대해 살펴본다.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Prerequisites:</th> + <td>Basic computer literacy, a reasonable understanding of JavaScript fundamentals.</td> + </tr> + <tr> + <th scope="row">Objective:</th> + <td>To understand asynchronous loops and intervals and what they are useful for.</td> + </tr> + </tbody> +</table> + +<h2 id="Introduction">Introduction</h2> + +<p>오랜 시간 동안 웹플랫폼은 자바스크립트 프로그래머가 일정한 시간이 흐른 뒤에 비동기적 코드를 실행할 수 있게하는 다양한 함수들을 제공해 왔다. 그리고 프로그래머가 중지시킬 때까지 코드 블록을 반복적으로 실행하기 위한 다음과 같은 함수들이 있다.</p> + +<dl> + <dt><code><a href="/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setTimeout">setTimeout()</a></code></dt> + <dd>특정 시간이 경과한 뒤에 특정 코드블록을 한번 실행한다.</dd> + <dt></dt> + <dt><code><a href="/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setInterval">setInterval()</a></code></dt> + <dd>각각의 호출 간에 일정한 시간 간격으로 특정 코드블록을 반복적으로 실행한다.</dd> + <dt><code><a href="/en-US/docs/Web/API/window/requestAnimationFrame">requestAnimationFrame()</a></code></dt> + <dd>setInterval()의 최신 버전; 그 코드가 실행되는 환경에 관계없이 적절한 프레임 속도로 애니메이션을 실행시키면서, 브라우저가 다음 화면을 보여주기 전에 특정 코드블록을 실행한다.</dd> +</dl> + +<p>이 함수들에 의해 설정된 비동기 코드는 메인 스레드에서 작동한다. 그러나 프로세서가 이러한 작업을 얼마나 많이 수행하는지에 따라, 코드가 반복되는 중간에 다른 코드를 어느 정도 효율적으로 실행할 수 있다. 어쨌든 이러한 함수들은 웹사이트나 응용 프로그램에서 일정한 애니메이션 및 기타 배경 처리를 실행하는 데 사용된다. 다음 섹션에서는 그것들을 어떻게 사용할 수 있는지 보여줄 것이다.</p> + +<h2 id="setTimeout">setTimeout()</h2> + +<p>앞에서 언급했듯이 setTimeout ()은 지정된 시간이 경과 한 후 특정 코드 블록을 한 번 실행한다. 그리고 다음과 같은 파라미터가 필요하다.:</p> + +<ul> + <li>실행할 함수 또는 다른 곳에 정의 된 함수 참조.</li> + <li>코드를 실행하기 전에 대기 할 밀리세컨드 단위의 시간 간격 (1000밀리세컨드는 1 초)을 나타내는 숫자. 값을 0으로 지정하면(혹은 이 값을 모두 생략하면) 함수가 즉시 실행된다. 왜 이 파라미터를 수행해야 하는지도 좀 더살펴 볼 것이다. </li> + <li>함수가 실행될 때 함수에 전달해야할 파라미터를 나타내는 0이상의 값.</li> +</ul> + +<div class="blockIndicator note"> +<p><strong>Note:</strong> 타임아웃 콜백은 단독으로 실행되지 않기 때문에 지정된 시간이 지난 그 시점에 정확히 콜백 될 것이라는 보장은 없다. 그보다는 최소한 그 정도의 시간이 지난 후에 호출된다. 메인 스레드가 실행해야 할 핸들러를 찾기 위해 이런 핸들러들을 살펴보는 시점에 도달할 때까지 타임아웃 핸들러를 실행할 수 없다.</p> +</div> + +<p>아래 예제에서 브라우저는 2분이 지나면 익명의 함수를 실행하고 경보 메시지를 띄울 것이다. (<a href="https://mdn.github.io/learning-area/javascript/asynchronous/loops-and-intervals/simple-settimeout.html">see it running live</a>, and <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/loops-and-intervals/simple-settimeout.html">see the source code</a>):</p> + +<pre class="brush: js">let myGreeting = setTimeout(function() { + alert('Hello, Mr. Universe!'); +}, 2000)</pre> + +<p>지정한 함수가 꼭 익명일 필요는 없다. 함수에 이름을 부여 할 수 있고, 다른 곳에서 함수를 정의하고 setTimeout ()에 참조(reference)를 전달할 수도 있다. 아래 코드는 위의 코드와 같은 실행 결과를 얻을 수 있다. </p> + +<pre class="brush: js">// With a named function +let myGreeting = setTimeout(function sayHi() { + alert('Hello, Mr. Universe!'); +}, 2000) + +// With a function defined separately +function sayHi() { + alert('Hello Mr. Universe!'); +} + +let myGreeting = setTimeout(sayHi, 2000);</pre> + +<p>예를 들자면 timeout 함수와 이벤트에 의해 중복 호출되는 함수를 사용하려면 이 방법이 유용할 수 있다. 이 방법은 코드라인을 깔끔하게 정리하는 데 도움을 준다. 특히 timeout 콜백의 코드라인이 여러 줄이라면 더욱 그렇다. </p> + +<p>setTimeout ()은 나중에 타임아웃을 할 경우에 타임아웃을 참조하는데 사용하는 식별자 값을 리턴한다. 그 방법을 알아 보려면 아래{{anch("Clearing timeouts")}}을 참조하세요.</p> + +<h3 id="setTimeout_함수에_매개변수parameter_전달">setTimeout () 함수에 매개변수(parameter) 전달</h3> + +<p>setTimeout () 내에서 실행되는 함수에 전달하려는 모든 매개변수는 setTimeout () 매개변수 목록 끝에 추가하여 전달해야 한다. 아래 예제처럼, 이전 함수를 리팩터링하여 전달된 매개변수의 사람 이름이 추가된 문장을 표시할 수 있다.</p> + +<pre class="brush: js">function sayHi(who) { + alert('Hello ' + who + '!'); +}</pre> + +<p>Say hello의 대상이 되는 사람이름은 <code>setTimeout()의 세번째 매개변수로 함수에 전달된다.</code></p> + +<pre class="brush: js">let myGreeting = setTimeout(sayHi, 2000, 'Mr. Universe');</pre> + +<h3 id="timeout_취소">timeout 취소</h3> + +<p>마지막으로 타임아웃이 생성되면(setTimeout()이 실행되면) 특정시간이 경과하기 전에 <code><a href="/en-US/docs/Web/API/WindowOrWorkerGlobalScope/clearTimeout">clearTimeout()</a></code>을 호출하여 타임아웃을 취소할 수 있다. <code><a href="/en-US/docs/Web/API/WindowOrWorkerGlobalScope/clearTimeout">clearTimeout()</a></code>은 <code>setTimeout()</code>콜의 식별자를 매개변수로 <code>setTimeout()</code>에 전달한다. 위 예제의 타임아웃을 취소하려면 아래와 같이 하면 된다.</p> + +<pre class="brush: js">clearTimeout(myGreeting);</pre> + +<div class="blockIndicator note"> +<p><strong>Note</strong>: 인사를 할 사람의 이름을 설정하고 별도의 버튼을 사용하여 인사말을 취소 할 수있는 약간 더 복잡한 폼양식 예제인 <a href="https://mdn.github.io/learning-area/javascript/asynchronous/loops-and-intervals/greeter-app.html">greeter-app.html</a> 을 참조하세요.</p> +</div> + +<h2 id="setInterval">setInterval()</h2> + +<p>setTimeout ()은 일정 시간이 지난 후 코드를 한 번 실행해야 할 때 완벽하게 작동합니다. 그러나 애니메이션의 경우와 같이 코드를 반복해서 실행해야 할 경우 어떨까요?</p> + +<p>이럴 경우에 setInterval ()이 필요합니다. setInterval ()은 setTimeout ()과 매우 유사한 방식으로 작동합니다. 다만 setTimeout ()처럼 첫 번째 매개 변수(함수)가 타임아웃 후에 한번 실행되는게 아니라 두 번째 매개 변수에 주어진 시간까지 반복적으로 실행되는 것이 차이점입니다. setInterval() 호출의 후속 파라미터로 실행 중인 함수에 필요한 파라미터를 전달할 수도 있다.</p> + +<p>예를 들어 봅시다. 다음 함수는 새 Date() 객체를 생성한 후에 ToLocaleTimeString()을 사용하여 시간데이터를 문자열로 추출한 다음 UI에 표시합니다. 그리고 setInterval()을 사용하여 초당 한 번 함수(displayTime)를 실행하면 초당 한 번 업데이트되는 디지털 시계와 같은 효과를 만들어냅니다.(<a href="https://mdn.github.io/learning-area/javascript/asynchronous/loops-and-intervals/setinterval-clock.html">see this live</a>, and also <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/loops-and-intervals/setinterval-clock.html">see the source</a>): </p> + +<pre class="brush: js">function displayTime() { + let date = new Date(); + let time = date.toLocaleTimeString(); + document.getElementById('demo').textContent = time; +} + +const createClock = setInterval(displayTime, 1000);</pre> + +<p>setTimeout()과 같이 setInterval()도 식별자 값을 리턴하여 나중에 interval을 취소해야 할 때 사용한다.</p> + +<h3 id="interval_취소">interval 취소</h3> + +<p>setInterval ()은 아무 조치를 취하지 않으면 끊임없이 계속 실행됩니다. 이 상태를 중지하는 방법이 필요합니다. 그렇지 않으면 브라우저가 추가 작업을 완료 할 수 없거나, 현재 처리 중인 애니메이션이 완료되었을 때 오류가 발생할 수 있습니다. setTimeout()과 같은 방식으로 setInterval () 호출에 의해 반환 된 식별자를 clearInterval () 함수에 전달하여 이 작업을 취소할수 있습니다.</p> + +<pre class="brush: js">const myInterval = setInterval(myFunction, 2000); + +clearInterval(myInterval);</pre> + +<h4 id="능동학습_자신만의_스톱워치를_만들기.">능동학습 : 자신만의 스톱워치를 만들기.</h4> + +<p>위에서 모두 설명해 드렸으니, 과제를 드리겠습니다. <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/loops-and-intervals/setinterval-clock.html">setInterval-clock.html</a> 예제를 수정하여 자신만의 간단한 스톱워치를 만들어 보세요.</p> + +<p>위에서 설명(디지털 시계)한 것처럼 시간을 표시해야 하고, 이 예제에서는 아래 기능을 추가하세요.</p> + +<ul> + <li>스톱워치를 실행시키는 "Start" 버튼. </li> + <li>일시정지나 종료시키는 "Stop" 버튼.</li> + <li>시간을 0으로 설정하는 "Reset" 버튼.</li> + <li>실제 시간을 표시하지 말고 경과된 시간을 초단위로 표시..</li> +</ul> + +<p>몇가지 힌트를 드립니다.</p> + +<ul> + <li>버튼 마크업은 여러분이 원하는 대로 구성하고 스타일링 하세요. 자바스크립트 버튼 레퍼런스를 가져올 수 있는 후크를 포함한 semantic HTML을 사용하세요.</li> + <li> 0에서 시작하여 상수 루프를 이용하여 1 초 단위로 증가하는 변수를 작성해 보세요.</li> + <li>앞서 설명한 Date () 객체를 사용하지 않고 이 예제를 작성하는 것이 더 쉽지만 정확도는 떨어집니다. 정확히 1000ms 후에 콜백이 시작된다고 보장 할 수는 없기 때문입니다. 보다 정확한 방법은 startTime = Date.now ()를 실행하여 사용자가 시작 버튼을 클릭했을 때 정확한 timestamp을 얻은 다음 Date.now ()-startTime을 실행하여 시간(milliseconds)을 얻어 냅니다.</li> + <li>시, 분, 초 단위의 시간을 별도의 변수를 통해 계산한 다음 각 루프 반복 후에 문자열로 함께 표시해 보세요. 두 번째 카운터에서 하나씩 해결할 수 있습니다.</li> + <li>어떻게 계산할 것인지 생각해 봅시다. + <ul> + <li>1시간은 3600초 입니다.</li> + <li>분단위 시간은 시간을 60으로 나눈 값에서 시간단위를 제거한 값입니다. 그리고 초단위 시간은 그 값에서 분단위 시간을 제거한 값입니다(예 :3700초를 60초로 나누면 3600초(시단위) + 100초(분단위), 분단위를 다시 60으로 나누면 60초(분단위) + 40초(초단위))</li> + </ul> + </li> + <li>시간값이 10밀리세컨드이하면 화면의 시간을 0으로 표시하세요. 더 일반적인 시계처럼 보일 겁니다.</li> + <li>스톱워치를 정지시키기 위해 interval을 취소해 보세요. 스톱워치를 리셋하기 위해 시간 카운터를 0으로 설정하고, interval을 취소한 후에 화면을 즉시 업데이트 하세요.</li> + <li>스타트 버튼이 클릭되면 버튼을 즉시 비활성화 시키고 스톱/리셋버튼이 클릭되면 다시 활성화해 보세요. 그렇지 않고 스타트 버튼이 여러번 클릭되면 setInterval()이 중복 실행되어서 실행 오류가 발생할 수 있습니다.</li> +</ul> + +<div class="blockIndicator note"> +<p><strong>Note</strong>: If you get stuck, you can <a href="https://mdn.github.io/learning-area/javascript/asynchronous/loops-and-intervals/setinterval-stopwatch.html">find our version here</a> (see the <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/loops-and-intervals/setinterval-stopwatch.html">source code</a> also).</p> +</div> + +<h2 id="setTimeout과_setInterval에서_주의해야할_것_들">setTimeout()과 setInterval()에서 주의해야할 것 들</h2> + +<p>setTimeout()과 setInterval()에는 몇가지 주의해야 할 것들이 있습니다. 어떤 것인지 한번 살펴보겠습니다.</p> + +<h3 id="순환_timeouts">순환 timeouts</h3> + +<p>setTimeout()을 사용하는 또 다른 방법입니다. 바로 setInterval()을 사용하는 대신 setTimeout()을 이용해 같은코드를 반복적으로 실행시키는 방법입니다.</p> + +<p>The below example uses a recursive <code>setTimeout()</code> to run the passed function every 100 milliseconds: 아래 예제에서는 setTimeout()이 주어진 함수를 100밀리세컨드마다 실행합니다.</p> + +<pre class="brush: js">let i = 1; + +setTimeout(function run() { + console.log(i); + i++; + setTimeout(run, 100); +}, 100);</pre> + +<p>위 예제를 아래 예제와 비교해 보세요. 아래 예제는 setInterval()을 사용하여 같은 결과를 얻을 수 있습니다.</p> + +<pre class="brush: js">let i = 1; + +setInterval(function run() { + console.log(i); + i++ +}, 100);</pre> + +<h4 id="그렇다면_순환_setTimeout과_setInterval은_어떻게_다를까요">그렇다면 순환 setTimeout()과 setInterval()은 어떻게 다를까요?</h4> + +<p>두 방법의 차이는 미묘합니다.</p> + +<ul> + <li>순환 setTimeout ()은 실행과 실행 사이에 동일한 지연을 보장합니다. 위의 경우 100ms입니다. 코드가 실행 된 후 다시 실행되기 전에 100 ms 동안 대기하므로 간격은 코드 실행 시간에 관계없이 동일합니다.</li> + <li>setInterval ()을 사용하는 예제는 약간 다르게 작동합니다. 설정된 간격에는 실행하려는 코드를 실행하는 데 걸리는 시간이 포함됩니다. 코드를 실행하는 데 40ms가 걸리다면 간격이 60ms에 불과합니다.</li> + <li>setTimeout ()을 재귀적으로 사용할 때 각 반복은 다음 반복을 실행하기 전에 또 하나의 대기시간을 설정합니다. 즉, setTimeout ()의 두 번째 매개 변수의 값은 코드를 다시 실행하기 전에 대기 할 또 하나의 시간을 지정합니다.</li> +</ul> + +<p>코드가 지정한 시간 간격보다 실행 시간이 오래 걸리면 순환 setTimeout ()을 사용하는 것이 좋습니다. 이렇게하면 코드 실행 시간에 관계없이 실행 간격이 일정하게 유지되어 오류가 발생하지 않습니다.</p> + +<h3 id="즉시_timeouts">즉시 timeouts</h3> + +<p>setTimeout()의 값으로 0을 사용하면 메인 코드 스레드가 실행된 후에 가능한 한 빨리 지정된 콜백 함수의 실행을 예약할 수 있다.</p> + +<p>예를 들어 아래 코드 (<a href="https://mdn.github.io/learning-area/javascript/asynchronous/loops-and-intervals/zero-settimeout.html">see it live</a>) 는 "Hello"가 포함된 alert를 출력 한 다음 첫 번째 경고에서 OK를 클릭하자마자 "World"가 포함된 alert를 출력합니다.</p> + +<pre class="brush: js">setTimeout(function() { + alert('World'); +}, 0); + +alert('Hello');</pre> + +<p>이것은 모든 메인 스레드의 실행이 완료되자마자 실행되도록 코드 블록을 설정하려는 경우 유용할 할 수 있습니다. 비동기 이벤트 루프에 배치하면 곧바로 실행될 겁니다.</p> + +<h3 id="clearTimeout_와_clearInterval의_취소기능">clearTimeout() 와 clearInterval()의 취소기능</h3> + +<p>clearTimeout ()과 clearInterval ()은 모두 동일한 entry를 사용하여 대상 메소드(setTimeout () 또는 setInterval ())을 취소합니다. 흥미롭게도 이는 setTimeout () 또는 setInterval ()을 지우는 데 clearTimeout ()과 clearInterval ()메소드 어느 것을 사용해도 무방합니다.</p> + +<p>그러나 일관성을 유지하려면 clearTimeout ()을 사용하여 setTimeout () 항목을 지우고 clearInterval ()을 사용하여 setInterval () 항목을 지우십시오. 혼란을 피하는 데 도움이됩니다.</p> + +<h2 id="requestAnimationFrame">requestAnimationFrame()</h2> + +<p>requestAnimationFrame ()은 브라우저에서 애니메이션을 효율적으로 실행하기 위해 만들어진 특수한 반복 함수입니다. 근본적으로 setInterval ()의 최신 버전입니다. 브라우저가 다음에 디스플레이를 다시 표시하기 전에 지정된 코드 블록을 실행하여 애니메이션이 실행되는 환경에 관계없이 적절한 프레임 속도로 실행될 수 있도록합니다.</p> + +<p>setInterval ()을 사용함에 있어 알려진 문제점을 개선하기위해 만들어졌습니다. 예를 들어 장치에 최적화 된 프레임 속도로 실행되지 않는 문제, 때로는 프레임을 빠뜨리는 문제, 탭이 활성 탭이 아니거나 애니메이션이 페이지를 벗어난 경우에도 계속 실행되는 문제 등등이다 . <a href="http://creativejs.com/resources/requestanimationframe/index.html">CreativeJS에서 이에 대해 자세히 알아보십시오.</a></p> + +<div class="blockIndicator note"> +<p><strong>Note</strong>: requestAnimationFrame() 사용에 관한 예제들은 이 코스의 여러곳에서 찾아볼 수 있습니다. <a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Drawing_graphics">Drawing graphics</a> 와 <a href="/en-US/docs/Learn/JavaScript/Objects/Object_building_practice">Object building practice</a> 의 예제를 찾아 보세요.</p> +</div> + +<p>이 메소드는 화면을 다시 표시하기 전에 호출 할 콜백을 인수로 사용합니다. 이것이 일반적인 패턴입니다. 아래는 사용예를 보여줍니다.</p> + +<pre class="brush: js">function draw() { + // Drawing code goes here + requestAnimationFrame(draw); +} + +draw();</pre> + +<p>그 발상은 애니메이션을 업데이트하는 함수 (예 : 스프라이트 이동, 스코어 업데이트, 데이터 새로 고침 등)를 정의한 후 그것을 호출하여 프로세스를 시작하는 것입니다. 함수 블록의 끝에서 매개 변수로 전달 된 함수 참조를 사용하여 requestAnimationFrame ()을 호출하면 브라우저가 다음 화면을 재표시할 때 함수를 다시 호출하도록 지시합니다. 그런 다음 requestAnimationFrame ()을 반복적으로 호출하므로 계속 실행되는 것입니다.</p> + +<div class="blockIndicator note"> +<p><strong>Note</strong>: 어떤 간단한 DOM 애니메이션을 수행하려는 경우, <a href="/en-US/docs/Web/CSS/CSS_Animations">CSS Animations</a> 은 JavaScript가 아닌 브라우저의 내부 코드로 직접 계산되므로 속도가 더 빠릅니다. 그러나 더 복잡한 작업을 수행하고 DOM 내에서 직접 액세스 할 수 없는 객체(예 :<a href="/en-US/docs/Web/API/Canvas_API">2D Canvas API</a> or <a href="/en-US/docs/Web/API/WebGL_API">WebGL</a> objects)를 포함하는 경우 대부분의 경우 requestAnimationFrame ()이 더 나은 옵션입니다. </p> +</div> + +<h3 id="여러분의_애니메이션의_작동속도는_얼마나_빠른가요">여러분의 애니메이션의 작동속도는 얼마나 빠른가요?</h3> + +<p>부드러운 애니메이션을 구현은 직접적으로 프레임 속도에 달려 있으며, 프레임속도는 초당 프레임 (fps)으로 측정됩니다. 이 숫자가 높을수록 애니메이션이 더 매끄럽게 보입니다.</p> + +<p>일반적으로 화면 재생률는 60Hz이므로 웹 브라우저를 사용할 때 여러분이 설정할 수 있는 가장 빠른 프레임 속도는 초당 60 프레임 (FPS)입니다. 이 속도보다 빠르게 설정하면 과도한 연산이 실행되어 화면이 더듬거리고 띄엄띄엄 표시될 수 있다. 이런 현상을 프레임 손실 또는 쟁크라고 한다. </p> + +<p>재생률 60Hz의 모니터에 60FPS를 달성하려는 경우 각 프레임을 렌더링하기 위해 애니메이션 코드를 실행하려면 약 16.7ms(1000/60)가 필요합니다. 그러므로 각 애니메이션 루프를 통과 할 때마다 실행하려고 하는 코드의 양을 염두에 두어야합니다.</p> + +<p>requestAnimationFrame()은 불가능한 경우에도 가능한한 60FPS 값에 가까워 지려고 노력합니다. 실제로 복잡한 애니메이션을 느린 컴퓨터에서 실행하는 경우 프레임 속도가 떨어집니다. requestAnimationFrame ()은 항상 사용 가능한 것을 최대한 활용합니다.</p> + +<h3 id="requestAnimationFrame이_setInterval_setTimeout과_다른점은">requestAnimationFrame()이 setInterval(), setTimeout()과 다른점은?</h3> + +<p>requestAnimationFrame () 메소드가 이전에 살펴본 다른 메소드와 어떻게 다른지에 대해 조금 더 이야기하겠습니다. 위의 코드를 다시 살펴보면;</p> + +<pre class="brush: js">function draw() { + // Drawing code goes here + requestAnimationFrame(draw); +} + +draw();</pre> + +<p>setInterval()을 사용하여 위와 같은 작업을 하는 방법을 살펴봅시다.</p> + +<pre class="brush: js">function draw() { + // Drawing code goes here +} + +setInterval(draw, 17);</pre> + +<p>앞에서언급했듯이 requestAnimationFrame ()은 시간 간격을 지정하지 않습니다. requestAnimationFrame ()은 현재 상황에서 최대한 빠르고 원활하게 실행됩니다. 어떤 이유로 애니메이션이 화면에 표시되지 않으면 브라우저는 그 애니메이션을 실행하는 데 시간을 낭비하지 않습니다.</p> + +<p>반면에 setInterval ()은 특정 시간간격을 필요로 합니다. 1000 ms/60Hz 계산을 통해 최종값 16.6에 도달 한 후 반올림(17)했습니다. 이때 반올림하는 것이 좋습니다. 그 이유는 반내림(16)을하면 60fps보다 빠르게 애니메이션을 실행하려고 하게 되지만 애니메이션의 부드러움에 아무런 영향을 미치지 않기 때문입니다. 앞에서 언급했듯이 60Hz가 표준 재생률입니다.</p> + +<h3 id="timestamp를_포함하기">timestamp를 포함하기</h3> + +<p>requestAnimationFrame() 함수에 전달 된 실제 콜백에는 requestAnimationFrame()이 실행되기 시작한 이후의 시간을 나타내는 timestamp를 매개변수로 제공할 수 있습니다. 장치 속도에 관계없이 특정 시간과 일정한 속도로 작업을 수행할 수 있으므로 유용합니다. 사용하는 일반적인 패턴은 다음과 같습니다.</p> + +<pre class="brush: js">let startTime = null; + +function draw(timestamp) { + if(!startTime) { + startTime = timestamp; + } + + currentTime = timestamp - startTime; + + // Do something based on current time + + requestAnimationFrame(draw); +} + +draw();</pre> + +<h3 id="브라우저_지원">브라우저 지원</h3> + +<p>requestAnimationFrame()은 setInterval() / setTimeout()보다 좀 더 최신 브라우저에서 지원됩니다. 가장 흥미롭게도 Internet Explorer 10 이상에서 사용할 수 있습니다. 따라서 별도의 코드로 이전 버전의 IE를 지원해야할 필요가 없다면, requestAnimationFrame()을 사용하지 않을 이유가 없습니다.</p> + +<h3 id="간단한_예">간단한 예</h3> + +<p>지금까지 이론적으로는 충분히 살펴보았습니다. 그러면 직접 requestAnimationFrame() 예제를 작성해 봅시다. 우리는 간단한 "스피너 애니메이션"을 만들 것입니다. 여러분들이 앱 사용중 서버 과부하일 때 이것을 자주 보았을 겁니다.</p> + +<div class="blockIndicator note"> +<p><strong>Note</strong>: 실제로는 CSS 애니메이션을 사용하여 이러한 종류의 간단한 애니메이션을 실행해야 합니다. 그러나 이러한 종류의 예제는 requestAnimationFrame() 사용법을 보여주는 데 매우 유용하며, 각 프레임에서 게임의 디스플레이를 업데이트하는 것과 같이 좀 더 복잡한 작업을 수행 할 때 이러한 종류의 기술을 사용하는 것이 좋습니다.</p> +</div> + +<ol> + <li> + <p>먼저 HTML 템플릿을 <a href="https://github.com/mdn/learning-area/blob/master/html/introduction-to-html/getting-started/index.html">여기</a>에서.가져옵니다.</p> + </li> + <li> + <p><body>안에 빈 <div> 요소를 삽입합니다. 그리고 ↻캐릭터를 그 안에 추가합니다. 이 예제에서 이 원형 화살표가 회전하게됩니다.</p> + </li> + <li> + <p>아래 CSS를 HTML 템플릿에 여러분이 원하는 방식으로 적용하세요. 이 CSS는 페이지 배경을 빨간색으로, <body>의 height를 html height의 100%로 설정합니다. 그리고 <div>를 수직, 수평으로 <body> 중앙에 위치 시킵니다.</p> + + <pre class="brush: css">html { + background-color: white; + height: 100%; +} + +body { + height: inherit; + background-color: red; + margin: 0; + display: flex; + justify-content: center; + align-items: center; +} + +div { + display: inline-block; + font-size: 10rem; +}</pre> + </li> + <li> + <p></body> 태크 위에 <script>를 추가하세요.</p> + </li> + <li> + <p><script> 안에 아래 자바스크립트 코드를 추가하세요. 여기에서 <div>의 참조를 상수로 저장하고, rotateCount 변수를 0으로 설정하고, 나중에 requestAnimationFrame()의 시작 시간을 저장할 startTime 변수를 null로 설정하고, 그리고 requestAnimationFrame() 콜의 참조를 저장할 초기화하지 않은 rAF 변수를 선언합니다.</p> + + <pre class="brush: js">const spinner = document.querySelector('div'); +let rotateCount = 0; +let startTime = null; +let rAF; +</pre> + </li> + <li> + <p>그 아래에 draw() 함수를 추가합니다. 이 함수는 timestamp 매개변수를 포함하는 애니메이션 코드 작성에 사용됩니다.</p> + + <pre class="brush: js">function draw(timestamp) { + +}</pre> + </li> + <li> + <p>draw() 함수안데 다음 코드를 추가합니다. if 조건문으로 startTime이 정의되지 않았다면 startTime을 정의합니다 (루프 반복의 첫번째에만 작동합니다). 그리고 스피너를 회전시키는 rotateCount 변수값을 설정합니다(현재 timestamp는 시작 timestamp를 3으로 나눈 것이라서 그리 빠르지 않습니다).</p> + + <pre class="brush: js"> if (!startTime) { + startTime = timestamp; + } + + rotateCount = (timestamp - startTime) / 3; +</pre> + </li> + <li> + <p>draw() 함수 안의 이전 코드 아래에 다음 블록을 추가합니다. 이렇게하면 rotateCount 값이 359보다 큰지 확인합니다 (예 : 360, 완전한 원). 그렇다면 값을 모듈러 360 (즉, 값을 360으로 나눌 때 남은 나머지)으로 설정하여 원 애니메이션이 합리적인 낮은 값으로 중단없이 계속 될 수 있습니다. 꼭 이렇게 해야되는 것은 아니지만 "128000도" 같은 값보다는 0~359 도의 값으로 작업하는 것이 더 쉽습니다.</p> + + <pre class="brush: js">if (rotateCount > 359) { + rotateCount %= 360; +}</pre> + </li> + <li>다음으로 아래 코드를 추가하세요. 실제 스피너를 회전시키는 코드입니다. + <pre class="brush: js">spinner.style.transform = 'rotate(' + rotateCount + 'deg)';</pre> + </li> + <li> + <p> draw() 함수 제일 아래에 다음 코드를 추가합니다. 이 코드는 모든 작업의 키 포인트입니다. draw() 함수를 매개변수로 가져오는 requestAnimationFrame() 콜을 저장하기 위해 앞에서 정의한 rAF 변수를 설정합니다. 이 코드는 애니메이션을 실행시키고, 가능한한 60fps에 근사하게 draw() 함수를 계속 실행합니다.</p> + + <pre class="brush: js">rAF = requestAnimationFrame(draw);</pre> + </li> +</ol> + +<div class="blockIndicator note"> +<p><strong>Note</strong>: You can find this <a href="https://mdn.github.io/learning-area/javascript/asynchronous/loops-and-intervals/simple-raf-spinner.html">example live on GitHub</a> (see the <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/loops-and-intervals/simple-raf-spinner.html">source code</a> also).</p> +</div> + +<h3 id="requestAnimationFrame_call의_취소">requestAnimationFrame() call의 취소</h3> + +<p>cancelAnimationFrame() 메소드를 호출하여 requestAnimationFrame()을 취소할 수 있다. (접두어가 "clear"가 아니고 "cancel"임에 유의) requestAnimationFrame()에 의해서 리턴된 rAF 변수값을 전달받아 취소한다. </p> + +<pre class="brush: js">cancelAnimationFrame(rAF);</pre> + +<h3 id="Active_learning_Starting_and_stopping_our_spinner">Active learning: Starting and stopping our spinner</h3> + +<p>In this exercise, we'd like you to test out the <code>cancelAnimationFrame()</code> method by taking our previous example and updating it, adding an event listener to start and stop the spinner when the mouse is clicked anywhere on the page.</p> + +<p>Some hints:</p> + +<ul> + <li>A <code>click</code> event handler can be added to most elements, including the document <code><body></code>. It makes more sense to put it on the <code><body></code> element if you want to maximize the clickable area — the event bubbles up to its child elements.</li> + <li>You'll want to add a tracking variable to check whether the spinner is spinning or not, clearing the animation frame if it is, and calling it again if it isn't.</li> +</ul> + +<div class="blockIndicator note"> +<p><strong>Note</strong>: Try this yourself first; if you get really stuck, check out of our <a href="https://mdn.github.io/learning-area/javascript/asynchronous/loops-and-intervals/start-and-stop-spinner.html">live example</a> and <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/loops-and-intervals/start-and-stop-spinner.html">source code</a>.</p> +</div> + +<h3 id="Throttling_a_requestAnimationFrame_animation">Throttling a requestAnimationFrame() animation</h3> + +<p>One limitation of <code>requestAnimationFrame()</code> is that you can't choose your frame rate. This isn't a problem most of the time, as generally you want your animation to run as smoothly as possible, but what about when you want to create an old school, 8-bit-style animation?</p> + +<p>This was a problem for example in the Monkey Island-inspired walking animation from our <a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Drawing_graphics">Drawing Graphics</a> article:</p> + +<p>{{EmbedGHLiveSample("learning-area/javascript/apis/drawing-graphics/loops_animation/7_canvas_walking_animation.html", '100%', 260)}}</p> + +<p>In this example we have to animate both the position of the character on the screen, and the sprite being shown. There are only 6 frames in the sprite's animation; if we showed a different sprite frame for every frame displayed on the screen by <code>requestAnimationFrame()</code>, Guybrush would move his limbs too fast and the animation would look ridiculous. We therefore throttled the rate at which the sprite cycles its frames using the following code:</p> + +<pre class="brush: js">if (posX % 13 === 0) { + if (sprite === 5) { + sprite = 0; + } else { + sprite++; + } +}</pre> + +<p>So we are only cycling a sprite once every 13 animation frames. OK, so it's actually about every 6.5 frames, as we update <code>posX</code> (character's position on the screen) by two each frame:</p> + +<pre class="brush: js">if(posX > width/2) { + newStartPos = -((width/2) + 102); + posX = Math.ceil(newStartPos / 13) * 13; + console.log(posX); +} else { + posX += 2; +}</pre> + +<p>This is the code that works out how to update the position in each animation frame.</p> + +<p>The method you use to throttle your animation will depend on your particular code. For example, in our spinner example we could make it appear to move slower by only increasing our <code>rotateCount</code> by one on each frame instead of two.</p> + +<h2 id="Active_learning_a_reaction_game">Active learning: a reaction game</h2> + +<p>For our final section of this article, we'll create a 2-player reaction game. Here we have two players, one of whom controls the game using the <kbd>A</kbd> key, and the other with the <kbd>L</kbd> key.</p> + +<p>When the <em>Start</em> button is pressed, a spinner like the one we saw earlier is displayed for a random amount of time between 5 and 10 seconds. After that time, a message will appear saying "PLAYERS GO!!" — once this happens, the first player to press their control button will win the game.</p> + +<p>{{EmbedGHLiveSample("learning-area/javascript/asynchronous/loops-and-intervals/reaction-game.html", '100%', 500)}}</p> + +<p>Let's work through this.</p> + +<ol> + <li> + <p>First of all, download the <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/loops-and-intervals/reaction-game-starter.html">starter file for the app</a> — this contains the finished HTML structure and CSS styling, giving us a game board that shows the two players' information (as seen above), but with the spinner and results paragraph displayed on top of one another. We just have to write the JavaScript code.</p> + </li> + <li> + <p>Inside the empty {{htmlelement("script")}} element on your page, start by adding the following lines of code that define some constants and variables we'll need in the rest of the code:</p> + + <pre class="brush: js">const spinner = document.querySelector('.spinner p'); +const spinnerContainer = document.querySelector('.spinner'); +let rotateCount = 0; +let startTime = null; +let rAF; +const btn = document.querySelector('button'); +const result = document.querySelector('.result');</pre> + + <p>In order, these are:</p> + + <ol> + <li>A reference to our spinner, so we can animate it.</li> + <li>A reference to the {{htmlelement("div")}} element that contains the spinner, used for showing and hiding it.</li> + <li>A rotate count — how much we want to show the spinner rotated on each frame of the animation.</li> + <li>A null start time — will be populated with a start time when the spinner starts spinning.</li> + <li>An uninitialized variable to later store the {{domxref("Window.requestAnimationFrame", "requestAnimationFrame()")}} call that animates the spinner.</li> + <li>A reference to the Start button.</li> + <li>A reference to the results paragraph.</li> + </ol> + </li> + <li> + <p>Next, below the previous lines of code, add the following function. This simply takes two numerical inputs and returns a random number between the two. We'll need this to generate a random timeout interval later on.</p> + + <pre class="brush: js">function random(min,max) { + var num = Math.floor(Math.random()*(max-min)) + min; + return num; +}</pre> + </li> + <li> + <p>Next add in the <code>draw()</code> function, which animates the spinner. This is very similar to the version seen in the simple spinner example we looked at earlier:</p> + + <pre class="brush: js">function draw(timestamp) { + if(!startTime) { + startTime = timestamp; + } + + rotateCount = (timestamp - startTime) / 3; + + if(rotateCount > 359) { + rotateCount %= 360; + } + + spinner.style.transform = 'rotate(' + rotateCount + 'deg)'; + rAF = requestAnimationFrame(draw); +}</pre> + </li> + <li> + <p>Now it is time to set up the initial state of the app when the page first loads. Add the following two lines, which simply hide the results paragraph and spinner container using <code>display: none;</code>.</p> + + <pre class="brush: js">result.style.display = 'none'; +spinnerContainer.style.display = 'none';</pre> + </li> + <li> + <p>We'll also define a <code>reset()</code> function, which sets the app back to the original state required to start the game again after it has been played. Add the following at the bottom of your code:</p> + + <pre class="brush: js">function reset() { + btn.style.display = 'block'; + result.textContent = ''; + result.style.display = 'none'; +}</pre> + </li> + <li> + <p>OK, enough preparation. Let's make the game playable! Add the following block to your code. The <code>start()</code> function calls <code>draw()</code> to start the spinner spinning and display it in the UI, hides the <em>Start</em> button so we can't mess up the game by starting it multiple times concurrently, and runs a <code>setTimeout()</code> call that runs a <code>setEndgame()</code> function after a random interval between 5 and 10 seconds has passed. We also add an event listener to our button to run the <code>start()</code> function when it is clicked.</p> + + <pre class="brush: js">btn.addEventListener('click', start); + +function start() { + draw(); + spinnerContainer.style.display = 'block'; + btn.style.display = 'none'; + setTimeout(setEndgame, random(5000,10000)); +}</pre> + + <div class="blockIndicator note"> + <p><strong>Note</strong>: You'll see that in this example we are calling <code>setTimeout()</code> without storing the return value (so not <code>let myTimeout = setTimeout(functionName, interval)</code>). This works and is fine, as long as you don't need to clear your interval/timeout at any point. If you do, you'll need to save the returned identifier.</p> + </div> + + <p>The net result of the previous code is that when the <em>Start</em> button is pressed, the spinner is shown and the players are made to wait a random amount of time before they are then asked to press their button. This last part is handled by the <code>setEndgame()</code> function, which we should define next.</p> + </li> + <li> + <p>So add the following function to your code next:</p> + + <pre class="brush: js">function setEndgame() { + cancelAnimationFrame(rAF); + spinnerContainer.style.display = 'none'; + result.style.display = 'block'; + result.textContent = 'PLAYERS GO!!'; + + document.addEventListener('keydown', keyHandler); + + function keyHandler(e) { + console.log(e.key); + if(e.key === 'a') { + result.textContent = 'Player 1 won!!'; + } else if(e.key === 'l') { + result.textContent = 'Player 2 won!!'; + } + + document.removeEventListener('keydown', keyHandler); + setTimeout(reset, 5000); + }; +}</pre> + + <p>Stepping through this:</p> + + <ol> + <li>First we cancel the spinner animation with {{domxref("window.cancelAnimationFrame", "cancelAnimationFrame()")}} (it is always good to clean up unneeded processes), and hide the spinner container.</li> + <li>Next we display the results paragraph and set its text content to "PLAYERS GO!!" to signal to the players that they can now press their button to win.</li> + <li>We then attach a <code><a href="/en-US/docs/Web/API/Document/keydown_event">keydown</a></code> event listener to our document — when any button is pressed down, the <code>keyHandler()</code> function is run.</li> + <li>Inside <code>keyHandler()</code>, we include the event object as a parameter (represented by <code>e</code>) — its {{domxref("KeyboardEvent.key", "key")}} property contains the key that was just pressed, and we can use this to respond to specific key presses with specific actions.</li> + <li>We first log <code>e.key</code> to the console, which is a useful way of finding out the <code>key</code> value of different keys you are pressing.</li> + <li>When <code>e.key</code> is "a", we display a message to say that Player 1 won, and when <code>e.key</code> is "l", we display a message to say Player 2 won. Note that this will only work with lowercase a and l — if an uppercase A or L is submitted (the key plus <kbd>Shift</kbd>), it is counted as a different key.</li> + <li>Regardless of which one of the player control keys was pressed, we remove the <code>keydown</code> event listener using {{domxref("EventTarget.removeEventListener", "removeEventListener()")}} so that once the winning press has happened, no more keyboard input is possible to mess up the final game result. We also use <code>setTimeout()</code> to call <code>reset()</code> after 5 seconds — as we explained earlier, this function resets the game back to its original state so that a new game can be started.</li> + </ol> + </li> +</ol> + +<p>That's it, you're all done.</p> + +<div class="blockIndicator note"> +<p><strong>Note</strong>: If you get stuck, check out <a href="https://mdn.github.io/learning-area/javascript/asynchronous/loops-and-intervals/reaction-game.html">our version of the reaction game</a> (see the <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/loops-and-intervals/reaction-game.html">source code</a> also).</p> +</div> + +<h2 id="Conclusion">Conclusion</h2> + +<p>So that's it — all the essentials of async loops and intervals covered in one article. You'll find these methods useful in a lot of situations, but take care not to overuse them — since these still run on the main thread, heavy and intensive callbacks (especially those that manipulate the DOM) can really slow down a page if you're not careful.</p> + +<p>{{PreviousMenuNext("Learn/JavaScript/Asynchronous/Introducing", "Learn/JavaScript/Asynchronous/Promises", "Learn/JavaScript/Asynchronous")}}</p> + +<h2 id="In_this_module">In this module</h2> + +<ul> + <li><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Concepts">General asynchronous programming concepts</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Introducing">Introducing asynchronous JavaScript</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Timeouts_and_intervals">Cooperative asynchronous JavaScript: Timeouts and intervals</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Promises">Graceful asynchronous programming with Promises</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Async_await">Making asynchronous programming easier with async and await</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Choosing_the_right_approach">Choosing the right approach</a></li> +</ul> diff --git a/files/ko/learn/javascript/building_blocks/build_your_own_function/index.html b/files/ko/learn/javascript/building_blocks/build_your_own_function/index.html new file mode 100644 index 0000000000..e700eb083d --- /dev/null +++ b/files/ko/learn/javascript/building_blocks/build_your_own_function/index.html @@ -0,0 +1,251 @@ +--- +title: Build your own function +slug: Learn/JavaScript/Building_blocks/Build_your_own_function +translation_of: Learn/JavaScript/Building_blocks/Build_your_own_function +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/JavaScript/Building_blocks/Functions","Learn/JavaScript/Building_blocks/Return_values", "Learn/JavaScript/Building_blocks")}}</div> + +<p class="summary">이번 장에선 앞의 글에서 배운 function이론을 사용하여 사용자 정의 함수를 만들어 봅니다. 사용자 정의 함수 연습과 더불어, 함수를 다루는 몇 가지 유용한 사항들도 설명을 하겠습니다. </p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">알아야 할 것:</th> + <td>기본적인 컴퓨터 사용 능력, HTML과 CSS에 대한 기본적인 이해, 자바스크립트 첫걸음, 함수 - 재사용 가능한 블록 코드</td> + </tr> + <tr> + <th scope="row">목표:</th> + <td>사용자 정의 함수를 만드는 방법에 대한 몇가지 예제 제공, 그와 관련된 여러가지 유용한 세부 사항 설명. </td> + </tr> + </tbody> +</table> + +<h2 id="Active_learning_Lets_build_a_function">Active learning: Let's build a function</h2> + +<p>여기서 만들 사용자 정의 함수는 <code>displayMessage()</code>라고 명명하겠습니다. 이 함수는 내장함수 <a href="/en-US/docs/Web/API/Window/alert">alert()</a> 을 사용하여 메시지를 표시하는 대신 다른 방법으로 페이지에 메시지 박스를 만듭니다. 이전에도 봐온 기능이지만 다시한번 연습해보자는 의미로 브라우저의 JavaScript 콘솔에 아래처럼 입력하세요 :</p> + +<pre class="brush: js notranslate">alert('This is a message');</pre> + +<p><code>alert</code> 함수는 하나의 인수만 사용합니다. — 전달받는 인수는 브라우저의 alert박스에 표시됩니다. 인수를 다른 문자로 교체하여 시험해보세요.</p> + +<p><code>alert</code> 함수는 제한적 입니다. : 원하는 메시지를 출력할 순 있지만 글자 색, 아이콘 등 다른 요소는 첨부할 수 없습니다. 아래서 다른 방법을 사용하여 재미있는 무언가를 만드는 방법을 소개하겠습니다.</p> + +<div class="note"> +<p><strong>Note</strong>: 이 예제는 모든 모던 브라우저에서 잘 작동합니다. 하지만 조금 오래된 브라우저는 스타일이 이상하게 적용될 수 있습니다. 이번 예제를 원활하게 즐기려면 Firefox, Opera, Chrome 브라우저를 사용해주세요</p> +</div> + +<h2 id="The_basic_function">The basic function</h2> + +<p>본격적으로 시작하기 앞서, 기본적인 함수를 만들어봅시다..</p> + +<div class="note"> +<p><strong>Note</strong>: 함수 명명규칙은 <a href="/en-US/Learn/JavaScript/First_steps/Variables#An_aside_on_variable_naming_rules">변수 명명규칙</a>과 동일하게 사용하는것이 좋습니다. 명명규칙이 동일해서 헷갈리지 않습니다. — 함수는 이름 뒤에 ()괄호가 함께 쓰이지만 변수는 그렇지 않습니다.</p> +</div> + +<ol> + <li><a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/functions/function-start.html">function-start.html</a> 파일을 연습하고있는 컴퓨터에 복사하여 저장합니다. HTML 구조는 매우 간단합니다. — body 태그에는 한 개의 버튼이 있습니다. 그리고 style 태그에 메시지 박스를 위한 CSS 블럭이 있습니다. 그리고 비어있는 {{htmlelement("script")}} 엘리먼트에 연습할 자바스크립트 코드를 앞으로 쓰겠씁니다..</li> + <li>다음으로 아래의 코드를 <code><script></code> 엘리먼트에 써봅시다. : + <pre class="brush: js notranslate">function displayMessage() { + +}</pre> + <code>function</code>이라는 키워드로 블럭 작성을 시작했습니다. 이 의미는 방금 우리가 함수를 정의했다는 뜻 입니다. 그리고 뒤에는 만들고자 하는 이름을 정의했고, 괄호에 이어 중괄호를 넣었습니다. 함수에 전달하고자 하는 인수는 괄호()안에 작성합니다. 그리고 우리가 만들고자 하는 로직은 중괄호 안에 작성합니다..</li> + <li>마지막으로 아래의 코드를 중괄호 안에 작성합니다.: + <pre class="brush: js notranslate">const html = document.querySelector('html'); + +const panel = document.createElement('div'); +panel.setAttribute('class', 'msgBox'); +html.appendChild(panel); + +const msg = document.createElement('p'); +msg.textContent = 'This is a message box'; +panel.appendChild(msg); + +const closeBtn = document.createElement('button'); +closeBtn.textContent = 'x'; +panel.appendChild(closeBtn); + +closeBtn.onclick = function() { + panel.parentNode.removeChild(panel); +}</pre> + </li> +</ol> + +<p>코드가 꽤 긴 편이니 조금씩 설명을 이어가겠습니다..</p> + +<p>첫 번째 줄에서 {{domxref("document.querySelector()")}} 라는 DOM API를 사용했습니다. 이 API는 {{htmlelement("html")}} 엘리먼트를 선택하여 <code>html</code>이라는 변수에 저장합니다. 따라서 아래와 같은 작업을 수행할 수 있습니다. :</p> + +<pre class="brush: js notranslate">const html = document.querySelector('html');</pre> + +<p>다음 줄에선 마찬가지로 DOM API인 {{domxref("document.createElement()")}} 을 사용하여 {{htmlelement("div")}} 엘리먼트를 생성한 후 <code>panel</code>변수에 저장합니다. 이 엘리먼트는 메시지 상자 바깥쪽 컨테이너가 될 것 입니다.</p> + +<p>그리고 또 다른 DOM API인 {{domxref("Element.setAttribute()")}} 을 사용하여 <code>class</code> 속성을 만들고 그 이름을 <code>msgBox</code>로 지정했습니다. 이 작업으로 스타일을 좀 더 쉽게 적용할 수 있습니다. — HTML 파일의 CSS 블럭을 살펴보면 <code>.msgBox</code> 클래스 셀렉터를 사용하여 메시지 박스와 그 내용을 스타일링할 수 있음을 알 수 있습니다.</p> + +<p>마지막으로, {{domxref("Node.appendChild()")}} DOM 함수를 사용하여 <code>html</code> 변수 안의 엘리먼트에 <font face="consolas, Liberation Mono, courier, monospace"><span style="background-color: rgba(220, 220, 220, 0.5);">panel</span></font> 변수에 저장된 <code><div></code>엘리먼트를 자식 엘리먼트로 삽입했습니다. 변수 선언만으로는 페이지에 표시할 수 없습니다. 반드시 아래처럼 작성하여 엘리먼트가 어디에 표시되는지 명시할 필요가 있습니다. </p> + +<pre class="brush: js notranslate">const panel = document.createElement('div'); +panel.setAttribute('class', 'msgBox'); +html.appendChild(panel);</pre> + +<p>다음 두 섹션은 위에서 봤던것과 동일한 <code>createElement()</code> 그리고 <code>appendChild()</code> 함수를 사용합니다. — {{htmlelement("p")}} 그리고 {{htmlelement("button")}} — 만들어 <font face="consolas, Liberation Mono, courier, monospace"><span style="background-color: rgba(220, 220, 220, 0.5);">panel</span></font>의 <code><div></code>태그의 자식 엘리먼트로 넣습니다. 우리는 {{domxref("Node.textContent")}} 속성을 사용하여 버튼에 x 라는 글자를 새겨넣습니다. 이 버튼은 사용자가 메시지 박스를 닫기를 원할 때 클릭/활성화 해야 하는 버튼입니다..</p> + +<pre class="brush: js notranslate">const msg = document.createElement('p'); +msg.textContent = 'This is a message box'; +panel.appendChild(msg); + +const closeBtn = document.createElement('button'); +closeBtn.textContent = 'x'; +panel.appendChild(closeBtn);</pre> + +<p>마지막으로 {{domxref("GlobalEventHandlers.onclick")}} 이벤트 핸들러를 사용하여 사용자가 x버튼을 클릭하면 메시지상자를 닫을 수 있게 만듭니다. </p> + +<p>간단히 말하면 <code>onclick</code> 핸들러는 버튼 (또는 실제 페이지의 다른 엘리먼트) 에서 사용할 수 있으며 버튼이 클릭됐을때 실행될 코드를 작성할 수 있습니다. 더 자세한 기능은 <a href="/en-US/docs/Learn/JavaScript/Building_blocks/Events">events article</a>을 참조하세요. 이제 <code>onclick</code> 핸들러를 익명 함수와 동일하게 만들고, 그 안에 버튼이 클릭됐을 때 실행될 코드를 작성합니다. 함수 안쪽에서 {{domxref("Node.removeChild()")}} DOM API 함수를 사용하여 HTML 엘리먼트를 삭제하도록 명령합니다. — 이 경우 <code>panel</code> 변수의 <code><div></code>입니다.</p> + +<pre class="brush: js notranslate">closeBtn.onclick = function() { + panel.parentNode.removeChild(panel); +}</pre> + +<p>기본적으로 전체 코드 블럭은 아래처럼 보이는 HTML 블록을 생성하고 페이지에 나타내줍니다. :</p> + +<pre class="brush: html notranslate"><div class="msgBox"> + <p>This is a message box</p> + <button>x</button> +</div></pre> + +<p>많은 코드를 살펴봤습니다. — 예제에 포함된 CSS코드를 포함한 모든 코드를 지금 당장 이해할 필요는 없습니다. 이 예제에서 중점적으로 다루고자 하는 부분은 함수의 구조와 사용 방법 이었습니다. CSS 코드는 학습자의 흥미를 유도하기 위해 재미있는 것을 보여주고자 만들었습니다.</p> + +<h2 id="Calling_the_function">Calling the function</h2> + +<p>You've now got your function definition written into your <code><script></code> element just fine, but it will do nothing as it stands.</p> + +<ol> + <li>Try including the following line below your function to call it: + <pre class="brush: js notranslate">displayMessage();</pre> + This line invokes the function, making it run immediately. When you save your code and reload it in the browser, you'll see the little message box appear immediately, only once. We are only calling it once, after all.</li> + <li> + <p>Now open your browser developer tools on the example page, go to the JavaScript console and type the line again there, you'll see it appear again! So this is fun — we now have a reusable function that we can call any time we like.</p> + + <p>But we probably want it to appear in response to user and system actions. In a real application, such a message box would probably be called in response to new data being available, or an error having occurred, or the user trying to delete their profile ("are you sure about this?"), or the user adding a new contact and the operation completing successfully, etc.</p> + + <p>In this demo, we'll get the message box to appear when the user clicks the button.</p> + </li> + <li>Delete the previous line you added.</li> + <li>Next, we'll select the button and store a reference to it in a constant. Add the following line to your code, above the function definition: + <pre class="brush: js notranslate">const btn = document.querySelector('button');</pre> + </li> + <li>Finally, add the following line below the previous one: + <pre class="brush: js notranslate">btn.onclick = displayMessage;</pre> + In a similar way to our <code>closeBtn.onclick...</code> line inside the function, here we are calling some code in response to a button being clicked. But in this case, instead of calling an anonymous function containing some code, we are calling our function name directly.</li> + <li>Try saving and refreshing the page — now you should see the message box appear when you click the button.</li> +</ol> + +<p>You might be wondering why we haven't included the parentheses after the function name. This is because we don't want to call the function immediately — only after the button has been clicked. If you try changing the line to</p> + +<pre class="brush: js notranslate">btn.onclick = displayMessage();</pre> + +<p>and saving and reloading, you'll see that the message box appears without the button being clicked! The parentheses in this context are sometimes called the "function invocation operator". You only use them when you want to run the function immediately in the current scope. In the same respect, the code inside the anonymous function is not run immediately, as it is inside the function scope.</p> + +<p>If you tried the last experiment, make sure to undo the last change before carrying on.</p> + +<h2 id="Improving_the_function_with_parameters">Improving the function with parameters</h2> + +<p>As it stands, the function is still not very useful — we don't want to just show the same default message every time. Let's improve our function by adding some parameters, allowing us to call it with some different options.</p> + +<ol> + <li>First of all, update the first line of the function: + <pre class="brush: js notranslate">function displayMessage() {</pre> + + <div>to this:</div> + + <pre class="brush: js notranslate">function displayMessage(msgText, msgType) {</pre> + Now when we call the function, we can provide two variable values inside the parentheses to specify the message to display in the message box, and the type of message it is.</li> + <li>To make use of the first parameter, update the following line inside your function: + <pre class="brush: js notranslate">msg.textContent = 'This is a message box';</pre> + + <div>to</div> + + <pre class="brush: js notranslate">msg.textContent = msgText;</pre> + </li> + <li>Last but not least, you now need to update your function call to include some updated message text. Change the following line: + <pre class="brush: js notranslate">btn.onclick = displayMessage;</pre> + + <div>to this block:</div> + + <pre class="brush: js notranslate">btn.onclick = function() { + displayMessage('Woo, this is a different message!'); +};</pre> + If we want to specify parameters inside parentheses for the function we are calling, then we can't call it directly — we need to put it inside an anonymous function so that it isn't in the immediate scope and therefore isn't called immediately. Now it will not be called until the button is clicked.</li> + <li>Reload and try the code again and you'll see that it still works just fine, except that now you can also vary the message inside the parameter to get different messages displayed in the box!</li> +</ol> + +<h3 id="A_more_complex_parameter">A more complex parameter</h3> + +<p>On to the next parameter. This one is going to involve slightly more work — we are going to set it so that depending on what the <code>msgType</code> parameter is set to, the function will display a different icon and a different background color.</p> + +<ol> + <li>First of all, download the icons needed for this exercise (<a href="https://raw.githubusercontent.com/mdn/learning-area/master/javascript/building-blocks/functions/icons/warning.png">warning</a> and <a href="https://raw.githubusercontent.com/mdn/learning-area/master/javascript/building-blocks/functions/icons/chat.png">chat</a>) from GitHub. Save them in a new folder called <code>icons</code> in the same location as your HTML file. + + <div class="note"><strong>Note</strong>: The warning and chat icons were originally found on <a href="https://www.iconfinder.com/">iconfinder.com</a>, and designed by <a href="https://www.iconfinder.com/nazarr">Nazarrudin Ansyari</a> — Thanks! (The actual icon pages were since moved or removed.)</div> + </li> + <li>Next, find the CSS inside your HTML file. We'll make a few changes to make way for the icons. First, update the <code>.msgBox</code> width from: + <pre class="brush: css notranslate">width: 200px;</pre> + + <div>to</div> + + <pre class="brush: css notranslate">width: 242px;</pre> + </li> + <li>Next, add the following lines inside the <code>.msgBox p { ... }</code> rule: + <pre class="brush: css notranslate">padding-left: 82px; +background-position: 25px center; +background-repeat: no-repeat;</pre> + </li> + <li>Now we need to add code to our <code>displayMessage()</code> function to handle displaying the icons. Add the following block just above the closing curly brace (<code>}</code>) of your function: + <pre class="brush: js notranslate">if (msgType === 'warning') { + msg.style.backgroundImage = 'url(icons/warning.png)'; + panel.style.backgroundColor = 'red'; +} else if (msgType === 'chat') { + msg.style.backgroundImage = 'url(icons/chat.png)'; + panel.style.backgroundColor = 'aqua'; +} else { + msg.style.paddingLeft = '20px'; +}</pre> + Here, if the <code>msgType</code> parameter is set as <code>'warning'</code>, the warning icon is displayed and the panel's background color is set to red. If it is set to <code>'chat'</code>, the chat icon is displayed and the panel's background color is set to aqua blue. If the <code>msgType</code> parameter is not set at all (or to something different), then the <code>else { ... }</code> part of the code comes into play, and the paragraph is simply given default padding and no icon, with no background panel color set either. This provides a default state if no <code>msgType</code> parameter is provided, meaning that it is an optional parameter!</li> + <li>Let's test out our updated function, try updating the <code>displayMessage()</code> call from this: + <pre class="brush: js notranslate">displayMessage('Woo, this is a different message!');</pre> + + <div>to one of these:</div> + + <pre class="brush: js notranslate">displayMessage('Your inbox is almost full — delete some mails', 'warning'); +displayMessage('Brian: Hi there, how are you today?','chat');</pre> + You can see how useful our (now not so) little function is becoming.</li> +</ol> + +<div class="note"> +<p><strong>Note</strong>: If you have trouble getting the example to work, feel free to check your code against the <a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/functions/function-stage-4.html">finished version on GitHub</a> (<a href="http://mdn.github.io/learning-area/javascript/building-blocks/functions/function-stage-4.html">see it running live</a> also), or ask us for help.</p> +</div> + +<h2 id="Test_your_skills!">Test your skills!</h2> + +<p>You've reached the end of this article, but can you remember the most important information? You can find some further tests to verify that you've retained this information before you move on — see <a href="/en-US/docs/Learn/JavaScript/Building_blocks/Test_your_skills:_Functions">Test your skills: Functions</a>. These tests require skills that are covered in the next article, so you might want to read those first before trying it.</p> + +<h2 id="Conclusion">Conclusion</h2> + +<p>Congratulations on reaching the end! This article took you through the entire process of building up a practical custom function, which with a bit more work could be transplanted into a real project. In the next article we'll wrap up functions by explaining another essential related concept — return values.</p> + +<ul> +</ul> + +<p>{{PreviousMenuNext("Learn/JavaScript/Building_blocks/Functions","Learn/JavaScript/Building_blocks/Return_values", "Learn/JavaScript/Building_blocks")}}</p> + +<h2 id="In_this_module">In this module</h2> + +<ul> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/conditionals">Making decisions in your code — conditionals</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Looping_code">Looping code</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Functions">Functions — reusable blocks of code</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Build_your_own_function">Build your own function</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Return_values">Function return values</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Events">Introduction to events</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Image_gallery">Image gallery</a></li> +</ul> diff --git a/files/ko/learn/javascript/building_blocks/functions/index.html b/files/ko/learn/javascript/building_blocks/functions/index.html new file mode 100644 index 0000000000..4cc3420afe --- /dev/null +++ b/files/ko/learn/javascript/building_blocks/functions/index.html @@ -0,0 +1,394 @@ +--- +title: 함수 — 재사용 가능한 코드 블록 +slug: Learn/JavaScript/Building_blocks/Functions +translation_of: Learn/JavaScript/Building_blocks/Functions +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/JavaScript/Building_blocks/Looping_code","Learn/JavaScript/Building_blocks/Build_your_own_function", "Learn/JavaScript/Building_blocks")}}</div> + +<p class="summary">코딩에 있어서 또 하나의 중요한 개념은 바로 '함수'입니다. 함수란, 한 가지의 일을 수행하는 코드가 블럭으로 묶여있는 것을 말하며, 간단한 명령만으로 동일한 코드를 필요한 곳마다 반복해서 사용하지 않을 수 있게 만들어 줍니다. 이번 장에서는 함수에 대한 기본 문법과 파라미터(parameter) 및 범위(scope), 그리고 호출 방법에 대해 설명합니다.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">필요 사항:</th> + <td>기본적인 컴퓨터 활용 능력, HTML과 CSS의 기본적인 이해, <a href="/en-US/docs/Learn/JavaScript/First_steps">자바스크립트 첫 단계</a>.</td> + </tr> + <tr> + <th scope="row">목표:</th> + <td>JavaScript 함수의 기본 개념을 이해합니다.</td> + </tr> + </tbody> +</table> + +<h2 id="함수는_어디에서_찾을_수_있나요">함수는 어디에서 찾을 수 있나요?</h2> + +<p>자바스크립트 어디서든 함수를 찾을 수 있습니다. 사실, 우리는 지금까지 수업에서 함수를 계속 사용해왔습니다; 함수에 대해서 그렇게 말해오지 않았을 뿐이죠. 그러나 이제 함수에 대해서 분명하게 말하고, 실제로 문법을 탐험할 때가 되었습니다. </p> + +<p> <a href="/ko/docs/Learn/JavaScript/Building_blocks/Looping_code#%EB%A3%A8%ED%94%84%EC%9D%98_%ED%91%9C%EC%A4%80">for loop</a>, <a href="/ko/docs/Learn/JavaScript/Building_blocks/Looping_code#while_%EA%B7%B8%EB%A6%AC%EA%B3%A0_do_..._while">while 과 do...while loop</a>, 또는 <a href="/ko/docs/Learn/JavaScript/Building_blocks/%EC%A1%B0%EA%B1%B4%EB%AC%B8#if_..._else_%EB%AC%B8">if...else문</a>과 같은 일반적인 내장 언어 구조를 사용하지 <strong>않고</strong> — <code>()</code> —같은 괄호 쌍을 사용했다면 당신은 함수를 사용하고 있던 겁니다</p> + +<h2 id="브라우저_내장_함수">브라우저 내장 함수</h2> + +<p>우리는 이 코스에서 많은 브라우저 빌트인 함수를 사용해왔습니다.<br> + 예를 들어, 우리가 매번 텍스트 string을 조작할 때마다:</p> + +<pre class="brush: js notranslate">var myText = 'I am a string'; +var newString = myText.replace('string', 'sausage'); +console.log(newString); +// the replace() string function takes a string, +// replaces one substring with another, and returns +// a new string with the replacement made</pre> + +<p>또는 우리가 배열을 조작할 때마다:</p> + +<pre class="brush: js notranslate">var myArray = ['I', 'love', 'chocolate', 'frogs']; +var madeAString = myArray.join(' '); +console.log(madeAString); +// the join() function takes an array, joins +// all the array items together into a single +// string, and returns this new string</pre> + +<p>또는 우리가 무작위의 숫자를 생성할 때마다:</p> + +<pre class="brush: js notranslate">var myNumber = Math.random(); +// the random() function generates a random +// number between 0 and 1, and returns that +// number</pre> + +<p>...우리는 함수를 사용하고 있었어요!</p> + +<div class="note"> +<p><strong>Note</strong>: Feel free to enter these lines into your browser's JavaScript console to re-familiarize yourself with their functionality, if needed.</p> +</div> + +<p>JavaScript 언어는 당신 스스로 코드 전체를 적을 필요 없이, 유용한 것들을 할 수 있게 해주는 많은 내장 함수를 가지고 있습니다. 사실, 브라우저 내장 함수를 <strong>호출</strong>("함수를 실행하다"는 말을 멋있게 "호출하다"라고 하기도 합니다)할 때 호출하는 일부 코드는 JavaScript로 작성할 수 없었습니다 — 이러한 함수 중 상당수는 백그라운드 브라우저 코드의 일부를 호출하고 있으며, 이는 JavaScript와 같은 웹 언어가 아니라 C++와 같은 저수준 시스템 언어로 작성됩니다.</p> + +<p>명심하세요. 몇몇 브라우저 내장함수는 JavaScript core가 아닌 브라우저 API의 일부입니다. 브라우저 API는 기본 언어에서 더 많은 기능을 쓸 수 있게 만들어 졌습니다. (<a href="/ko/docs/Learn/JavaScript/First_steps/What_is_JavaScript#%EA%B7%B8%EB%9E%98%EC%84%9C_%EC%A7%84%EC%A7%9C_%EC%96%B4%EB%96%A4_%EC%9D%BC%EC%9D%84_%ED%95%A0_%EC%88%98_%EC%9E%88%EB%82%98%EC%9A%94">앞선 코스</a>에서 더 자세한 설명을 볼 수 있습니다). 브라우저 API를 다루는 법은 나중에 더 살펴보도록 하겠습니다.</p> + +<h2 id="함수_대_메소드">함수 대 메소드</h2> + +<p>우리가 다음으로 넘어가기 전에, 확실하게 짚고 가야할 게 있습니다. — 기술적으로, Built-in browser functions은 functions이 아닙니다. 그들은 <strong>methods</strong>죠. 이 문장이 약간 이상하고 혼란스럽게 들릴 수 있겠지만, 걱정마세요. — function과 method 이 두 단어는 광범위하게 교체가능하답니다. 최소한 그들의 용도적 측면과 지금 당신의 배움 단계에서는요.<br> + <br> + 구별되는 점은 methods는 objects안에 정의된 functions이라는 겁니다. Built-in browser functions(methods)와 변수(<strong>properties</strong>라 불리는 것들)는 코드를 더욱 효율적이고 다루기 쉽게하기 위해 구조화된 objects안에 저장되어 있습니다.</p> + +<p>당신은 아직 구조화된 JavaScript objects의 내부 동작에 대해서까지는 배우지 않아도 괜찮습니다. — 당신은 우리가 가르쳐 줄 objects의 내부 동작에 관한 모든 것인 모듈과, 어떻게 당신만의 모듈을 창조할 수 있는지에 대해 기다릴 수 있습니다. 현재로서는, 우리는 단지 어떤 혼동도 가능한 method 대 function(당신이 웹에서 이용가능한 관련 자원들을 볼때, 두 가지 용어를 만날 가능 성이 충분히 있는)에 대해 정리하고 싶을 뿐입니다. </p> + +<h2 id="사용자_정의_함수">사용자 정의 함수</h2> + +<p>또한 지금까지 많은 <strong>사용자 정의 함수</strong>(브라우저가 아닌 코드에 정의된 함수)를 봤습니다. 바로 뒤에 괄호가 있는 사용자가 정의한 이름을 볼 때마다, 바로 사용자 정의 함수를 사용하고 있었던 겁니다. <a href="/en-US/docs/Learn/JavaScript/Building_blocks/Looping_code">loops article</a>의 <a href="http://mdn.github.io/learning-area/javascript/building-blocks/loops/random-canvas-circles.html">random-canvas-circles.html</a> 예제(전체 <a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/loops/random-canvas-circles.html">소스 코드</a> 참조)에는 다음과 같은 <code>draw()</code> 사용자 정의 함수가 포함되어 있습니다:</p> + +<pre class="brush: js notranslate">function draw() { + ctx.clearRect(0,0,WIDTH,HEIGHT); + for (var i = 0; i < 100; i++) { + ctx.beginPath(); + ctx.fillStyle = 'rgba(255,0,0,0.5)'; + ctx.arc(random(WIDTH), random(HEIGHT), random(50), 0, 2 * Math.PI); + ctx.fill(); + } +}</pre> + +<p>이 함수는 {{htmlelement("canvas")}} 요소 안에 100개의 임의의 원을 그립니다. 원할 때마다 아래 코드로 함수를 호출할 수 있습니다:</p> + +<pre class="brush: js notranslate">draw();</pre> + +<p>모든 코드를 또 작성하지 않고 말이죠. 그리고 함수는 당신이 원하는 코드를 포함할 수 있습니다. 심지어 함수 내의 다른 함수를 불러올 수도 있구요. 위의 예시는 아래와 같이 정의된 코드를 <code>random()</code> 을 통해 세번이나 호출하고 있죠.</p> + +<pre class="brush: js notranslate">function random(number) { + return Math.floor(Math.random()*number); +}</pre> + +<p><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/random">Math.random()</a> 라는 내장함수는 오직 0과 1사이의 소수를 생성해내기 때문에 우리는 위의 함수가 필요했습니다. 우리는 0과 특정 수 사이의 무작위한 정수를 원했거든요.</p> + +<h2 id="함수_호출">함수 호출</h2> + +<p>지금까지 꽤 잘 따라온 거 같은데 혹시 모르니깐 말해 주자면... 정의된 함수를 작동시키기 위해선 함수를 '호출' 해야 돼요. 함수 호출은 함수의 이름을 괄호와 함께 코드 내에 적어 주면 됩니다.</p> + +<pre class="brush: js notranslate">function myFunction() { + alert('hello'); +} + +myFunction() +// calls the function once</pre> + +<h2 id="익명_함수">익명 함수</h2> + +<p>당신은 조금 다른 방식으로 정의되거나 호출되는 함수를 본 적 있을 거예요. 이제까지 우리는 이런 식으로 함수를 생성했죠: </p> + +<pre class="brush: js notranslate">function myFunction() { + alert('hello'); +}</pre> + +<p>하지만 이름 없는 함수 또한 만들 수 있답니다.</p> + +<pre class="brush: js notranslate">function() { + alert('hello'); +}</pre> + +<p>이건 <strong>익명 함수</strong>라고 불려요. 이름이 없다는 뜻이죠! 익명함수는 스스로 뭘 어쩌지 못 해요. 익명함수는 주로 이벤트 핸들러와 사용됩니다. 아래의 예시는 함수 내의 코드가 버튼을 클릭함에 따라 작동한다는 걸 보여주죠. </p> + +<pre class="brush: js notranslate">var myButton = document.querySelector('button'); + +myButton.onclick = function() { + alert('hello'); +}</pre> + +<p>위의 예시는 페이지 상의 클릭을 위해 {{htmlelement("button")}} 요소를 필요로 합니다. 당신은 코스를 거치며 이런 구조의 코드를 꽤 봐왔을 거예요. 다음 예시에서 더 많은 걸 배워 보자구요.</p> + +<p>당신은 변수 속에 익명함수를 넣을 수 있어요. 예시입니다.</p> + +<pre class="brush: js notranslate">var myGreeting = function() { + alert('hello'); +}</pre> + +<p>이 함수는 이런 식으로 호출되죠:</p> + +<pre class="brush: js notranslate">myGreeting();</pre> + +<p>이 방법은 효과적으로 함수에 이름을 부여하고 있어요. 당신은 다중 변수들에 함수를 할당할 수도 있죠. 예를 들면,</p> + +<pre class="brush: js notranslate">var anotherGreeting = function() { + alert('hello'); +}</pre> + +<p>이제 함수는 이런 식으로도 호출이 가능해졌구요.</p> + +<pre class="brush: js notranslate">myGreeting(); +anotherGreeting();</pre> + +<p>하지만 위의 방식은 사람 헷갈리게 만들어요. 그니깐 쓰진 맙시다! 함수를 만들 땐 아래의 형태를 고수하는 게 나아요.</p> + +<pre class="brush: js notranslate">function myGreeting() { + alert('hello'); +}</pre> + +<p>익명함수는 이벤트 발생에 따른 수많은 코드를 작동시키기 위해 주로 쓰이게 돼요. 이벤트 핸들러를 사용한 버튼의 클릭과 같은 상황에 말이죠. 자, 그 코드는 아래와 같이 생겼어요.</p> + +<pre class="brush: js notranslate">myButton.onclick = function() { + alert('hello'); + // 내가 원하는 만큼 얼마든지 + // 여기에 코드를 작성하면 됩니다! +}</pre> + +<h2 id="매개변수"><strong>매개변수</strong></h2> + +<p>몇몇 함수는 호출을 위해 매개변수를 필요로 하는 경우가 있습니다. 이런 함수가 제대로 작동하기 위해선 함수 괄호 안에 값들을 넣어주어야 해요.</p> + +<div class="note"> +<p><strong>Note</strong>: 매개변수는 종종 arguments, properties, 심지어 attributes 라고도 불려요.</p> +</div> + +<p>예를 들어, 내장 함수인 <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/random">Math.random()</a>은 어떤 매개변수도 필요로 하지 않습니다. 이 함수는 호출되면 늘 0과 1사이의 무작위 수를 반환해 주죠. </p> + +<pre class="brush: js notranslate">var myNumber = Math.random();</pre> + +<p>하지만 내장 함수 <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/replace">replace()</a>는 두 개의 매개변수를 필요로 합니다. 대체될 문자와 대체할 문자죠. </p> + +<pre class="brush: js notranslate">var myText = 'I am a string'; +var newString = myText.replace('string', 'sausage');</pre> + +<div class="note"> +<p><strong>Note</strong>: 여러 개의 매개변수는 콤마에 의해 구분되어 집니다. </p> +</div> + +<p>매개변수는 이따금 선택 사항이기도 합니다. 당신이 명시해 줄 필요가 없다는 뜻이죠. 그런 경우, 일반적으로 함수는 디폴트 기능을 수행합니다. 예를 들어, 배열과 관련된 <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/join">join()</a> 함수의 매개변수가 그렇죠.</p> + +<pre class="brush: js notranslate">var myArray = ['I', 'love', 'chocolate', 'frogs']; +var madeAString = myArray.join(' '); +// returns 'I love chocolate frogs' +var madeAString = myArray.join(); +// returns 'I,love,chocolate,frogs'</pre> + +<p>만일 결합의 기준이 될 매개변수가 없다면, 콤마가 매개변수로서 사용됩니다.</p> + +<h2 id="함수_스코프와_충돌">함수 스코프와 충돌</h2> + +<p>우리 '스코프(scope)'에 대해 얘기해 볼까요? '스코프'는 함수와 관련된 매우 중요한 개념입니다. 함수를 생성할 때, 변수 및 함수 내 정의된 코드들은 그들만의 '스코프' 안에 자리하게 됩니다. 그 말인 즉슨, 다른 함수의 내부나 외부 함수의 코드가 접근할 수 없는 그들만의 구획에 갇혀 있다는 뜻입니다. </p> + +<p>함수 바깥에 선언된 가장 상위 레벨의 스코프를 '<strong>전역 스코프</strong>(global scope)' 라고 부릅니다.전역 스코프 내에 정의된 값들은 어느 코드든 접근이 가능합니다.</p> + +<p>자바스크립트는 다양한 이유로 인해 이와 같은 기능을 제공하지만, 주로는 안전성과 구조 때문입니다. 어떤 때에는 당신의 변수가 어느 코드나 접근 가능한 변수가 되는 걸 원치 않을 겁니다. 당신이 어딘가에서 불러온 외부 스크립트가 문제를 일으킬 수도 있으니깐요. 외부 스크립트의 코드와 같은 변수 이름을 사용하면 충돌이 일어나게 돼요. 이건 악의적일 수도 있고, 아님 뭐 단순한 우연이겠죠.</p> + +<p>예를 들어 , 당신에게 두 개의 외부 자바스크립트 파일을 호출하는 HTML이 있다고 쳐요. 그 둘은 같은 이름으로 정의된 변수와 함수를 사용하고 있습니다.</p> + +<pre class="brush: html notranslate"><!-- Excerpt from my HTML --> +<script src="first.js"></script> +<script src="second.js"></script> +<script> + greeting(); +</script></pre> + +<pre class="brush: js notranslate">// first.js +var name = 'Chris'; +function greeting() { + alert('Hello ' + name + ': welcome to our company.'); +}</pre> + +<pre class="brush: js notranslate">// second.js +var name = 'Zaptec'; +function greeting() { + alert('Our company is called ' + name + '.'); +}</pre> + +<p>두 함수 모두 <code>greeting()</code>라고 불리지만, 당신은 <code>second.js</code> 파일의 <code>greeting()</code> 함수에만 접근 가능합니다. HTML 소스 코드 상 후자이므로, 그 파일의 변수와 기능이 <code>first.js</code>것을 덮어쓰는 거죠.</p> + +<div class="note"> +<p><strong>Note</strong>: 예제를 여기서 볼 수 있습니다. <a href="http://mdn.github.io/learning-area/javascript/building-blocks/functions/conflict.html">running live on GitHub</a> (<a href="https://github.com/mdn/learning-area/tree/master/javascript/building-blocks/functions">source code</a> 또한 볼 수 있습니다.).</p> +</div> + +<p>함수의 일부를 코드 안에 가두는 것은 이러한 문제를 피할 수 있고, 가장 좋은 방법이라 여겨집니다.</p> + +<p>동물원 같네요. 사자, 얼룩말, 호랑이, 그리고 펭귄은 자신들만의 울타리 안에 있으며, 그들의 울타리 내부에 있는 것만 건드릴 수 있어요. 함수 스코프처럼 말이죠. 만약 동물들이 다른 울타리 안으로 들어갈 수 있었다면, 문제가 생겼을 겁니다. 좋게는 다른 동물이 낯선 거주 환경에서 불편함을 느끼는 정도겠죠. 사자나 호랑이가 펭귄의 물기 많고 추운 영역 안에서 끔찍함을 느끼듯이요. 하지만 최악의 상황엔 사자나 호랑이가 펭귄을 먹어 치울 지도 모르죠!</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/14079/MDN-mozilla-zoo.png" style="display: block; margin: 0 auto;"></p> + +<p>사육사는 전역 스코프와 같습니다. 그들은 모든 울타리에 들어갈 수 있고, 먹이를 보충하고, 아픈 동물들을 돌볼 수 있어요.</p> + +<h3 id="실습_스코프랑_놀자">실습: 스코프랑 놀자</h3> + +<p>스코프 사용의 실례를 한번 봅시다.</p> + +<ol> + <li>먼저, 주어진 <a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/functions/function-scope.html">function-scope.html</a> 예제의 복사본을 만드세요. 예제에는 2개의 function <code>a()</code> 와 <code>b()</code> 와, 3개의 변수 — <code>x</code>, <code>y</code>, 와 <code>z</code> —가 있습니다. 그 중 2개는 함수 안에 정의되어 있으며, 1개는 전역 범위에 정의되어 있습니다. It also contains a third function called <code>output()</code>, 이건 하나의 매개변수만 받으며, and outputs it in a paragraph on the page.</li> + <li>예제를 인터넷 브라우저나 텍스트 에디터를 통해 열어봅시다.</li> + <li>브라우저 개발자 툴을에서 자바스크립트 콘솔을 엽시다. 자바스크립트 콘솔에서 아래와 같이 작성해보세요: + <pre class="brush: js notranslate">output(x);</pre> + 변수 <code>x</code>의 결과값을 볼 수 있습니다.</li> + <li>Now try entering the following in your console + <pre class="brush: js notranslate">output(y); +output(z);</pre> + Both of these should return an error along the lines of "<a href="/en-US/docs/Web/JavaScript/Reference/Errors/Not_defined">ReferenceError: y is not defined</a>". Why is that? Because of function scope — <code>y</code> and <code>z</code> are locked inside the <code>a()</code> and <code>b()</code> functions, so <code>output()</code> can't access them when called from the global scope.</li> + <li>However, what about when it's called from inside another function? Try editing <code>a()</code> and <code>b()</code> so they look like this: + <pre class="brush: js notranslate">function a() { + var y = 2; + output(y); +} + +function b() { + var z = 3; + output(z); +}</pre> + Save the code and reload it in your browser, then try calling the <code>a()</code> and <code>b()</code> functions from the JavaScript console: + + <pre class="brush: js notranslate">a(); +b();</pre> + You should see the <code>y</code> and <code>z</code> values output in the page. This works fine, as the <code>output()</code> function is being called inside the other functions — in the same scope as the variables it is printing are defined in, in each case. <code>output()</code> itself is available from anywhere, as it is defined in the global scope.</li> + <li>Now try updating your code like this: + <pre class="brush: js notranslate">function a() { + var y = 2; + output(x); +} + +function b() { + var z = 3; + output(x); +}</pre> + </li> + <li>Save and reload again, and try this again in your JavaScript console: + <pre class="brush: js notranslate">a(); +b();</pre> + </li> + <li>Both the <code>a()</code> and <code>b()</code> call should output the value of x — 1. These work fine because even though the <code>output()</code> calls are not in the same scope as <code>x</code> is defined in, <code>x</code> is a global variable so is available inside all code, everywhere.</li> + <li>Finally, try updating your code like this: + <pre class="brush: js notranslate">function a() { + var y = 2; + output(z); +} + +function b() { + var z = 3; + output(y); +}</pre> + </li> + <li>Save and reload again, and try this again in your JavaScript console: + <pre class="brush: js notranslate">a(); +b();</pre> + This time the <code>a()</code> and <code>b()</code> calls will both return that annoying "<a href="/en-US/docs/Web/JavaScript/Reference/Errors/Not_defined">ReferenceError: z is not defined</a>" error — this is because the <code>output()</code> calls and the variables they are trying to print are not defined inside the same function scopes — the variables are effectively invisible to those function calls.</li> +</ol> + +<div class="note"> +<p><strong>Note</strong>: The same scoping rules do not apply to loop (e.g. <code>for() { ... }</code>) and conditional blocks (e.g. <code>if() { ... }</code>) — they look very similar, but they are not the same thing! Take care not to get these confused.</p> +</div> + +<div class="note"> +<p><strong>Note</strong>: The <a href="/en-US/docs/Web/JavaScript/Reference/Errors/Not_defined">ReferenceError: "x" is not defined</a> error is one of the most common you'll encounter. If you get this error and you are sure that you have defined the variable in question, check what scope it is in.</p> +</div> + +<ul> +</ul> + +<h3 id="Functions_inside_functions">Functions inside functions</h3> + +<p>Keep in mind that you can call a function from anywhere, even inside another function. This is often used as a way to keep code tidy — if you have a big complex function, it is easier to understand if you break it down into several sub-functions:</p> + +<pre class="brush: js notranslate">function myBigFunction() { + var myValue; + + subFunction1(); + subFunction2(); + subFunction3(); +} + +function subFunction1() { + console.log(myValue); +} + +function subFunction2() { + console.log(myValue); +} + +function subFunction3() { + console.log(myValue); +} +</pre> + +<p>Just make sure that the values being used inside the function are properly in scope. The example above would throw an error <code>ReferenceError: myValue is not defined</code>, because although the <code>myValue</code> variable is defined in the same scope as the function calls, it is not defined inside the function definitions — the actual code that is run when the functions are called. To make this work, you'd have to pass the value into the function as a parameter, like this:</p> + +<pre class="brush: js notranslate">function myBigFunction() { + var myValue = 1; + + subFunction1(myValue); + subFunction2(myValue); + subFunction3(myValue); +} + +function subFunction1(value) { + console.log(value); +} + +function subFunction2(value) { + console.log(value); +} + +function subFunction3(value) { + console.log(value); +}</pre> + +<h2 id="Conclusion">Conclusion</h2> + +<p>This article has explored the fundamental concepts behind functions, paving the way for the next one in which we get practical and take you through the steps to building up your own custom function.</p> + +<h2 id="See_also">See also</h2> + +<ul> + <li><a href="/en-US/docs/Web/JavaScript/Guide/Functions">Functions detailed guide</a> — covers some advanced features not included here.</li> + <li><a href="/en-US/docs/Web/JavaScript/Reference/Functions">Functions reference</a></li> + <li><a href="/en-US/docs/Web/JavaScript/Reference/Functions/Default_parameters">Default parameters</a>, <a href="/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions">Arrow functions</a> — advanced concept references</li> +</ul> + +<ul> +</ul> + +<p>{{PreviousMenuNext("Learn/JavaScript/Building_blocks/Looping_code","Learn/JavaScript/Building_blocks/Build_your_own_function", "Learn/JavaScript/Building_blocks")}}</p> + +<h2 id="In_this_module">In this module</h2> + +<ul> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/conditionals">Making decisions in your code — conditionals</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Looping_code">Looping code</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Functions">Functions — reusable blocks of code</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Build_your_own_function">Build your own function</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Return_values">Function return values</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Events">Introduction to events</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Image_gallery">Image gallery</a></li> +</ul> diff --git a/files/ko/learn/javascript/building_blocks/index.html b/files/ko/learn/javascript/building_blocks/index.html new file mode 100644 index 0000000000..27e2a90cf5 --- /dev/null +++ b/files/ko/learn/javascript/building_blocks/index.html @@ -0,0 +1,49 @@ +--- +title: JavaScript 구성요소 +slug: Learn/JavaScript/Building_blocks +tags: + - 가이드 + - 국제화 + - 소개 + - 자바스크립트 + - 초보자 + - 함수 +translation_of: Learn/JavaScript/Building_blocks +--- +<div>{{LearnSidebar}}</div> + +<p class="summary">이번 장에서는 조건문, 반복문, 함수, 이벤트 등 일반적으로 발생하는 코드 종류를 중심으로 JavaScript의 중요한 기본 기능에 대해 설명합니다. 지금까지의 과정을 지나면서 여기서 다룰 내용을 살짝 보셨겠지만 좀 더 심도있게 다루겠습니다.</p> + +<h2 id="선행사항">선행사항</h2> + +<p>시작하기전에, 기본 <a href="/ko/docs/Learn/HTML/Introduction_to_HTML">HTML</a>, <a href="/ko/docs/Learn/CSS/Introduction_to_CSS">CSS</a> 기본지식을 가지고 계신 것이 좋습니다. 그리고 <a href="/ko/docs/Learn/JavaScript/First_steps">JavaScript 첫 걸음</a>을 꼭 진행하신후 오시기 바랍니다.</p> + +<div class="note"> +<p><strong>Note</strong>: 여기 나온 코드를 작성하고 실행해 볼 수 없는 환경이라면 (태블릿, 스마트폰, 기타장치) , <a href="http://jsbin.com/">JSBin</a>이나 <a href="https://glitch.com">Glitch</a>에서 대부분의 예제를 시험해 볼 수 있습니다.</p> +</div> + +<h2 id="가이드">가이드</h2> + +<dl> + <dt><a href="/ko/docs/Learn/JavaScript/Building_blocks/conditionals">Making decisions in your code — conditionals</a></dt> + <dd>어떤 프로그래밍 언어든 코드는 의사 결정을 내리고 입력 내용에 따라 작업을 수행해야합니다. 예를 들어 게임에서 플레이어의 생명 수치가 0이면 게임이 종료됩니다. 날씨 앱에서는 아침에 해가 뜬 그림을 보여주고 밤에는 달과 별을 보여줍니다. 이 문서에서는 JavaScript에서 조건문이 작동하는 방법을 살펴 보겠습니다. </dd> + <dt><a href="/ko/docs/Learn/JavaScript/Building_blocks/Looping_code">반복문</a></dt> + <dd>때로는 여러 반복 작업을 수행해야 할 때가 있습니다. 예를 들면 이름 목록을 살펴보는 것입니다. 프로그래밍에서 이런 반복 작업은 매우 적합합니다. JavaScript의 반복문 구조를 살펴봅니다.</dd> + <dt><a href="/ko/docs/Learn/JavaScript/Building_blocks/Functions">함수 — 코드 재사용</a></dt> + <dd>코딩의 또 다른 핵심 개념은 <strong>함수</strong>입니다. <strong>함수</strong>를 사용하면 정의된 구간 안에 하나의 작업을 하는 코드를 저장한 후, 같은 코드를 여러 번 입력하지 않고도 짧은 명령어를 사용해 이 코드를 이용할 수 있습니다. 기본 문법, 함수, 범위 및 매개 변수를 호출하고 정의하는 방법과 같은 함수의 기본 개념을 살펴봅니다.</dd> + <dt><a href="/ko/docs/Learn/JavaScript/Building_blocks/Build_your_own_function">함수 만들기</a></dt> + <dd>그동안 배운 이론을 활용해 실제 코드를 작성해봅니다. 사용자 정의 함수를 작성해 보고, 함수의 유용한 기능을 좀 더 알아봅니다.</dd> + <dt><a href="/ko/docs/Learn/JavaScript/Building_blocks/Return_values">함수는 값을 반환한다</a></dt> + <dd>함수에 대해 알아야 할 마지막 필수 개념은 반환값입니다. 어떤 함수는 완료하면서 값을 반환하지 않지만, 반환하는 함수도 있습니다. 값이 무엇인지, 코드에서 어떻게 사용하는지, 여러분이 작성한 함수가 어떻게 값을 반환하는지 이해하는 것이 중요합니다.</dd> + <dt><a href="/ko/docs/Learn/JavaScript/Building_blocks/Events">Introduction to events</a></dt> + <dd>이벤트란 프로그래밍중인 시스템에서 발생하는 동작이나 발생을 말하며, 시스템에서 그에 대해 알려주므로 원하는 경우 사용자가 어떤 방식으로든 이에 응답 할 수 있습니다. 예를 들어 사용자가 웹 페이지에서 버튼을 클릭하면 정보 상자를 표시하여 해당 작업에 응답 할 수 있습니다. 이 마지막 문서에서는 이벤트를 둘러싼 몇 가지 중요한 개념에 대해 이야기하고 브라우저에서 어떻게 작동하는지 살펴 보겠습니다.</dd> +</dl> + +<h2 id="평가">평가</h2> + +<p>여기에선 위에서 다룬 JavaScript 기본 사항에 대해 여러분이 얼마나 이해했는지 테스트해볼 수 있습니다..</p> + +<dl> + <dt><a href="/ko/docs/Learn/JavaScript/Building_blocks/Image_gallery">Image gallery</a></dt> + <dd>이제 JavaScript의 기본 구성 요소를 살펴 보았으므로 많은 웹 사이트에서 볼 수있는 공통 항목인 JavaScript 기반 이미지 갤러리를 만들어 반복문, 함수, 조건문, 이벤트에 대한 지식을 테스트합니다.</dd> +</dl> diff --git a/files/ko/learn/javascript/building_blocks/looping_code/index.html b/files/ko/learn/javascript/building_blocks/looping_code/index.html new file mode 100644 index 0000000000..e95a78af37 --- /dev/null +++ b/files/ko/learn/javascript/building_blocks/looping_code/index.html @@ -0,0 +1,948 @@ +--- +title: Looping code +slug: Learn/JavaScript/Building_blocks/Looping_code +tags: + - for문 + - 반복문 + - 초보자 +translation_of: Learn/JavaScript/Building_blocks/Looping_code +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/JavaScript/Building_blocks/조건문", "Learn/JavaScript/Building_blocks/Functions", "Learn/JavaScript/Building_blocks")}}</div> + +<p class="summary">프로그래밍 언어는 다양한 작업을 통해 반복적 인 작업을 신속하게 처리 할 수 있습니다. 이제 우리는 JavaScript를 사용하여 반복 구문을 사용하여 편리하게 처리 할 수 있습니다. </p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">선수 과목 :</th> + <td>기본적인 컴퓨터 활용 능력, HTML과 CSS, <a href="/en-US/docs/Learn/JavaScript/First_steps">자바 스크립트</a> 의 기본 이해 .</td> + </tr> + <tr> + <th scope="row">목표:</th> + <td>JavaScript에서 루프를 사용하는 방법을 이해합니다.</td> + </tr> + </tbody> +</table> + +<h2 id="나를_계속_붙잡아_라.">나를 계속 붙잡아 라.</h2> + +<p>반복(loop), 반복 반복. <a href="https://en.wikipedia.org/wiki/Froot_Loops">popular breakfast cereals</a>, <a href="https://en.wikipedia.org/wiki/Vertical_loop">roller coasters</a> 그리고 <a href="https://en.wikipedia.org/wiki/Loop_(music)">musical production</a>과 같이, 그것들은 프로그래밍의 중요한 개념이다. 프로그래밍 loop는 반복적으로 동일한 작업을 반복하는것이고 이런것들을 프로그래밍 언어로 loop라 한다.</p> + +<p>가족들이 일주일동안 먹을 식량이 충분한지 확신하기 위해 고민하는 농부의 상황을 보자. 그는 이것을 알기위해 다음과 같은 loop를 취할수 있다:</p> + +<p><br> + <img alt="" src="https://mdn.mozillademos.org/files/13755/loop_js-02-farm.png" style="display: block; margin: 0 auto;"></p> + +<p>이 loop에서 다음과 같이 우리는 한가지 이상의 기능을 가질수 있다:</p> + +<ul> + <li><strong>counter</strong>은 특정 값으로 초기화된다 — loop의 시작점이다. ("시작: I have no food", 위 그림을 참고).</li> + <li><strong>exit condition</strong>는 loop가 멈추는 기준이 되는 종료 조건 — 보통 counter가 특정 값에 도달하면 멈추게된다. 이것은 위에서 "Have I got enough food?"라고 설명되어 있다. 가족에게 먹일 음식 10개가 필요하다고 가정 해 보자.</li> + <li><strong>iterator</strong>는 끝나는 조건에 도달 할 때까지 일반적으로 counter를 각각의 연속된 루프에서 조금 씩 증가시킨다. 우리는 위에 명시적으로 설명하지 않았지만, 농부가 시간 당 음식을 2개씩 수집 할 수 있다고 생각할 수 있다. 매시간 후, 그가 모은 음식의 양은 2개씩 증가하고, 그는 음식이 충분한 지 여부를 확인한다. 그가 10개(종료 조건)에 도달하면, 그는 수집을 중지하고 집에 갈수 있다.</li> +</ul> + +<p>{{glossary("pseudocode")}}에서 이것은 다음과 같아 보일 것이다.:</p> + +<pre class="notranslate">loop(food = 0; foodNeeded = 10) { + if (food = foodNeeded) { + exit loop; + // We have enough food; let's go home + } else { + food += 2; // Spend an hour collecting 2 more food + // loop will then run again + } +}</pre> + +<p>따라서 필요한 음식의 양은 10으로 설하고, 현재 농부의 양은 0으로 설정한다. 매 반복마다 농부의 음식 양이 필요한 양과 같은지 확인한다. 필요한 양을 얻었다면 loop를 종료 할수 있다. 그렇지 않다면, 농부는 음식을 모을때까지 다시 반복해서 loop를 실행한다.</p> + +<h3 id="왜_귀찮게">왜 귀찮게?</h3> + +<p>여기에서 loop의 뒤에 있는 고급개념을 이해했을 것이다. 하지만 "그래 뭐 괜찮군 그래서 이 코드가 어떻게 도움이 될수 있는거지?"라고 생각할수도 있다. 앞서 말햇듯이 <strong>loop는 반복적인 작업을 빠르게 동일한 작업을 반복해서 수행해 완료하는 것이다.</strong></p> + +<p>종종 코드는 각각의 연속적인 반복된 loop에서 조금씩 달라질수도 있다. 그래서 유사하지만 약간 다른 작업에 이것을 이용해 작업을 완료할수도 있다.만약 너가 여러가지 다른종류의 계산을 해야한다면, 반복해서 처리하는게 아닌 각각 계산하고 싶을것이다.</p> + +<p>Loop가 왜 그렇게 좋은지 완벽하게 설명하는 예제를 한번 보자. {{htmlelement("canvas")}} element에 100개의 무작위 원을 그려야 한다고 가정해보자. (예제를 다시 실행하여 다른 임의의 세트를 보려면 Update 버튼을 클릭) :</p> + +<div class="hidden"> +<h6 id="Hidden_code">Hidden code</h6> + +<pre class="brush: html notranslate"><!DOCTYPE html> +<html> + <head> + <meta charset="utf-8"> + <title>Random canvas circles</title> + <style> + html { + width: 100%; + height: inherit; + background: #ddd; + } + + canvas { + display: block; + } + + body { + margin: 0; + } + + button { + position: absolute; + top: 5px; + left: 5px; + } + </style> + </head> + <body> + + <button>Update</button> + + <canvas></canvas> + + + <script> + const btn = document.querySelector('button'); + const canvas = document.querySelector('canvas'); + const ctx = canvas.getContext('2d'); + + let WIDTH = document.documentElement.clientWidth; + let HEIGHT = document.documentElement.clientHeight; + + canvas.width = WIDTH; + canvas.height = HEIGHT; + + function random(number) { + return Math.floor(Math.random()*number); + } + + function draw() { + ctx.clearRect(0,0,WIDTH,HEIGHT); + for (let i = 0; i < 100; i++) { + ctx.beginPath(); + ctx.fillStyle = 'rgba(255,0,0,0.5)'; + ctx.arc(random(WIDTH), random(HEIGHT), random(50), 0, 2 * Math.PI); + ctx.fill(); + } + } + + btn.addEventListener('click',draw); + + </script> + + </body> +</html></pre> +</div> + +<p>{{ EmbedLiveSample('Hidden_code', '100%', 400, "", "", "hide-codepen-jsfiddle") }}</p> + +<p>지금 당장은 모든 코드를 이해할 필요는 없지만 실제로100개의 원을 그리는 코드를 살펴보자:</p> + +<pre class="brush: js notranslate">for (let i = 0; i < 100; i++) { + ctx.beginPath(); + ctx.fillStyle = 'rgba(255,0,0,0.5)'; + ctx.arc(random(WIDTH), random(HEIGHT), random(50), 0, 2 * Math.PI); + ctx.fill(); +}</pre> + +<ul> + <li>코드의 앞부분에서 정의한<code>random()</code>은 <code>0</code> 그리고 <code>x-1</code>사이의 정수를 반환한다.</li> + <li><code>WIDTH</code> 그리고 <code>HEIGHT</code> 는 내부 브라우저 윈도우의 너비와 높이이다.</li> +</ul> + +<p>우리는 이 코드를 100번 반복하기 위해서 loop를 사용하고 있다. 너는 여기에서 기본적인 아이디어를 얻을수 있다. 코드는 페이지에서 임의의 위치에 원을 그린다. 코드의 크기가 100개가 되든 1000개가 되든 또는 10,000개가 되든간에 동일하게 작업을 수행할것이다. 너는 숫자만 변경하면된다.</p> + +<p>만약 우리가 loop를 사용하지 않았다면 원을 그릴때마다 다음 코드를 반복해서 써야한다 :</p> + +<pre class="brush: js notranslate">ctx.beginPath(); +ctx.fillStyle = 'rgba(255,0,0,0.5)'; +ctx.arc(random(WIDTH), random(HEIGHT), random(50), 0, 2 * Math.PI); +ctx.fill();</pre> + +<p>이것은 겁나 지루하고 빠르게 유지하기 힘들것이다. 이럴때 loop를 사용하는게가장 좋다.</p> + +<h2 id="루프의_표준">루프의 표준</h2> + +<p>특정 loop 구문을 살펴보도록 하자. 대부분의 시간을 보낼 첫번째는 for loop이다. 이 구문은 다음과 같다:</p> + +<pre class="notranslate">for (initializer; exit-condition; final-expression) { + // code to run +}</pre> + +<p>여기서 우리가 알수있는것:</p> + +<ol> + <li><code>for</code> 라는 키워드를 쓰고 그옆에 괄호를 만든다.</li> + <li>괄호 안에는 세미콜론(;)으로 구분 된 세개의 항목이 있다. + <ol> + <li><strong>initializer</strong> — 일반적으로 숫자로 설정된 변수이며 루프가 실행 된 횟수가 얼마나 되는제 되는지 알기위해 증가한다 그것을 <strong>counter variable</strong>라고 한다.</li> + <li><strong>exit-condition</strong> — 앞에서 언급했듯이 loop가 loop를 언제 멈출지 정의한다. 이 조건은 일반적으로 비교 연산자, 종료 조건이 충족되었는지 확인하는 테스트를 특징으로 하는 표현식이다.</li> + <li>A <strong>final-expression</strong> — 이것은 매번 loop 전체가 반복이 될때 항상 분석(또는 실행)한다. 일반적으로 <strong>counter variable</strong>를 증가(또는 경우에 따라 감소)하여 종료 조건 값으로 점점 가까워진다.</li> + </ol> + </li> + <li>코드 블럭을 감싸는 중괄호({}) — 중괄호 안에 있는 코드는 loop가 반복 될 때마다 실행된다.</li> +</ol> + +<p>실제 예제를 보면서 이러한 것들이 무엇을 더 확실하게 시각화 할 수 있는지 살펴보자.</p> + +<pre class="brush: js notranslate">const cats = ['Bill', 'Jeff', 'Pete', 'Biggles', 'Jasmin']; +let info = 'My cats are called '; +const para = document.querySelector('p'); + +for (let i = 0; i < cats.length; i++) { + info += cats[i] + ', '; +} + +para.textContent = info;</pre> + +<p>이것은 우리에게 다음과 같은 결과를 보여준다:</p> + +<div class="hidden"> +<h6 id="Hidden_code_2">Hidden code 2</h6> + +<pre class="brush: html notranslate"><!DOCTYPE html> +<html> + <head> + <meta charset="utf-8"> + <title>Basic for loop example</title> + <style> + + </style> + </head> + <body> + + <p></p> + + + <script> + const cats = ['Bill', 'Jeff', 'Pete', 'Biggles', 'Jasmin']; + let info = 'My cats are called '; + const para = document.querySelector('p'); + + for (let i = 0; i < cats.length; i++) { + info += cats[i] + ', '; + } + + para.textContent = info; + + </script> + + </body> +</html></pre> +</div> + +<p>{{ EmbedLiveSample('Hidden_code_2', '100%', 60, "", "", "hide-codepen-jsfiddle") }}</p> + +<div class="note"> +<p><strong>Note</strong>: 너는 <a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/loops/basic-for.html">example code on GitHub</a> too (also <a href="http://mdn.github.io/learning-area/javascript/building-blocks/loops/basic-for.html">see it running live</a>)에서 예제를 찾을수 있다.</p> +</div> + +<p>이것은 배열의 항목을 반복하는 데 사용되는 loop를 보여 주며 각각의 항목을 사용하여 JavaScript에서 매우 일반적인 패턴을 나타낸다:</p> + +<ol> + <li>iterator <code>i</code>는 <code>0</code>에서부터 시작한다 (<code>let i = 0</code>).</li> + <li><code><font face="Arial, x-locale-body, sans-serif">cats의 배열의 길이보다 작을때 까지만 실행하라는 명령을 받았다. 이것은 중요하다. 종료 조건은 loop가 계속 실행되는 조건을 나타낸다. 따라서 이 경우에는 </font>i < cats.length</code> 까지만 loop가 true여서 계속 실행된다.</li> + <li>loop 안에서 현재 loop항목(<code>cats[i가 몇번 실행되었던지 간에</code> <code>cats[i]</code> 는)과 쉼표 및 공백을 <code>info</code>변수 끝에 위치한다: + <ol> + <li>처음 실행되는 동안, <code>i = 0</code>, 이므로 <code>cats[0] + ', '</code> 는 info ("Bill, ")에 옆에 위치한다.</li> + <li>두번째로 실행되는 동안, <code>i = 1</code>, 이므로 <code>cats[1] + ', '</code> 역시 info ("Jeff, ")에 옆에 위치한다.</li> + <li>계속해서 loop가 실행될 때마다 1이 <code>i</code> (<code>i++</code>)에 추가되고, 프로세스가 다시 시작된다.</li> + </ol> + </li> + <li><code>i</code>의 값이 <code>cats.length</code>같아질때, loop는 멈추고, 브라우저는 loop 아래의 다음 코드로 넘어가게된다.</li> +</ol> + +<div class="note"> +<p><strong>Note</strong>: 컴퓨터는 1이 아닌 0부터 계산하기 때문에 exit 조건을<code>i <= cats.length</code>이 아닌 <code>i < cats.length</code>로 설정했다. — 우리는 <code>i</code> 를 <code>0</code>에서 시작해서, <code>i = 4</code> (배열의 마지막 index 항목)까지 실행한다. <code>cats.length</code> 는 5개의 항목을 가지고있어 5까지 반환하지만 우리는 <code>i = 5</code>까지의 값을 원하지 않으므로 마지막 항목은 <code>undefined</code>를 반환하게 된다.(그래서 index가 5인 배열 항목이 존재하지 않는다.)그러므로 <code>cats.length</code> (<code>i <=</code>) 를 쓰지 않고 <code>cats.length</code> (<code>i <</code>)로 만들었다.</p> +</div> + +<div class="note"> +<p><strong>Note</strong>: exit조건의 공통적인 실수는 "작거나 같다" (<code><=</code>)를 사용하는것보다 "동등"(<code>===</code>)을 사용하는것이다 . 만약 우리가 <code>i = 5</code>까지 loop를 사용한다면 exit 조건은 <code>i <= cats.length</code>가 되어야 한다. 만약 우리가 <code>i === cats.length</code>로 설정한다면 그 loop는 전부를 실행하지 않을것이다 왜냐하면 <code>i</code>는 첫번째 loop에서 <code>5</code>와 같지 않기 때문에 작업이 즉시 중단된다. </p> +</div> + +<p>우리는 마지막으로 출력되는 문장이 잘 만들어지지 않았다는 작은 문제를 가지고 있다.:</p> + +<blockquote> +<p>My cats are called Bill, Jeff, Pete, Biggles, Jasmin,</p> +</blockquote> + +<p>이상적으로 우리는 문장의 마지막에 쉼표가 없도록 마지막 loop 반복에서 연결을 변경하는것을 원한다 — 우리는 for loop 내부에서 조건부를 넣어서 이 특별한 경우를 처리할수 있다:</p> + +<pre class="brush: js notranslate">for (let i = 0; i < cats.length; i++) { + if (i === cats.length - 1) { + info += 'and ' + cats[i] + '.'; + } else { + info += cats[i] + ', '; + } +}</pre> + +<div class="note"> +<p><strong>Note</strong>: 너는 <a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/loops/basic-for-improved.html">example code on GitHub</a> too (also <a href="http://mdn.github.io/learning-area/javascript/building-blocks/loops/basic-for-improved.html">see it running live</a>)에서 예제를 찾아볼수있다.</p> +</div> + +<div class="warning"> +<p><strong>중요</strong>: With for — 모든 loop와 마찬가지로 — initializer 가 반복되어 결국 종료 조건에 도달하는지 확인해야 한다. 그렇지 않으면 loop가 영원히 계속되고 브라우저가 강제로 중지 시키거나 충돌하게 된다. 이를 우리는 <strong>infinite loop(무한 루프)</strong>라 한다.</p> +</div> + +<h2 id="Break을_가지고있는_loops">Break을 가지고있는 loops</h2> + +<p>만약 너가 모든 반복이 완료되기 전에 loop를 종료하려면 <a href="/en-US/docs/Web/JavaScript/Reference/Statements/break">break</a> 문을 사용할수 있다. 우리는 이미 이전 설명에서 <a href="/en-US/Learn/JavaScript/Building_blocks/conditionals#switch_statements">switch statements</a>을 본적이 있다. — 입력 식과 일치하는 switch 문에서 case가 충족되면 break 문은 switch 문을 즉시 종료하고 그 뒤에 코드로 이동한다.</p> + +<p>이것은 loop와 같다. — <code>break</code> 문은 즉시 loop를 빠져 나와 브라우저가 그 다음에 나오는 코드로 이동하게 한다.</p> + +<p>여러 연락처와 전화 번호를 검색하여 찾고자 하는 번호 만 반환하고 싶다고 해보자 먼저 간단한 HTML — 우리가 검색할 이름을 입력 할 수 잇께 해주는 텍스트 {{htmlelement("input")}}, 검색 제출을 위한 {{htmlelement("button")}}요소, 그리고 {{htmlelement("p")}} 요소를 사용해 결과를 표시하자:</p> + +<pre class="brush: html notranslate"><label for="search">Search by contact name: </label> +<input id="search" type="text"> +<button>Search</button> + +<p></p></pre> + +<p>이제 JavaScript를 보자:</p> + +<pre class="brush: js notranslate">const contacts = ['Chris:2232322', 'Sarah:3453456', 'Bill:7654322', 'Mary:9998769', 'Dianne:9384975']; +const para = document.querySelector('p'); +const input = document.querySelector('input'); +const btn = document.querySelector('button'); + +btn.addEventListener('click', function() { + let searchName = input.value; + input.value = ''; + input.focus(); + for (let i = 0; i < contacts.length; i++) { + let splitContact = contacts[i].split(':'); + if (splitContact[0] === searchName) { + para.textContent = splitContact[0] + '\'s number is ' + splitContact[1] + '.'; + break; + } else { + para.textContent = 'Contact not found.'; + } + } +});</pre> + +<div class="hidden"> +<h6 id="Hidden_code_3">Hidden code 3</h6> + +<pre class="brush: html notranslate"><!DOCTYPE html> +<html> + <head> + <meta charset="utf-8"> + <title>Simple contact search example</title> + <style> + + </style> + </head> + <body> + + <label for="search">Search by contact name: </label> + <input id="search" type="text"> + <button>Search</button> + + <p></p> + + + <script> + const contacts = ['Chris:2232322', 'Sarah:3453456', 'Bill:7654322', 'Mary:9998769', 'Dianne:9384975']; + const para = document.querySelector('p'); + const input = document.querySelector('input'); + const btn = document.querySelector('button'); + + btn.addEventListener('click', function() { + let searchName = input.value; + input.value = ''; + input.focus(); + for (let i = 0; i < contacts.length; i++) { + let splitContact = contacts[i].split(':'); + if (splitContact[0] === searchName) { + para.textContent = splitContact[0] + '\'s number is ' + splitContact[1] + '.'; + break; + } else if (i === contacts.length-1) + para.textContent = 'Contact not found.'; + } + }); + </script> + + </body> +</html></pre> +</div> + +<p>{{ EmbedLiveSample('Hidden_code_3', '100%', 100, "", "", "hide-codepen-jsfiddle") }}</p> + +<ol> + <li>우선 우리는 몇 가지 변수 정의를 한다. 우리는 각 항목이 콜론(:)으로 구분 된 이름과 전화 번호를 포함하는 문자열인 연락처 정보 배열을 가지고 있다.</li> + <li>그 다음에는 버튼 (<code>btn</code>)에 EventListener에 연결하여 버튼을 누르면 검색을 수행하고 결과를 반환하는 코드를 실행한다.</li> + <li>텍스트 input을 비우고 text input 에 focus를 두기 전에, 다음 검색을 준비하기위해 <code><font face="Arial, x-locale-body, sans-serif"><span style="background-color: #ffffff;">텍스트 input에 입력한 값을 </span></font>searchName</code>이라는 변수에 저장한다. </li> + <li>이제 for 반복문의 흥미로운 점을 보자: + <ol> + <li><code><font face="Arial, x-locale-body, sans-serif"><span style="background-color: #ffffff;">카운터를 </span></font>0</code>에서 시작하고 카운터가 <code>contacts.length</code> 보다 커지지 않을때 까지 loop를 실행하고 <code>i</code> 를 1씩 증가시킨다.</li> + <li>반복문 내부에서 먼저 콜론 문자에서 현재 연락처(<code>contacts[i]</code>) 를 나누고 결과값이 두 값을<code>splitContact</code>라는 배열에 저장한다.</li> + <li><code><font face="Arial, x-locale-body, sans-serif"><span style="background-color: #ffffff;">그런 다음 </span></font>splitContact[0]</code> (the contact's name)의 값과 입력된 값 <code>searchName</code>이 같은지 조건문을 이용하여 테스트한다. 두값이 같은 경우, 우리는 para 값에 문자열을 입력하여 연락처 번호를 알린후 <code>break</code> 을 사용하여 loop를 종료한다.</li> + </ol> + </li> + <li> + <p>연락처 이름<code>(contacts.length-1)</code> 을 반복한 후 연락처 이름이 입력 된 검색과 일치 하지 않으면 단락 텍스트가 "연락처 를 찾을 수 없습니다."로 설정되고 반복문이 계속 반복된다.</p> + </li> +</ol> + +<div class="note"> +<p>Note: 너는 <a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/loops/contact-search.html">full source code on GitHub</a> too (also <a href="http://mdn.github.io/learning-area/javascript/building-blocks/loops/contact-search.html">see it running live</a>) 에서 전체 코드를 볼수있다.</p> +</div> + +<h2 id="Continue로_반복_건너뛰기">Continue로 반복 건너뛰기</h2> + +<p><a href="/en-US/docs/Web/JavaScript/Reference/Statements/continue">continue</a>문은 <code>break</code>과 비슷한 방식으로 작동하지만 loop에서 완전히 벗어나는 대신 loop의 다음 반복으로 건너 뛰게된다. 숫자를 입력으로 사용하고 정수의 제곱 인 숫자 (정수)만 반환하는 또 다른 예를 살펴보자.</p> + +<p>HTML 코드는 기본적으로 마지막 예제와 같다 — 간단한 텍스트 입력 및 출력을 위한 단락, loop자체가 약간 다르긴 하지만 JavaScript는 대부분 동일하다 :</p> + +<pre class="brush: js notranslate">let num = input.value; + +for (let i = 1; i <= num; i++) { + let sqRoot = Math.sqrt(i); + if (Math.floor(sqRoot) !== sqRoot) { + continue; + } + + para.textContent += i + ' '; +}</pre> + +<p>여기에서 출력값을 볼수있다:</p> + +<div class="hidden"> +<h6 id="Hidden_code_4">Hidden code 4</h6> + +<pre class="brush: html notranslate"><!DOCTYPE html> +<html> + <head> + <meta charset="utf-8"> + <title>Integer squares generator</title> + <style> + + </style> + </head> + <body> + + <label for="number">Enter number: </label> + <input id="number" type="text"> + <button>Generate integer squares</button> + + <p>Output: </p> + + + <script> + const para = document.querySelector('p'); + const input = document.querySelector('input'); + const btn = document.querySelector('button'); + + btn.addEventListener('click', function() { + para.textContent = 'Output: '; + let num = input.value; + input.value = ''; + input.focus(); + for (let i = 1; i <= num; i++) { + let sqRoot = Math.sqrt(i); + if (Math.floor(sqRoot) !== sqRoot) { + continue; + } + + para.textContent += i + ' '; + } + }); + </script> + + </body> +</html></pre> +</div> + +<p>{{ EmbedLiveSample('Hidden_code_4', '100%', 100, "", "", "hide-codepen-jsfiddle") }}</p> + +<ol> + <li>이 경우에 입력된 값은 숫자(<code>num</code>)여야 한다. <code>for</code> loop는 1에서 시작하는 카운터(이 경우에는 0에 관심이 없기 때문에), 카운터가 입력 <code>num</code> 보다 커질 때 루프가 중지 될 것이라고 말하는 종료 조건 및 매회 마다 1씩 증가되는 반복자가 주어진다.</li> + <li>Loop 내에서<a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/sqrt">Math.sqrt(i)</a>를 사용하여 숫자의 제곱근을 찾은 다음 제곱근이 가장 가까운 정수로 반올림 된 경우와 같은지 테스트 하여 제곱근이 정수인지 확인한다. <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/floor">Math.floor()</a>가 전달받은 숫자에 대해 정수로 바꿔준다.</li> + <li>만약 제곱근과 정수로 바뀐 제곱근이 서로 같지 않다면(<code>!==</code>) 제곱근이 정수가 아니므로 관심이 없다. 이 경우<code>continue</code> 문을 사용하여 번호를 기록하지 않고 다음 루프 반복으로 건너 뛴다.</li> + <li><code><font face="Arial, x-locale-body, sans-serif"><span style="background-color: #ffffff;">만약 제곱근이 정수 인 경우 </span></font>continue</code> 문이 실행되지 않도록 if 블록을 지나치게 건너 뛴다. 대신 현재 <code>i</code> 값과 단락 내용 의 끝 부분에 공백을 연결한다.</li> +</ol> + +<div class="note"> +<p><strong>Note</strong>: 너는 <a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/loops/integer-squares.html">full source code on GitHub</a> too (also <a href="http://mdn.github.io/learning-area/javascript/building-blocks/loops/integer-squares.html">see it running live</a>)에서 전체 코드를 볼수 있다.</p> +</div> + +<h2 id="while_그리고_do_..._while">while 그리고 do ... while</h2> + +<p><code>for</code> 는 JavaScript에서 사용할 수 잇는 유일한 유형의 loop가 아니다. 실제로 많은 다른 것들이 있따. 지금 모든 것을 이해할 필요는 없지만 약간 다른 방식으로 같은 기능을 인식 할 수 있도록 몇 가지 다른 구조를 살펴 보는것이 좋다.</p> + +<p>먼저 <a href="/en-US/docs/Web/JavaScript/Reference/Statements/while">while</a> loop를 살펴보자 이 loop의 구문은 다음과 같다:</p> + +<pre class="notranslate">initializer +while (exit-condition) { + // code to run + + final-expression +}</pre> + +<p>이는 for loop와 매우 비슷하게 작동한다. 단, initializer 변수가 loop 앞에 설정되어 있고, final-expression이 실행되는 코드 다음에 loop 내에 포함되어 있지 않다. 이 두개가 괄호 안에 포함되어 있지 않다. exit-조건은 괄호 안에 포함되며 <code>for</code>대신 <code>while</code> 키워드가 온다.</p> + +<p>같은 세 가지 항목이 여전히 존재하며 for loop와 동일한 순서로 정의되어 있다. exit 조건에 도달햇는지 여부를 확인 하기 전에 initializer를 정의해야 하므로 의미가 있다. loop 내부의 코드가 실행 된 후 최종 조건이 실행되고 (반복이 완료 되었다.) 이는 exit 조건에 아직 도달하지 않은 경우에만 발생한다. </p> + +<p>고양이 목록 예제를 다시 한번 살펴 보자 while loop를 사용하도록 다시 작성해 보자:</p> + +<pre class="brush: js notranslate">let i = 0; + +while (i < cats.length) { + if (i === cats.length - 1) { + info += 'and ' + cats[i] + '.'; + } else { + info += cats[i] + ', '; + } + + i++; +}</pre> + +<div class="note"> +<p><strong>Note</strong>: 이것은 여전히 예상하는 바와 똑같이 작동한다 <a href="http://mdn.github.io/learning-area/javascript/building-blocks/loops/while.html">running live on GitHub</a> (also view the <a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/loops/while.html">full source code</a>).</p> +</div> + +<p><a href="/en-US/docs/Web/JavaScript/Reference/Statements/do...while">do...while</a> loop 는 많이 비슷하지만 while 구조에 변형을 제공한다:</p> + +<pre class="notranslate">initializer +do { + // code to run + + final-expression +} while (exit-condition)</pre> + +<p>이 경우 루프가 시작되기 전에 initializer가 다시 시작된다. <code>do</code> 키워드 는 실행할 코드와 최종 표현식을 포함하는 중괄호 바로 앞에 온다.</p> + +<p><code><font face="Arial, x-locale-body, sans-serif"><span style="background-color: #ffffff;">여기서 차별화 요소는 종료 조건이 그 밖의 모든 것 다음에 괄호로 묶여 있고 </span></font>while</code> 키워드로 시작한다는 것이다. <code>do...while</code> loop 에서 중괄호 안의 코드는 체크가 실행되기 전에 항상 한 번 실행되어 다시 실행되어야 하는지를 확인한다.( 체크가 먼저 오면 코드가 실행 되지 않을 수도 있다.)</p> + +<p><code>do...while</code> loop를 사용하기 위해 고양이 목록 예제를 다시 작성해 보자:</p> + +<pre class="brush: js notranslate">let i = 0; + +do { + if (i === cats.length - 1) { + info += 'and ' + cats[i] + '.'; + } else { + info += cats[i] + ', '; + } + + i++; +} while (i < cats.length);</pre> + +<div class="note"> +<p><strong>Note</strong>: 다시 말하지만 이것은 예상했던 것과 똑같이 작동한다. <a href="http://mdn.github.io/learning-area/javascript/building-blocks/loops/do-while.html">running live on GitHub</a> (also view the <a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/loops/do-while.html">full source code</a>).</p> +</div> + +<div class="warning"> +<p><strong>중요</strong>: while과 do ... while - while - 모든 loop와 마찬가지로 - initalizer 가 반복 되어 결국 종료 조건에 도달하는지 확인해야 한다. 그렇지 않으면 loop는 영원히 계속되고 브라우저가 강제로 종료 시키거나 충돌한다. 이를 <strong>infinite loop(무한 루프)라한다</strong>.</p> +</div> + +<h2 id="활동_학습_카운트_다운_시작!">활동 학습: 카운트 다운 시작!</h2> + +<p>이 연습에서 출력 상자에 간단한 발사 카운트 다운을 인쇄하여 특히 우리가 원하는10에서 Blast off로 출력한다:</p> + +<ul> + <li>Loop를 10에서 0으로 반복한다 initializer — <code>let i = 10;</code>.</li> + <li>반복 할때 마다 새로운 단락을 만들어 <code>const output = document.querySelector('.output');</code> 를 사용하여 <code><div></code>에 추가한다. comments에서 우리는 loop의 어딘가에 사용되어야하는 세 개의 코드 라인을 제공했다: + <ul> + <li><code>const para = document.createElement('p');</code> — 새로운 단락 생성.</li> + <li><code>output.appendChild(para);</code> — 문단을 <code><div></code>에 추가</li> + <li><code>para.textContent =</code> — 단락 안의 텍스트를 등호 다음에 오른쪽에 놓은 것과 동일하게 만든다.</li> + </ul> + </li> + <li><code><font face="Arial, x-locale-body, sans-serif"><span style="background-color: #ffffff;">다른 반복 숫자는 해당 반복에 대한 단락에 다른 텍스트를 넣어야한다.(조건문과 여러 문장이 필요하다 </span></font>para.textContent =</code> lines): + <ul> + <li>숫자가 10이면 단락에 "카우트 다운 10."을 출력해라</li> + <li>숫자가 0이면 "Blast off!"라고 단락에 출력해라.</li> + <li>다른 번호의 경우 단락에 숫자만 출력해라.</li> + </ul> + </li> + <li>반복자를 포함하는 것을 잊지 말아라! 그리고 이 예제에서 각각의 반복 후에 숫자가 증가되는게 아니게 카운트 다운을 하고있다.너는 <code>i++</code> 원하지 <strong>않는다.</strong>— 어떻게 아래로 반복시킬까?</li> +</ul> + +<p>만약 실수를 한 경우 "재설정" 버튼을 사용하여 예제를 얼마든지 재설정 할수 있다. 정말 모르겠다면 "soultion보기"를 눌러 풀이를 보자</p> + +<div class="hidden"> +<h6 id="Active_learning">Active learning</h6> + +<pre class="brush: html notranslate"><h2>Live output</h2> +<div class="output" style="height: 410px;overflow: auto;"> + +</div> + +<h2>Editable code</h2> +<p class="a11y-label">Press Esc to move focus away from the code area (Tab inserts a tab character).</p> +<textarea id="code" class="playable-code" style="height: 300px;width: 95%"> +let output = document.querySelector('.output'); +output.innerHTML = ''; + +// let i = 10; + +// const para = document.createElement('p'); +// para.textContent = ; +// output.appendChild(para); +</textarea> + +<div class="playable-buttons"> + <input id="reset" type="button" value="Reset"> + <input id="solution" type="button" value="Show solution"> +</div> +</pre> + +<p class="brush: js"></p> + +<p class="brush: js"></p> + +<p class="brush: js"></p> + +<pre class="brush: css notranslate">html { + font-family: sans-serif; +} + +h2 { + font-size: 16px; +} + +.a11y-label { + margin: 0; + text-align: right; + font-size: 0.7rem; + width: 98%; +} + +body { + margin: 10px; + background: #f5f9fa; +}</pre> + +<p class="brush: js"></p> + +<p class="brush: js"></p> + +<p class="brush: js"></p> + +<p class="brush: js"></p> + +<pre class="brush: js notranslate">const textarea = document.getElementById('code'); +const reset = document.getElementById('reset'); +const solution = document.getElementById('solution'); +let code = textarea.value; +let userEntry = textarea.value; + +function updateCode() { + eval(textarea.value); +} + +reset.addEventListener('click', function() { + textarea.value = code; + userEntry = textarea.value; + solutionEntry = jsSolution; + solution.value = 'Show solution'; + updateCode(); +}); + +solution.addEventListener('click', function() { + if(solution.value === 'Show solution') { + textarea.value = solutionEntry; + solution.value = 'Hide solution'; + } else { + textarea.value = userEntry; + solution.value = 'Show solution'; + } + updateCode(); +}); + +let jsSolution = 'let output = document.querySelector(\'.output\');\noutput.innerHTML = \'\';\n\nlet i = 10;\n\nwhile(i >= 0) {\n let para = document.createElement(\'p\');\n if(i === 10) {\n para.textContent = \'Countdown \' + i;\n } else if(i === 0) {\n para.textContent = \'Blast off!\';\n } else {\n para.textContent = i;\n }\n\n output.appendChild(para);\n\n i--;\n}'; +let solutionEntry = jsSolution; + +textarea.addEventListener('input', updateCode); +window.addEventListener('load', updateCode); + +// stop tab key tabbing out of textarea and +// make it write a tab at the caret position instead + +textarea.onkeydown = function(e){ + if (e.keyCode === 9) { + e.preventDefault(); + insertAtCaret('\t'); + } + + if (e.keyCode === 27) { + textarea.blur(); + } +}; + +function insertAtCaret(text) { + let scrollPos = textarea.scrollTop; + let caretPos = textarea.selectionStart; + + let front = (textarea.value).substring(0, caretPos); + let back = (textarea.value).substring(textarea.selectionEnd, textarea.value.length); + textarea.value = front + text + back; + caretPos = caretPos + text.length; + textarea.selectionStart = caretPos; + textarea.selectionEnd = caretPos; + textarea.focus(); + textarea.scrollTop = scrollPos; +} + +// Update the saved userCode every time the user updates the text area code + +textarea.onkeyup = function(){ + // We only want to save the state when the user code is being shown, + // not the solution, so that solution is not saved over the user code + if(solution.value === 'Show solution') { + userEntry = textarea.value; + } else { + solutionEntry = textarea.value; + } + + updateCode(); +};</pre> + +<p class="brush: js"></p> +</div> + +<p>{{ EmbedLiveSample('Active_learning', '100%', 880, "", "", "hide-codepen-jsfiddle") }}</p> + +<h2 id="활동_학습_손님_목록_작성">활동 학습: 손님 목록 작성</h2> + +<p>이 연습에서 배열에 저장된 이름 목록을 가져 와서 손님 목록에 넣기를 원한다. 그러나 그것은 쉽지 않다. — 우리는 Phil과 Lola가 욕심 많고 무례하고, 항상 모든 음식을 먹기 때문에 Phil과 Lola를 들여 보내고 싶지 않다. 우리는 초대할 손님 목록과 거절할 손님목록을 가지고 있다.</p> + +<p>특히, 우리가 너에게 원하는 것:</p> + +<ul> + <li><code><font face="Arial, x-locale-body, sans-serif"><span style="background-color: #ffffff;">0부터 </span></font>people</code> 배열의 길이까지 반복 할 loop를 작성해라. <code>let i = 0;</code> 를 initializer 로 시작해야 하지만 종료 조건은 무엇일까?</li> + <li>각 loop 반복 중에 조건문을 사용하여 현재 배열 항목이 "Phil"또는 "Lola"와 같은지 확인해라: + <ul> + <li>그럴 경우 배열 항목을 <code>refused</code> 된 단락의 <code>textContent</code>, 끝에 쉽표와 공백을 붙여 연결해라 .</li> + <li>그렇지 않은 경우 배열 항목을 <code>admitted</code> 된단락의 <code>textContent</code>, 끝에 연결하고 뒤에 쉼표와 공백을 붙인다.</li> + </ul> + </li> +</ul> + +<p>우리는 너에게 이미 아래의 것들을 제공했다:</p> + +<ul> + <li><code>let i = 0;</code> — 너의 initializer.</li> + <li><code>refused.textContent +=</code> — <code>refused.textContent</code> 의 끝까지 무언가를 연결할 라인의 시작</li> + <li><code>admitted.textContent +=</code> — <code>admitted.textContent</code> 의 끝까지 무언가를 연결할 행의 시작 부분이다.</li> +</ul> + +<p>추가 보너스 질문 — 위의 작업을 성공적으로 마친 후에는 쉼표로 구분 된 두 개의 이름 목록이 남지만 정리되지 않는다. 각 끝에 쉼표가 표시된다. 각각의 경우에 마지막 쉼표를 잘라내는 줄을 작성하는 방법을 알아 내고 마지막에 모든것을 멈추는 코드를 추가할수 있겠어? 도움이 되는 <a href="/en-US/docs/Learn/JavaScript/First_steps/Useful_string_methods">Useful string methods</a> 도움말을 읽어봐라.</p> + +<p>실수를 한 경우 "재설정"버튼을 사용하여 예제를 언제든지 재설정 할 수 있다. 정말 힘들다면 "solution보기"를 눌러 풀이를 확인할수 있다.</p> + +<div class="hidden"> +<h6 id="Active_learning_2">Active learning 2</h6> + +<pre class="brush: html notranslate"><h2>Live output</h2> +<div class="output" style="height: 100px;overflow: auto;"> + <p class="admitted">Admit: </p> + <p class="refused">Refuse: </p> +</div> + +<h2>Editable code</h2> +<p class="a11y-label">Press Esc to move focus away from the code area (Tab inserts a tab character).</p> +<textarea id="code" class="playable-code" style="height: 400px;width: 95%"> +const people = ['Chris', 'Anne', 'Colin', 'Terri', 'Phil', 'Lola', 'Sam', 'Kay', 'Bruce']; + +const admitted = document.querySelector('.admitted'); +const refused = document.querySelector('.refused'); +admitted.textContent = 'Admit: '; +refused.textContent = 'Refuse: ' + +// let i = 0; + +// refused.textContent += ; +// admitted.textContent += ; + +</textarea> + +<div class="playable-buttons"> + <input id="reset" type="button" value="Reset"> + <input id="solution" type="button" value="Show solution"> +</div> +</pre> + + + + + +<pre class="brush: css notranslate">html { + font-family: sans-serif; +} + +h2 { + font-size: 16px; +} + +.a11y-label { + margin: 0; + text-align: right; + font-size: 0.7rem; + width: 98%; +} + +body { + margin: 10px; + background: #f5f9fa; +}</pre> + + + + + + + + + +<pre class="brush: js notranslate">const textarea = document.getElementById('code'); +const reset = document.getElementById('reset'); +const solution = document.getElementById('solution'); +let code = textarea.value; +let userEntry = textarea.value; + +function updateCode() { + eval(textarea.value); +} + +reset.addEventListener('click', function() { + textarea.value = code; + userEntry = textarea.value; + solutionEntry = jsSolution; + solution.value = 'Show solution'; + updateCode(); +}); + +solution.addEventListener('click', function() { + if(solution.value === 'Show solution') { + textarea.value = solutionEntry; + solution.value = 'Hide solution'; + } else { + textarea.value = userEntry; + solution.value = 'Show solution'; + } + updateCode(); +}); + +let jsSolution = 'const people = [\'Chris\', \'Anne\', \'Colin\', \'Terri\', \'Phil\', \'Lola\', \'Sam\', \'Kay\', \'Bruce\'];\n\nconst admitted = document.querySelector(\'.admitted\');\nconst refused = document.querySelector(\'.refused\');\n\nadmitted.textContent = \'Admit: \';\nrefused.textContent = \'Refuse: \'\nlet i = 0;\n\ndo {\n if(people[i] === \'Phil\' || people[i] === \'Lola\') {\n refused.textContent += people[i] + \', \';\n } else {\n admitted.textContent += people[i] + \', \';\n }\n i++;\n} while(i < people.length);\n\nrefused.textContent = refused.textContent.slice(0,refused.textContent.length-2) + \'.\';\nadmitted.textContent = admitted.textContent.slice(0,admitted.textContent.length-2) + \'.\';'; +let solutionEntry = jsSolution; + +textarea.addEventListener('input', updateCode); +window.addEventListener('load', updateCode); + +// stop tab key tabbing out of textarea and +// make it write a tab at the caret position instead + +textarea.onkeydown = function(e){ + if (e.keyCode === 9) { + e.preventDefault(); + insertAtCaret('\t'); + } + + if (e.keyCode === 27) { + textarea.blur(); + } +}; + +function insertAtCaret(text) { + let scrollPos = textarea.scrollTop; + let caretPos = textarea.selectionStart; + + let front = (textarea.value).substring(0, caretPos); + let back = (textarea.value).substring(textarea.selectionEnd, textarea.value.length); + textarea.value = front + text + back; + caretPos = caretPos + text.length; + textarea.selectionStart = caretPos; + textarea.selectionEnd = caretPos; + textarea.focus(); + textarea.scrollTop = scrollPos; +} + +// Update the saved userCode every time the user updates the text area code + +textarea.onkeyup = function(){ + // We only want to save the state when the user code is being shown, + // not the solution, so that solution is not saved over the user code + if(solution.value === 'Show solution') { + userEntry = textarea.value; + } else { + solutionEntry = textarea.value; + } + + updateCode(); +};</pre> + + + + +</div> + +<p>{{ EmbedLiveSample('Active_learning_2', '100%', 680, "", "", "hide-codepen-jsfiddle") }}</p> + +<h2 id="어떤_loop종류를_사용하나">어떤 loop종류를 사용하나?</h2> + +<p>기본적으로 <code>for</code>, <code>while</code>, 그리고 <code>do...while</code> loops 는 상호 교환이 가능하다. 그들은 모두 동일한 문제를 해결하는 데 사용할수 있으며, 사용하는 것은 주로 개인의 취향에 달려 있다. 가장 기억하기 쉽거나 가장 직관적인 방법을 찾아라. 다시 한번 살펴보자.</p> + +<p>First <code>for</code>:</p> + +<pre class="notranslate">for (initializer; exit-condition; final-expression) { + // code to run +}</pre> + +<p><code>while</code>:</p> + +<pre class="notranslate">initializer +while (exit-condition) { + // code to run + + final-expression +}</pre> + +<p>and finally <code>do...while</code>:</p> + +<pre class="notranslate">initializer +do { + // code to run + + final-expression +} while (exit-condition)</pre> + +<p><font face="Arial, x-locale-body, sans-serif"><span style="background-color: #ffffff;">우리는 적어도 </span></font><code>for</code>를 <font face="Arial, x-locale-body, sans-serif"><span style="background-color: #ffffff;">처음에는 모든 것중에 기억하는 것이 가장 쉽기 때문에 추천한다. </span></font>— initializer, exit 조건 및 최종 표현식은 모두 괄호 안에 깔끔하게 들어가야 하므로 어디에 있는지 쉽게 알 수 있다. 너가 그것들을 놓치지 않게 잘 점검해보자.</p> + +<div class="note"> +<p><strong>Note</strong>: 고급 / 특수한 상황에서 나아가 다른 loop 유형 / 기능도 있다. loop 학습으로 더 자세히 알고 싶다면 <a href="/en-US/docs/Web/JavaScript/Guide/Loops_and_iteration">Loops and iteration guide</a> 를 읽어보자.</p> +</div> + +<h2 id="결론">결론</h2> + +<p>이 설명에서는 기본 개념과 JavaScript에서 반복되느 코드를 사용할 수 있는 여러 가지 옵션에 대해 설명했다. 이제 loop가 반복적 인 코드를 처리하는 좋은 메커니즘 인 이유를 명확히 파악하고 자신의 예제에서 사용하도록 노력해야한다!</p> + +<p>만약 이해가 되지 않는 내용이 있으면 다시 내용을 읽어보거나 <a href="/en-US/Learn#Contact_us">contact us</a> 를 통해 도움을 요청하자.</p> + +<h2 id="또한_볼것">또한 볼것</h2> + +<ul> + <li><a href="/en-US/docs/Web/JavaScript/Guide/Loops_and_iteration">Loops and iteration in detail</a></li> + <li><a href="/en-US/docs/Web/JavaScript/Reference/Statements/for">for statement reference</a></li> + <li><a href="/en-US/docs/Web/JavaScript/Reference/Statements/while">while</a> and <a href="/en-US/docs/Web/JavaScript/Reference/Statements/do...while">do...while</a> references</li> + <li><a href="/en-US/docs/Web/JavaScript/Reference/Statements/break">break</a> and <a href="/en-US/docs/Web/JavaScript/Reference/Statements/continue">continue</a> references</li> + <li> + <p class="entry-title"><a href="https://www.impressivewebs.com/javascript-for-loop/">What’s the Best Way to Write a JavaScript For Loop?</a> — some advanced loop best practices</p> + </li> +</ul> + +<p>{{PreviousMenuNext("Learn/JavaScript/Building_blocks/conditionals","Learn/JavaScript/Building_blocks/Functions", "Learn/JavaScript/Building_blocks")}}</p> + +<h2 id="In_this_module">In this module</h2> + +<ul> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/conditionals">Making decisions in your code — conditionals</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Looping_code">Looping code</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Functions">Functions — reusable blocks of code</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Build_your_own_function">Build your own function</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Return_values">Function return values</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Events">Introduction to events</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Image_gallery">Image gallery</a></li> +</ul> diff --git a/files/ko/learn/javascript/building_blocks/조건문/index.html b/files/ko/learn/javascript/building_blocks/조건문/index.html new file mode 100644 index 0000000000..858d6f9116 --- /dev/null +++ b/files/ko/learn/javascript/building_blocks/조건문/index.html @@ -0,0 +1,770 @@ +--- +title: Making decisions in your code — 조건문 +slug: Learn/JavaScript/Building_blocks/조건문 +translation_of: Learn/JavaScript/Building_blocks/conditionals +--- +<div>{{LearnSidebar}}</div> + +<div>{{NextMenu("Learn/JavaScript/Building_blocks/Looping_code", "Learn/JavaScript/Building_blocks")}}</div> + +<p class="summary">어떤 프로그래밍 언어든 코드는 의사 결정을 내리고 입력 내용에 따라 작업을 수행해야합니다. 예를 들어 게임에서 플레이어의 생명 수치가 0이면 게임이 종료됩니다. 날씨 앱에서는 아침에 해가 뜬 그림을 보여주고 밤에는 달과 별을 보여줍니다. 이 문서에서는 JavaScript에서 조건문이 작동하는 방법을 살펴 보겠습니다.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">선행 조건:</th> + <td> + <p>기본적인 컴퓨터 활용 능력, HTML, CSS, <a href="/ko/docs/Learn/JavaScript/First_steps">Javascript 첫 걸음</a></p> + </td> + </tr> + <tr> + <th scope="row">목표:</th> + <td> + <p>자바스크립트에서 조건문의 사용법을 이해합니다.</p> + </td> + </tr> + </tbody> +</table> + +<h2 id="당신은_하나의_조건을_가질_수_있습니다.">당신은 하나의 조건을 가질 수 있습니다.</h2> + +<p>사람(과 동물)은 작은 것(과자를 하나 먹을까? 두개 먹을까?)부터 큰 것(고향에 머물면서 아버지의 농장에서 일해야 할까? 아니면 천체물리학을 공부하러 미국으로 유학을 갈까?)까지 자신의 경험을 바탕으로 결정합니다.</p> + +<p>조건문은 결정해야 하는 선택(예를 들면, "과자 하나? 두 개?)부터 선택의 결과(과자를 하나 먹으면 여전히 배고플 수 있고, 두 개를 먹으면 배는 부르지만, 엄마한테 과자를 다 먹었다고 혼날 수 있다)까지 자바스크립트에서 의사 결정을 내릴 수 있습니다. </p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/13703/cookie-choice-small.png" style="display: block; margin: 0 auto;"></p> + +<h2 id="if_..._else_문">if ... else 문</h2> + +<p>자바스크립트에서 사용하는 조건문 중에서 가장 일반적인 유형을 봅시다. — the humble <code><a href="/en-US/docs/Web/JavaScript/Reference/Statements/if...else">if ... else</a></code><a href="/en-US/docs/Web/JavaScript/Reference/Statements/if...else"> statement</a>.</p> + +<h3 id="if_..._else_문법">if ... else 문법</h3> + +<p><code>if...else</code> 문법은 {{glossary("pseudocode")}} 다음과 같습니다:</p> + +<pre class="notranslate">if (condition) { + code to run if condition is true +} else { + run some other code instead +}</pre> + +<p>Here we've got:</p> + +<ol> + <li>키워드 <code>if</code> 뒤에 괄호가 옵니다.</li> + <li>시험할 조건은 괄호 안에 위치합니다. (전형적으로 "이 값이 다른 값보다 큰지", "이 값이 존재하는지") 이 조건은 마지막 모듈에서 논의했던 비교연산자(<a href="/en-US/Learn/JavaScript/First_steps/Math#Comparison_operators">comparison operators</a>)를 사용할 것이고 <code>true</code> 나 <code>false</code>를 리턴합니다.</li> + <li>내부의 중괄호 안에 코드가 있습니다. — 이것은 우리가 좋아하는 코드일 수 있고, 조건이 <code>true</code>를 반환하는 경우에만 실행됩니다.</li> + <li>키워드 <code>else</code>.</li> + <li>또 다른 중괄호 안에 더 많은 코드가 있습니다. — 이것은 우리가 좋아하는 코드 일 수 있고, 조건이 <code>true</code>가 아닌 경우에만 실행됩니다.</li> +</ol> + +<p>이 코드는 사람이 읽을 수 있습니다. — "만약 조건이 <code>true</code>면, 코드 A를 실행하고, 아니면 코드 B를 실행한다." 라고 말합니다.</p> + +<p>반드시 <code>else</code>와 두 번째 중괄호를 포함하지 않아도 된다는 것을 주목해야 합니다. — 다음은 또한 완벽한 코드입니다.:</p> + +<pre class="notranslate">if (condition) { + code to run if condition is true +} + +run some other code</pre> + +<p>하지만, 여기서 조심 해야 할 점— 위의 경우, 코드의 두 번째 블록은 조건문에 의해서 제어되지 않습니다. 그래서 조건이 <code>true</code>나 <code>false</code>를 리턴하는 것에 관계없이 항상 동작합니다. 이것이 반드시 나쁜 것은 아니지만, 원하는 대로 되지 않을 수도 있습니다. — 코드의 한 블록이나 다른 블록이 실행되거나 둘 다 실행되지 않는 것을 원할 것입니다.</p> + +<p>마지막으로, 다음과 같이 짧은 스타일로 중괄호 없이 쓰여진 <code>if...else</code>를 볼 수 있었을 것입니다.:</p> + +<pre class="notranslate">if (condition) code to run if condition is true +else run some other code instead</pre> + +<p>이것은 완벽하게 유효한 코드이지만, 사용하는 것을 추천하지 않습니다. — 중괄호를 사용하여 코드를 구분하고, 여러 줄과 들여쓰기를 사용한다면, 코드를 쉽게 읽고, 진행되는 작업을 훨씬 쉽게 처리할 수 있습니다.</p> + +<h3 id="실제_예시">실제 예시</h3> + +<p>문법을 잘 이해하기 위해서 실제 예시를 알아봅시다. 어머니나 아버지가 아이에게 집안일을 도와달라고 요청한다고 상상해 봅시다. 부모님께서 "우리 애기, 만약에 쇼핑 하고 가는 걸 도와주면, 용돈을 더 줄게! 그럼 네가 원하는 걸 살 수 있을거야"라고 말씀 하신다면, 자바스크립트에서 이것을 다음과 같이 표현할 수 있습니다.</p> + +<pre class="brush: js notranslate">var shoppingDone = false; + +if (shoppingDone === true) { + var childsAllowance = 10; +} else { + var childsAllowance = 5; +}</pre> + +<p>위 코드에는 항상 <code>false</code>를 리턴하는 <code>shoppingDone</code>변수를 결과로 얻을 것입니다. 아이에게 실망을 안겨주겠죠. 아이가 부모님과 함께 쇼핑을 간다면 우리가 부모님을 위해 <code>shoppingDone</code>변수를 <code>true</code>로 설정하는 메커니즘을 만들 수 있겠죠.</p> + +<div class="note"> +<p><strong>Note</strong>: GitHub에서 예시를 더 볼 수 있습니다. <a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/allowance-updater.html">complete version of this example on GitHub</a> (also see it <a href="http://mdn.github.io/learning-area/javascript/building-blocks/allowance-updater.html">running live</a>.)</p> +</div> + +<h3 id="else_if">else if</h3> + +<p>지난 예시에서는 두 가지 선택과 결과가 있었죠. — 하지만 우리가 두 가지보다 더 많은 선택과 결과를 원한다면?</p> + +<p>추가로 선택/결과를 <code>if...else</code>에 연결하는 방법이 있습니다. — <code>else if</code>를 사용하여. 각 추가 선택은 <code>if() { ... }</code>와 <code>else { ... }</code>사이에 추가적인 블록이 필요합니다. 간단한 날씨 예보 어플리케이션의 일부가 될 수 있는 다음의 예시를 확인하세요. </p> + +<pre class="brush: html notranslate"><label for="weather">Select the weather type today: </label> +<select id="weather"> + <option value="">--Make a choice--</option> + <option value="sunny">Sunny</option> + <option value="rainy">Rainy</option> + <option value="snowing">Snowing</option> + <option value="overcast">Overcast</option> +</select> + +<p></p></pre> + +<pre class="brush: js notranslate">var select = document.querySelector('select'); +var para = document.querySelector('p'); + +select.addEventListener('change', setWeather); + +function setWeather() { + var choice = select.value; + + if (choice === 'sunny') { + para.textContent = 'It is nice and sunny outside today. Wear shorts! Go to the beach, or the park, and get an ice cream.'; + } else if (choice === 'rainy') { + para.textContent = 'Rain is falling outside; take a rain coat and a brolly, and don\'t stay out for too long.'; + } else if (choice === 'snowing') { + para.textContent = 'The snow is coming down — it is freezing! Best to stay in with a cup of hot chocolate, or go build a snowman.'; + } else if (choice === 'overcast') { + para.textContent = 'It isn\'t raining, but the sky is grey and gloomy; it could turn any minute, so take a rain coat just in case.'; + } else { + para.textContent = ''; + } +} + +</pre> + +<p>{{ EmbedLiveSample('else_if', '100%', 100, "", "", "hide-codepen-jsfiddle") }}</p> + +<ol> + <li>여기서 우리는 HTML {{htmlelement("select")}} 엘리먼트를 사용하여 다른 날씨 선택과 간단한 문단을 만들 수 있습니다. </li> + <li>자바스크립트에서 {{htmlelement("select")}} 와 {{htmlelement("p")}} 엘리먼트를 모두 저장하고 있고, <code><select></code> 엘리먼트에 이벤트 리스너를 추가하고, 값이 변할 때 <code>setWeather()</code>함수가 동작합니다.</li> + <li>함수가 동작했을 때, 현재 <code><select></code> 에서 선택된 값을 <code>choice</code>라는 변수에 설정합니다. 그런 다음 조건문을 사용하여 <code>choice</code>값에 따라 문단 안에 다른 텍스트를 표시합니다. <code>if() {...} block</code>에서 테스트된 첫 번째를 제외하고, <code>else if() {...}</code>에서 조건은 테스트되는 방법에 유의하세요.</li> + <li><code>else {...}</code>안의 가장 마지막 선택은 기본적으로 "최후의 수단" 옵션입니다. — <code>true</code>인 조건이 없으면 코드가 실행됩니다. 이 경우 아무것도 선택되지 않으면 예를 들어, 사용자가 처음에 표시한 "Make a choice" placeholder 옵션에서 다시 선택하기로 한다면, 문단의 텍스트를 비우는 역할을 합니다.</li> +</ol> + +<div class="note"> +<p><strong>Note</strong>: You can also <a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/simple-else-if.html">find this example on GitHub</a> (<a href="http://mdn.github.io/learning-area/javascript/building-blocks/simple-else-if.html">see it running live</a> on there also.)</p> +</div> + +<h3 id="비교_연산자">비교 연산자</h3> + +<p>비교 연산자는 우리의 조건문 안에 조건을 테스트하는데 사용된다. 우리는 먼저 <a href="/en-US/Learn/JavaScript/First_steps/Math#Comparison_operators">Basic math in JavaScript — numbers and operators</a> 에서 비교 연산자를 봤습니다. </p> + +<ul> + <li><code>===</code>와 <code>!==</code> — 한 값이 다른 값과 같거나 다른지 테스트 한다.</li> + <li><code><</code> 와 <code>></code> — 한 값이 다른 값보다 작은지 큰지 테스트 한다.</li> + <li><code><=</code> 와 <code>>=</code> — 한 값이 다른 값보다 작거나 같은지, 크거나 같은지 테스트 한다</li> +</ul> + +<div class="note"> +<p><strong>Note</strong>: Review the material at the previous link if you want to refresh your memories on these.</p> +</div> + +<p>boolean(<code>true</code>/<code>false</code>)값과 몇 번이고 다시 만날 일반적인 패턴을 테스트하는 것의 특별한 언급을 하고 싶었습니다.. <code>false</code>, <code>undefined</code>, <code>null</code>, <code>0</code>, <code>NaN</code>이나 빈 문자열(<code>''</code>)이 아닌 어떤 값은 조건문이 테스트 되었을 때, <code>true</code>를 리턴합니다.. 그러므로 우리는 변수가 참인지 값이 존재하는지 간단하게 변수 이름을 사용할 수 있습니다.. 예를 들어,</p> + +<pre class="brush: js notranslate">var cheese = 'Cheddar'; + +if (cheese) { + console.log('Yay! Cheese available for making cheese on toast.'); +} else { + console.log('No cheese on toast for you today.'); +}</pre> + +<p>그리고 부모님을 위해 집안일을 하는 아이에 대한 이전 예시에서 리턴하는 것을 다음과 같이 작성할 수 있었습니다.</p> + +<pre class="brush: js notranslate">var shoppingDone = false; + +if (shoppingDone) { // don't need to explicitly specify '=== true' + var childsAllowance = 10; +} else { + var childsAllowance = 5; +}</pre> + +<h3 id="if_..._else_중첩">if ... else 중첩</h3> + +<p><code>if...else</code>문을 다른 문 앞에 넣는 것(중첩하여)은 완벽하게 가능합니다.. 예를 들어, 온도가 무엇인지에 따라 더 많은 선택의 옵션을 보여주기위해 우리의 날씨 예보 어플리케이션에서 업데이트 할 수 있습니다..</p> + +<pre class="brush: js notranslate">if (choice === 'sunny') { + if (temperature < 86) { + para.textContent = 'It is ' + temperature + ' degrees outside — nice and sunny. Let\'s go out to the beach, or the park, and get an ice cream.'; + } else if (temperature >= 86) { + para.textContent = 'It is ' + temperature + ' degrees outside — REALLY HOT! If you want to go outside, make sure to put some suncream on.'; + } +}</pre> + +<p>비록 코드가 모두 동작하더라도, 각 <code>if...else</code>문은 다른 문과 완전히 독립적으로 동작합니다..</p> + +<h3 id="논리_연산자_AND_OR_and_NOT">논리 연산자: AND, OR and NOT</h3> + +<p>만약 중첩된 <code>if...else</code>문을 작성하는 것 없이 다양한 조건을 테스트하길 원한다면 <a href="/en-US/docs/Web/JavaScript/Reference/Operators/Logical_Operators">logical operators</a> 이 당신을 도와줄 수 있습니다. 조건 내에서 사용될 때, 처음 두 가지는 다음과 같이 합니다.</p> + +<ul> + <li><code>&&</code> — AND; <code>true</code>를 리턴하는 전체 표현식을 위해 각각 <code>true</code>계산되는 둘 이상의 표현식을 함께 연결할 수 있습니다.</li> + <li><code>||</code> — OR; <code>true</code>를 리턴하는 전체 표현식을 위해 하나 이상이 <code>true</code>로 계산되는 둘 이상의 표현식을 함께 연결할 수 있습니다.</li> +</ul> + +<p>AND 예시를 위해서 앞의 예제 코드 중에서 다음과 같이 작성할 수 있습니다.</p> + +<pre class="brush: js notranslate">if (choice === 'sunny' && temperature < 86) { + para.textContent = 'It is ' + temperature + ' degrees outside — nice and sunny. Let\'s go out to the beach, or the park, and get an ice cream.'; +} else if (choice === 'sunny' && temperature >= 86) { + para.textContent = 'It is ' + temperature + ' degrees outside — REALLY HOT! If you want to go outside, make sure to put some suncream on.'; +}</pre> + +<p>위 예시에서, 첫 번째 코드 블록은 <code>choice === 'sunny'</code>와 <code>temperature < 86</code>가 <code>true</code>를 리턴한다면 실행될 것입니다.</p> + +<p>빠르게 OR 예시를 봅시다.</p> + +<pre class="brush: js notranslate">if (iceCreamVanOutside || houseStatus === 'on fire') { + console.log('You should leave the house quickly.'); +} else { + console.log('Probably should just stay in then.'); +}</pre> + +<p>논리 연산자의 마지막 유형인 <code>!</code> 연산자로 표현되는 NOT은 표현식을 무효화할 수 있습니다. 위 OR 예시와 함께 봅시다.</p> + +<pre class="brush: js notranslate">if (!(iceCreamVanOutside || houseStatus === 'on fire')) { + console.log('Probably should just stay in then.'); +} else { + console.log('You should leave the house quickly.'); +}</pre> + +<p>위 예시에서, OR 문이 <code>true</code>를 리턴한다면, NOT 연산자는 전체 표현식이 <code>false</code>를 리턴하도록 무효화할 것입니다.</p> + +<p>어떤 구조든지 당신이 원하는 만큼 많은 논리 문을 결합할 수 있습니다. 다음 예시는 두 가지 OR 문 모두 true를 리턴하면, 전체 AND문은 true를 리턴한다는 것을 의미하는 코드를 실행합니다.</p> + +<pre class="brush: js notranslate">if ((x === 5 || y > 3 || z <= 10) && (loggedIn || userName === 'Steve')) { + // run the code +}</pre> + +<p>조건 문에서 논리적 OR 연산자를 사용할 때 일반적인 실수는 값을 한번 체크하는 변수를 명시한 다음, <code>||</code> (OR) 연산로 분리하여 true를 리턴될 수 있는 변수의 리스트를 사용한다는 것입니다. 예를 들어: </p> + +<pre class="example-bad brush: js notranslate">if (x === 5 || 7 || 10 || 20) { + // run my code +}</pre> + +<p>이 경우에 <code>if(...)</code> 내부 조건은 7(또는 다른 0이 아닌 값)이 항상 true가 되므로, 항상 true를 계산할 것입니다. 조건은 "x가 5와 같거나 7이 true면, 항상 그렇다"라고 분명하게 말하고 있습니다. 이것은 논리적으로 우리가 원하는 것이 아닙니다! 이를 동작하게 하기 위해 우리는 각 OR 연산자를 완전하게 명시해야 합니다.</p> + +<pre class="brush: js notranslate">if (x === 5 || x === 7 || x === 10 ||x === 20) { + // run my code +}</pre> + +<h2 id="switch_문">switch 문</h2> + +<p><code>if...else</code> 문은 조건문 코드가 잘 동작되는 일을 하지만, 단점이 없지 않습니다. 그 문은 두 가지 선택을 가지고 있는 경우에 주로 유용합니다. 그리고 각각은 실행되기 위한 합리적인 양의 코드가 필요하고, AND/OR 조건은 복잡합니다.(e.g. 다수의 논리 연산자) 어떤 값의 선택으로 변수를 설정하거나 조건에 따라서 특정 문을 출력하는 경우 구문이 약간 번거로울 수 있습니다. 특히 많은 선택 항목이 있는 경우에 특히 그렇습니다.</p> + +<p><a href="/en-US/docs/Web/JavaScript/Reference/Statements/switch"><code>switch</code> statements</a> 은 당신의 친구입니다. 이는 입력으로 하나의 표현식/값을 받고, 값과 일치하는 하나를 찾을 때까지 여러 항목을 살펴보고 그에 맞는 코드를 실행합니다. 여기 몇몇 많은 수도코드가 있습니다.</p> + +<pre class="notranslate">switch (expression) { + case choice1: + run this code + break; + + case choice2: + run this code instead + break; + + // include as many cases as you like + + default: + actually, just run this code +}</pre> + +<p>여기에서: </p> + +<ol> + <li>뒤에 괄호가 오는 키워드 <code>switch</code>.</li> + <li>괄오 내부에는 표현식이나 값을 입력합니다.</li> + <li>표현식이나 값이 될 수 있는 선택이 따라 오는 키워드 <code>case</code>는 콜론이 뒤에 옵니다.</li> + <li><code>break</code>문은 뒤에 세미콜론이 옵니다. 이전의 선택이 표현식이나 값과 일치한다면 해당 코드 블록에서 실행을 멉추고, switch 문 아래에 있는 어떤 코드로 이동합니다.</li> + <li>원하는 많은 다른 케이스를 입력할 수 있습니다. </li> + <li>키워드 <code>default</code>는 case들과 같은 코드를 입력하고, 일치하는 항목이 없으면 실행되는 기본 옵션입니다. case와 일치하지 않고, 예외가 필요하지 않는 경우 제외할 수 있습니다.</li> +</ol> + +<div class="note"> +<p><strong>Note</strong>: default를 반드시 포함하지 않고 생략가능합니다. 다만 필요하다면 미지의 경우를 처리하기 위해 포함해야 합니다.</p> +</div> + +<h3 id="A_switch_example">A switch example</h3> + +<p>실전 예제를 해봅시다.switch문을 활용해 일기예보 애플리케이션을 작성하세요.</p> + +<pre class="brush: html notranslate"><label for="weather">Select the weather type today: </label> +<select id="weather"> + <option value="">--Make a choice--</option> + <option value="sunny">Sunny</option> + <option value="rainy">Rainy</option> + <option value="snowing">Snowing</option> + <option value="overcast">Overcast</option> +</select> + +<p></p></pre> + +<pre class="brush: js notranslate">var select = document.querySelector('select'); +var para = document.querySelector('p'); + +select.addEventListener('change', setWeather); + + +function setWeather() { + var choice = select.value; + + switch (choice) { + case 'sunny': + para.textContent = 'It is nice and sunny outside today. Wear shorts! Go to the beach, or the park, and get an ice cream.'; + break; + case 'rainy': + para.textContent = 'Rain is falling outside; take a rain coat and a brolly, and don\'t stay out for too long.'; + break; + case 'snowing': + para.textContent = 'The snow is coming down — it is freezing! Best to stay in with a cup of hot chocolate, or go build a snowman.'; + break; + case 'overcast': + para.textContent = 'It isn\'t raining, but the sky is grey and gloomy; it could turn any minute, so take a rain coat just in case.'; + break; + default: + para.textContent = ''; + } +}</pre> + +<p>{{ EmbedLiveSample('A_switch_example', '100%', 100, "", "", "hide-codepen-jsfiddle") }}</p> + +<div class="note"> +<p><strong>Note</strong>: You can also <a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/simple-switch.html">find this example on GitHub</a> (see it <a href="http://mdn.github.io/learning-area/javascript/building-blocks/simple-switch.html">running live</a> on there also.)</p> +</div> + +<h2 id="삼항연산자">삼항연산자 </h2> + +<p>다른 예제로 들어가기 전에 소개하고 싶은 마지막 구문이 있다.삼항(조건)연산자( <a href="/en-US/docs/Web/JavaScript/Reference/Operators/Conditional_Operator">ternary or conditional operator</a>)는 조건이 참이면 한 값/표현식을 반환하고 조건이 거짓이면 다른 값/표현식을 반환하는 구문이다.— 이것은 어떤 상황에 유용할 수 있으며, 참/거짓 조건을 간단히 선택할 수 있는 상황이라면 <code>if...else</code> 블록문보다 코드를 훨씬 적게 사용할수 있다. 이 pseudocode는 아래와 같다:</p> + +<pre class="notranslate">( condition ) ? run this code : run this code instead</pre> + +<p>그러면 간단한 예를 보자:</p> + +<pre class="brush: js notranslate">var greeting = ( isBirthday ) ? 'Happy birthday Mrs. Smith — we hope you have a great day!' : 'Good morning Mrs. Smith.';</pre> + +<p><code>isBirthday</code> 라는 변수명이 여기 있다— 게스트가 생일이면 '해피버스데이' 메세지를 보내고, 생일이 아니라면 일반적인 '인사' 메세지를 보내는 경우에 해당된다..</p> + +<h3 id="삼항_연산자_예제">삼항 연산자 예제</h3> + +<p>삼항연산자로 변수값을 정할 필요가 없다; 단지 좋아하는 함수나 코드를 사용하면 된다. — . 이 예제는 삼항연산자를 사용하여 사이트의 스타일링 테마를 선택할 수 있는 것을 보여준다</p> + +<pre class="brush: html notranslate"><label for="theme">Select theme: </label> +<select id="theme"> + <option value="white">White</option> + <option value="black">Black</option> +</select> + +<h1>This is my website</h1></pre> + +<pre class="brush: js notranslate">var select = document.querySelector('select'); +var html = document.querySelector('html'); +document.body.style.padding = '10px'; + +function update(bgColor, textColor) { + html.style.backgroundColor = bgColor; + html.style.color = textColor; +} + +select.onchange = function() { + ( select.value === 'black' ) ? update('black','white') : update('white','black'); +} +</pre> + +<p>{{ EmbedLiveSample('Ternary_operator_example', '100%', 300, "", "", "hide-codepen-jsfiddle") }}</p> + +<p>여기에는 black이나 white의 테마를 고르기 위한 '{{htmlelement('select')}}' 엘리먼트가 있고, 여기에 더하여 웹사이트 제목을 보여주는 '{{htmlelement('h1')}}" 엘리먼트가 있다. <code>update()</code> 함수를 덧붙이면 두 칼라를 입력 인수(parameter)로 선택할 수 있다. 웹사이트 배경 칼라가 첫 번째 칼라로 지정되고, 텍스트 칼라가 두 번째로 정해진다.</p> + +<p>끝으로, '<a href="/en-US/docs/Web/API/GlobalEventHandlers/onchange">onchange</a>' 이벤트 리스너는 삼중연산자를 포함하는 함수를 움직('run')이게 합니다. <code>select.value === 'black' </code>조건을 테스트는 하는 것으로 시작하는데, 이 조건이 참이면 <code>update()</code> 함수가 배경색은 black으로 텍스트 색은 white로 동작하게 합니다. 이와는 반대로 select theme이 white로 선택되면(조건이 거짓이면) , <code>update()</code> 함수는 배경색은 white으로 텍스트 색은 black로 동작하게 합니다.</p> + +<div class="note"> +<p><strong>Note</strong>: You can also <a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/simple-ternary.html">find this example on GitHub</a> (see it <a href="http://mdn.github.io/learning-area/javascript/building-blocks/simple-ternary.html">running live</a> on there also.)</p> +</div> + +<h2 id="Active_learning_간단한_달력_만들기">Active learning: 간단한 달력 만들기</h2> + +<p>이 예제에서는 간단한 달력 어플리케이션을 만들어 볼겁니다. 코드에는 다음과 같은 것들이 들어 있습니다.</p> + +<ul> + <li>유저가 여러 달 중 특정 달을 고를 수 있게 하는 {{htmlelement("select")}} 요소.</li> + <li><code><select></code> 메뉴에서 선택된 값이 변경 되었음을 탐지하는 <code>onchange</code> 이벤트 핸들러.</li> + <li>{{htmlelement("h1")}} 요소에서 달력을 생성하고 올바른 달을 표시하는 <code>createCalendar()</code> 함수.</li> +</ul> + +<p><code>onchange</code> 핸들러 함수내에 조건문을 작성해야 합니다. 위치는 <code>// ADD CONDITIONAL HERE</code> 주석 바로 아래입니다. 조건문은 다음을 만족해야 합니다:</p> + +<ol> + <li>선택한 달 보기(이것은 값이 변경된 후의 요소 값이 됨.) </li> + <li><code>days</code> 란 변수를 선택한 달의 일 수와 같게 하기. 다만 윤년은 무시할 수 있다.</li> +</ol> + +<p>Hints:</p> + +<ul> + <li>논리연산자 OR을 사용해 동일한 일 수인 여러 달을 하나의 조건으로 그룹화 하기.</li> + <li>가장 흔한 일 수를 기본값을 사용하기.</li> +</ul> + +<p>만약 실수를 하더라도 'Reset' 버튼으로 초기화 할 수 있습니다. 해답을 모르겠다면 "Show solution" 으로 해결방법을 확인하세요.</p> + +<div class="hidden"> +<h6 id="Playable_code">Playable code</h6> + +<pre class="brush: html notranslate"><h2>Live output</h2> +<div class="output" style="height: 500px;overflow: auto;"> + <label for="month">Select month: </label> + <select id="month"> + <option value="January">January</option> + <option value="February">February</option> + <option value="March">March</option> + <option value="April">April</option> + <option value="May">May</option> + <option value="June">June</option> + <option value="July">July</option> + <option value="August">August</option> + <option value="September">September</option> + <option value="October">October</option> + <option value="November">November</option> + <option value="December">December</option> + </select> + + <h1></h1> + + <ul></ul> +</div> + +<h2>Editable code</h2> +<p class="a11y-label">Press Esc to move focus away from the code area (Tab inserts a tab character).</p> + +<textarea id="code" class="playable-code" style="height: 400px;width: 95%"> +var select = document.querySelector('select'); +var list = document.querySelector('ul'); +var h1 = document.querySelector('h1'); + +select.onchange = function() { + var choice = select.value; + + // ADD CONDITIONAL HERE + + createCalendar(days, choice); +} + +function createCalendar(days, choice) { + list.innerHTML = ''; + h1.textContent = choice; + for (var i = 1; i <= days; i++) { + var listItem = document.createElement('li'); + listItem.textContent = i; + list.appendChild(listItem); + } +} + +createCalendar(31,'January'); +</textarea> + +<div class="playable-buttons"> + <input id="reset" type="button" value="Reset"> + <input id="solution" type="button" value="Show solution"> +</div> +</pre> + +<pre class="brush: css notranslate">.output * { + box-sizing: border-box; +} + +.output ul { + padding-left: 0; +} + +.output li { + display: block; + float: left; + width: 25%; + border: 2px solid white; + padding: 5px; + height: 40px; + background-color: #4A2DB6; + color: white; +} + +html { + font-family: sans-serif; +} + +h2 { + font-size: 16px; +} + +.a11y-label { + margin: 0; + text-align: right; + font-size: 0.7rem; + width: 98%; +} + +body { + margin: 10px; + background: #f5f9fa; +}</pre> + +<pre class="brush: js notranslate">var textarea = document.getElementById('code'); +var reset = document.getElementById('reset'); +var solution = document.getElementById('solution'); +var code = textarea.value; +var userEntry = textarea.value; + +function updateCode() { + eval(textarea.value); +} + +reset.addEventListener('click', function() { + textarea.value = code; + userEntry = textarea.value; + solutionEntry = jsSolution; + solution.value = 'Show solution'; + updateCode(); +}); + +solution.addEventListener('click', function() { + if(solution.value === 'Show solution') { + textarea.value = solutionEntry; + solution.value = 'Hide solution'; + } else { + textarea.value = userEntry; + solution.value = 'Show solution'; + } + updateCode(); +}); + +var jsSolution = 'var select = document.querySelector(\'select\');\nvar list = document.querySelector(\'ul\');\nvar h1 = document.querySelector(\'h1\');\n\nselect.onchange = function() {\n var choice = select.value;\n var days = 31;\n if(choice === \'February\') {\n days = 28;\n } else if(choice === \'April\' || choice === \'June\' || choice === \'September\'|| choice === \'November\') {\n days = 30;\n }\n\n createCalendar(days, choice);\n}\n\nfunction createCalendar(days, choice) {\n list.innerHTML = \'\';\n h1.textContent = choice;\n for(var i = 1; i <= days; i++) {\n var listItem = document.createElement(\'li\');\n listItem.textContent = i;\n list.appendChild(listItem);\n }\n }\n\ncreateCalendar(31,\'January\');'; +var solutionEntry = jsSolution; + +textarea.addEventListener('input', updateCode); +window.addEventListener('load', updateCode); + +// stop tab key tabbing out of textarea and +// make it write a tab at the caret position instead + +textarea.onkeydown = function(e){ + if (e.keyCode === 9) { + e.preventDefault(); + insertAtCaret('\t'); + } + + if (e.keyCode === 27) { + textarea.blur(); + } +}; + +function insertAtCaret(text) { + var scrollPos = textarea.scrollTop; + var caretPos = textarea.selectionStart; + + var front = (textarea.value).substring(0, caretPos); + var back = (textarea.value).substring(textarea.selectionEnd, textarea.value.length); + textarea.value = front + text + back; + caretPos = caretPos + text.length; + textarea.selectionStart = caretPos; + textarea.selectionEnd = caretPos; + textarea.focus(); + textarea.scrollTop = scrollPos; +} + +// Update the saved userCode every time the user updates the text area code + +textarea.onkeyup = function(){ + // We only want to save the state when the user code is being shown, + // not the solution, so that solution is not saved over the user code + if(solution.value === 'Show solution') { + userEntry = textarea.value; + } else { + solutionEntry = textarea.value; + } + + updateCode(); +};</pre> +</div> + +<p>{{ EmbedLiveSample('Playable_code', '100%', 1110, "", "", "hide-codepen-jsfiddle") }}</p> + +<h2 id="Active_learning_색깔_고르기">Active learning: 색깔 고르기</h2> + +<p>In this example you are going to take the ternary operator example we saw earlier and convert the ternary operator into a switch statement that will allow us to apply more choices to the simple website. Look at the {{htmlelement("select")}} — this time you'll see that it has not two theme options, but five. You need to add a switch statement just underneath the <code>// ADD SWITCH STATEMENT</code> comment:</p> + +<ul> + <li>It should accept the <code>choice</code> variable as its input expression.</li> + <li>For each case, the choice should equal one of the possible values that can be selected, i.e. white, black, purple, yellow, or psychedelic.</li> + <li>For each case, the <code>update()</code> function should be run, and be passed two color values, the first one for the background color, and the second one for the text color. Remember that color values are strings, so need to be wrapped in quotes.</li> +</ul> + +<p>If you make a mistake, you can always reset the example with the "Reset" button. If you get really stuck, press "Show solution" to see a solution.</p> + +<div class="hidden"> +<h6 id="Playable_code_2">Playable code 2</h6> + +<pre class="brush: html notranslate"><h2>Live output</h2> +<div class="output" style="height: 300px;"> + <label for="theme">Select theme: </label> + <select id="theme"> + <option value="white">White</option> + <option value="black">Black</option> + <option value="purple">Purple</option> + <option value="yellow">Yellow</option> + <option value="psychedelic">Psychedelic</option> + </select> + + <h1>This is my website</h1> +</div> + +<h2>Editable code</h2> +<p class="a11y-label">Press Esc to move focus away from the code area (Tab inserts a tab character).</p> + +<textarea id="code" class="playable-code" style="height: 450px;width: 95%"> +var select = document.querySelector('select'); +var html = document.querySelector('.output'); + +select.onchange = function() { + var choice = select.value; + + // ADD SWITCH STATEMENT +} + +function update(bgColor, textColor) { + html.style.backgroundColor = bgColor; + html.style.color = textColor; +}</textarea> + +<div class="playable-buttons"> + <input id="reset" type="button" value="Reset"> + <input id="solution" type="button" value="Show solution"> +</div> +</pre> + +<pre class="brush: css notranslate">html { + font-family: sans-serif; +} + +h2 { + font-size: 16px; +} + +.a11y-label { + margin: 0; + text-align: right; + font-size: 0.7rem; + width: 98%; +} + +body { + margin: 10px; + background: #f5f9fa; +}</pre> + +<pre class="brush: js notranslate">var textarea = document.getElementById('code'); +var reset = document.getElementById('reset'); +var solution = document.getElementById('solution'); +var code = textarea.value; +var userEntry = textarea.value; + +function updateCode() { + eval(textarea.value); +} + +reset.addEventListener('click', function() { + textarea.value = code; + userEntry = textarea.value; + solutionEntry = jsSolution; + solution.value = 'Show solution'; + updateCode(); +}); + +solution.addEventListener('click', function() { + if(solution.value === 'Show solution') { + textarea.value = solutionEntry; + solution.value = 'Hide solution'; + } else { + textarea.value = userEntry; + solution.value = 'Show solution'; + } + updateCode(); +}); + +var jsSolution = 'var select = document.querySelector(\'select\');\nvar html = document.querySelector(\'.output\');\n\nselect.onchange = function() {\n var choice = select.value;\n\n switch(choice) {\n case \'black\':\n update(\'black\',\'white\');\n break;\n case \'white\':\n update(\'white\',\'black\');\n break;\n case \'purple\':\n update(\'purple\',\'white\');\n break;\n case \'yellow\':\n update(\'yellow\',\'darkgray\');\n break;\n case \'psychedelic\':\n update(\'lime\',\'purple\');\n break;\n }\n}\n\nfunction update(bgColor, textColor) {\n html.style.backgroundColor = bgColor;\n html.style.color = textColor;\n}'; +var solutionEntry = jsSolution; + +textarea.addEventListener('input', updateCode); +window.addEventListener('load', updateCode); + +// stop tab key tabbing out of textarea and +// make it write a tab at the caret position instead + +textarea.onkeydown = function(e){ + if (e.keyCode === 9) { + e.preventDefault(); + insertAtCaret('\t'); + } + + if (e.keyCode === 27) { + textarea.blur(); + } +}; + +function insertAtCaret(text) { + var scrollPos = textarea.scrollTop; + var caretPos = textarea.selectionStart; + + var front = (textarea.value).substring(0, caretPos); + var back = (textarea.value).substring(textarea.selectionEnd, textarea.value.length); + textarea.value = front + text + back; + caretPos = caretPos + text.length; + textarea.selectionStart = caretPos; + textarea.selectionEnd = caretPos; + textarea.focus(); + textarea.scrollTop = scrollPos; +} + +// Update the saved userCode every time the user updates the text area code + +textarea.onkeyup = function(){ + // We only want to save the state when the user code is being shown, + // not the solution, so that solution is not saved over the user code + if(solution.value === 'Show solution') { + userEntry = textarea.value; + } else { + solutionEntry = textarea.value; + } + + updateCode(); +};</pre> +</div> + +<p>{{ EmbedLiveSample('Playable_code_2', '100%', 950, "", "", "hide-codepen-jsfiddle") }}</p> + +<h2 id="Conclusion">Conclusion</h2> + +<p>And that's all you really need to know about conditional structures in JavaScript right now! I'm sure you'll have understood these concepts and worked through the examples with ease; if there is anything you didn't understand, feel free to read through the article again, or <a href="/en-US/Learn#Contact_us">contact us</a> to ask for help.</p> + +<h2 id="See_also">See also</h2> + +<ul> + <li><a href="/en-US/Learn/JavaScript/First_steps/Math#Comparison_operators">Comparison operators</a></li> + <li><a href="/en-US/docs/Web/JavaScript/Guide/Control_flow_and_error_handling#Conditional_statements">Conditional statements in detail</a></li> + <li><a href="/en-US/docs/Web/JavaScript/Reference/Statements/if...else">if...else reference</a></li> + <li><a href="/en-US/docs/Web/JavaScript/Reference/Operators/Conditional_Operator">Conditional (ternary) operator reference</a></li> +</ul> + +<p>{{NextMenu("Learn/JavaScript/Building_blocks/Looping_code", "Learn/JavaScript/Building_blocks")}}</p> + +<h2 id="In_this_module">In this module</h2> + +<ul> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/conditionals">Making decisions in your code — conditionals</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Looping_code">Looping code</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Functions">Functions — reusable blocks of code</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Build_your_own_function">Build your own function</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Return_values">Function return values</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Events">Introduction to events</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Image_gallery">Image gallery</a></li> +</ul> diff --git a/files/ko/learn/javascript/client-side_web_apis/client-side_storage/index.html b/files/ko/learn/javascript/client-side_web_apis/client-side_storage/index.html new file mode 100644 index 0000000000..e2ac144050 --- /dev/null +++ b/files/ko/learn/javascript/client-side_web_apis/client-side_storage/index.html @@ -0,0 +1,780 @@ +--- +title: Client-side storage +slug: Learn/JavaScript/Client-side_web_APIs/Client-side_storage +translation_of: Learn/JavaScript/Client-side_web_APIs/Client-side_storage +--- +<p>{{LearnSidebar}}</p> + +<div>{{PreviousMenu("Learn/JavaScript/Client-side_web_APIs/Video_and_audio_APIs", "Learn/JavaScript/Client-side_web_APIs")}}</div> + +<div></div> + +<p class="summary">현대 웹 브라우저들은 (사용자의 허락 하에) 사용자 컴퓨터에 웹사이트 정보를 저장할 수 있는 다양한 방법을 제공합니다. 그리고 필요한때 그 정보들을 읽어오죠. 이는 당신이 장기간 데이터를 보관할 수 있게 해주고 사이트와 웹문서를 당신이 지정한 설정에 따라 오프라인 상태에서도 사용할수 있게 해줍니다. 이 문서는 이러한 것들이 어떻게 동작하는지에 대한 기본지식들을 설명합니다. </p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Prerequisites:</th> + <td>JavaScript basics (see <a href="/en-US/docs/Learn/JavaScript/First_steps">first steps</a>, <a href="/en-US/docs/Learn/JavaScript/Building_blocks">building blocks</a>, <a href="/en-US/docs/Learn/JavaScript/Objects">JavaScript objects</a>), the <a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Introduction">basics of Client-side APIs</a></td> + </tr> + <tr> + <th scope="row">Objective:</th> + <td>To learn how to use client-side storage APIs to store application data.</td> + </tr> + </tbody> +</table> + +<h2 id="Client-side_storage">Client-side storage?</h2> + +<p>우리는 다른 MDN 학습영역에서 <a href="/en-US/docs/Learn/Server-side/First_steps/Client-Server_overview#Static_sites">정적인 사이트</a>와 <a href="/en-US/docs/Learn/Server-side/First_steps/Client-Server_overview#Dynamic_sites">동적인 사이트</a>에 대해 이미 설명하였습니다. 현대의 대부분의 웹사이트들은 어떤 데이터베이스(서버의 저장소)를 이용하여 서버에 데이터를 저장하고, 필요한 데이터를 찾아오기 위해 <a href="/en-US/docs/Learn/Server-side">서버-사이드</a> 코드를 돌리고, 정적인 페이지 템플릿에 데이터를 삽입하고, HTML 결과물을 사용자의 브라우저에 표시될 수 있게 제공합니다 - 즉 동적입니다.</p> + +<p>클라이언트-사이드 저장소는 비슷한 원리로 작동하지만, 다르게 쓰입니다. 이것은 개발자가 클라이언트 측(사용자의 컴퓨터 등)에 데이터를 저장할 수 있고 필요할 때 가져올 수 있게 해주는 자바스크립트 API로 구성되어 있습니다. 이것의 다양한 용도는 다음과 같습니다.</p> + +<ul> + <li>웹사이트에 대한 선호를 개인화하기(사용자가 선택한 커스텀 위젯, 배색, 폰트 크기로 보여주기)</li> + <li>이전 활동 기록 저장하기(이전 세션에 담았던 장바구니 목록 저장하기, 로그인 유지하기)</li> + <li>사이트 다운로드가 빨라지고(잠재적으로 비용이 적게 들어가고) 네트워크 연결 없이도 사용할 수 있게끔 데이터를 로컬에 저장하기</li> + <li>오프라인 상태에서 사용할 수 있도록 웹 어플리케이션 생성 문서를 로컬에 저장하기</li> +</ul> + +<p>클라이언트-사이드 저장소와 서버-사이드 저장소는 대개 함께 사용됩니다. 예를 들면, 당신은 (아마도 웹 게임이나 음악 재생 어플리케이션에서 사용할)음악 파일 여러 개를 다운받아 클라이언트-사이드 데이터베이스에 저장하고 필요할 때 재생할 수 있습니다. 사용자는 음악 파일을 한번만 다운받고, 재방문 시에는 데이터베이스에서 가져오기만 하면 됩니다.</p> + +<div class="note"> +<p><strong>Note</strong>: There are limits to the amount of data you can store using client-side storage APIs (possibly both per individual API and cumulatively); the exact limit varies depending on the browser and possibly based on user settings. See <a href="/en-US/docs/Web/API/IndexedDB_API/Browser_storage_limits_and_eviction_criteria">Browser storage limits and eviction criteria</a> for more information.</p> +</div> + +<h3 id="Old_fashioned_cookies">Old fashioned: cookies</h3> + +<p>클라이언트-사이드 저장소에 대한 개념은 오래전부터 있었습니다. 웹의 태동기 시절, 웹 사이트들은 사용자 경험(UX)을 개인화하는 정보들을 저장하기 위해 <a href="/en-US/docs/Web/HTTP/Cookies">cookies</a>를 사용했습니다. 그것들이 웹에서 보편적으로 사용된 클라이언트-사이드 저장소의 제일 오래된 형태입니다.</p> + +<p>오늘날에는 클라이언트 사이드에 데이터를 저장하는 더 쉬운 방법이 있지만, 이 문서에서 cookies를 사용하는 법을 가르쳐 주지는 않습니다. 그러나, 이것이 현대의 웹에서 cookies가 완벽하게 쓸모없다는 것을 뜻하지는 않습니다. cookies는 세션 ID나 access token 같은 사용자 상태와 개인화에 관련된 정보를 저장하는데 여전히 보편적으로 쓰입니다. cookies에 대한 더 자세한 정보는 우리의 <a href="/en-US/docs/Web/HTTP/Cookies">Using HTTP cookies</a> 문서를 참고하세요.</p> + +<h3 id="New_school_Web_Storage_and_IndexedDB">New school: Web Storage and IndexedDB</h3> + +<p>현대의 브라우저들은 클라이언트-사이드 데이터를 저장하는 데에 cookies보다 더 쉽고 더 효율적인 API들을 제공합니다.</p> + +<ul> + <li><a href="/en-US/docs/Web/API/Web_Storage_API">Web Storage API</a>는 이름과 대응되는 값으로 이루어진 더 작은 데이터를 저장하고 가져오는 매우 간단한 기능을 제공합니다. 이것은 사용자 이름과 로그인 여부, 스크린 배경색을 어떤 색으로 할지 등등 같은 간단한 데이터를 저장할 필요가 있을 때 유용합니다. </li> + <li><a href="/en-US/docs/Web/API/IndexedDB_API">IndexedDB API</a>는 복잡한 데이터를 저장할 수 있는 완벽한 데이터베이스를 브라우저에서 제공할 수 있게 해줍니다. 이것은 소비자 기록의 복잡한 데이터셋부터 오디오나 비디오 파일같은 더욱 복잡한 데이터까지 저장하는 데에 쓰일 수 있습니다.</li> +</ul> + +<p>밑에서 이런 API들을 더 배울 수 있습니다.</p> + +<h3 id="The_future_Cache_API">The future: Cache API</h3> + +<p>몇몇 현대적인 브라우저들은 새로운 {{domxref("Cache")}} API를 제공합니다. 이 API는 특정 requests에 대한 HTTP responses를 저장하기 위해 디자인되었고, 웹사이트가 차후에 네트워크 연결 없이도 사용될 수 있도록 사이트 정보를 저장하는 등의 일을 하는데 유용합니다. Cache는 일반적으로 <a href="/en-US/docs/Web/API/Service_Worker_API">Service Worker API</a>와 함께 사용되지만, 꼭 그럴 필요는 없습니다.</p> + +<p>Cache와 Service Workers의 사용은 심화 주제이므로 이 문서에서는 아래의 {{anch("Offline asset storage")}} 섹션에서 보여주는 것 이상으로 깊게 다루지는 않을 것입니다.</p> + +<h2 id="Storing_simple_data_—_web_storage">Storing simple data — web storage</h2> + +<p>The <a href="/en-US/docs/Web/API/Web_Storage_API">Web Storage API</a> is very easy to use — you store simple name/value pairs of data (limited to strings, numbers, etc.) and retrieve these values when needed.</p> + +<h3 id="Basic_syntax">Basic syntax</h3> + +<p>Let's show you how:</p> + +<ol> + <li> + <p>First, go to our <a href="https://mdn.github.io/learning-area/javascript/apis/client-side-storage/web-storage/index.html">web storage blank template</a> on GitHub (open this in a new tab).</p> + </li> + <li> + <p>Open the JavaScript console of your browser's developer tools.</p> + </li> + <li> + <p>All of your web storage data is contained within two object-like structures inside the browser: {{domxref("Window.sessionStorage", "sessionStorage")}} and {{domxref("Window.localStorage", "localStorage")}}. The first one persists data for as long as the browser is open (the data is lost when the browser is closed) and the second one persists data even after the browser is closed and then opened again. We'll use the second one in this article as it is generally more useful.</p> + + <p>The {{domxref("Storage.setItem()")}} method allows you to save a data item in storage — it takes two parameters: the name of the item, and its value. Try typing this into your JavaScript console (change the value to your own name, if you wish!):</p> + + <pre class="brush: js notranslate">localStorage.setItem('name','Chris');</pre> + </li> + <li> + <p>The {{domxref("Storage.getItem()")}} method takes one parameter — the name of a data item you want to retrieve — and returns the item's value. Now type these lines into your JavaScript console:</p> + + <pre class="brush: js notranslate">var myName = localStorage.getItem('name'); +myName</pre> + + <p>Upon typing in the second line, you should see that the <code>myName</code> variable now contains the value of the <code>name</code> data item.</p> + </li> + <li> + <p>The {{domxref("Storage.removeItem()")}} method takes one parameter — the name of a data item you want to remove — and removes that item out of web storage. Type the following lines into your JavaScript console:</p> + + <pre class="brush: js notranslate">localStorage.removeItem('name'); +var myName = localStorage.getItem('name'); +myName</pre> + + <p>The third line should now return <code>null</code> — the <code>name</code> item no longer exists in the web storage.</p> + </li> +</ol> + +<h3 id="The_data_persists!">The data persists!</h3> + +<p>One key feature of web storage is that the data persists between page loads (and even when the browser is shut down, in the case of <code>localStorage</code>). Let's look at this in action.</p> + +<ol> + <li> + <p>Open our web storage blank template again, but this time in a different browser to the one you've got this tutorial open in! This will make it easier to deal with.</p> + </li> + <li> + <p>Type these lines into the browser's JavaScript console:</p> + + <pre class="brush: js notranslate">localStorage.setItem('name','Chris'); +var myName = localStorage.getItem('name'); +myName</pre> + + <p>You should see the name item returned.</p> + </li> + <li> + <p>Now close down the browser and open it up again.</p> + </li> + <li> + <p>Enter the following lines again:</p> + + <pre class="brush: js notranslate">var myName = localStorage.getItem('name'); +myName</pre> + + <p>You should see that the value is still available, even though the browser has been closed and then opened again.</p> + </li> +</ol> + +<h3 id="Separate_storage_for_each_domain">Separate storage for each domain</h3> + +<p>There is a separate data store for each domain (each separate web address loaded in the browser). You will see that if you load two websites (say google.com and amazon.com) and try storing an item on one website, it won't be available to the other website.</p> + +<p>This makes sense — you can imagine the security issues that would arise if websites could see each other's data!</p> + +<h3 id="A_more_involved_example">A more involved example</h3> + +<p>Let's apply this new-found knowledge by writing a simple working example to give you an idea of how web storage can be used. Our example will allow you enter a name, after which the page will update to give you a personalized greeting. This state will also persist across page/browser reloads, because the name is stored in web storage.</p> + +<p>You can find the example HTML at <a href="https://github.com/mdn/learning-area/blob/master/javascript/apis/client-side-storage/web-storage/personal-greeting.html">personal-greeting.html</a> — this contains a simple website with a header, content, and footer, and a form for entering your name.</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/15735/web-storage-demo.png" style="display: block; margin: 0 auto;"></p> + +<p>Let's build up the example, so you can understand how it works.</p> + +<ol> + <li> + <p>First, make a local copy of our <a href="https://github.com/mdn/learning-area/blob/master/javascript/apis/client-side-storage/web-storage/personal-greeting.html">personal-greeting.html</a> file in a new directory on your computer.</p> + </li> + <li> + <p>Next, note how our HTML references a JavaScript file called <code>index.js</code> (see line 40). We need to create this and write our JavaScript code into it. Create an <code>index.js</code> file in the same directory as your HTML file. </p> + </li> + <li> + <p>We'll start off by creating references to all the HTML features we need to manipulate in this example — we'll create them all as constants, as these references do not need to change in the lifecycle of the app. Add the following lines to your JavaScript file:</p> + + <pre class="brush: js notranslate">// create needed constants +const rememberDiv = document.querySelector('.remember'); +const forgetDiv = document.querySelector('.forget'); +const form = document.querySelector('form'); +const nameInput = document.querySelector('#entername'); +const submitBtn = document.querySelector('#submitname'); +const forgetBtn = document.querySelector('#forgetname'); + +const h1 = document.querySelector('h1'); +const personalGreeting = document.querySelector('.personal-greeting');</pre> + </li> + <li> + <p>Next up, we need to include a small event listener to stop the form from actually submitting itself when the submit button is pressed, as this is not the behavior we want. Add this snippet below your previous code:</p> + + <pre class="brush: js notranslate">// Stop the form from submitting when a button is pressed +form.addEventListener('submit', function(e) { + e.preventDefault(); +});</pre> + </li> + <li> + <p>Now we need to add an event listener, the handler function of which will run when the "Say hello" button is clicked. The comments explain in detail what each bit does, but in essence here we are taking the name the user has entered into the text input box and saving it in web storage using <code>setItem()</code>, then running a function called <code>nameDisplayCheck()</code> that will handle updating the actual website text. Add this to the bottom of your code:</p> + + <pre class="brush: js notranslate">// run function when the 'Say hello' button is clicked +submitBtn.addEventListener('click', function() { + // store the entered name in web storage + localStorage.setItem('name', nameInput.value); + // run nameDisplayCheck() to sort out displaying the + // personalized greetings and updating the form display + nameDisplayCheck(); +});</pre> + </li> + <li> + <p>At this point we also need an event handler to run a function when the "Forget" button is clicked — this is only displayed after the "Say hello" button has been clicked (the two form states toggle back and forth). In this function we remove the <code>name</code> item from web storage using <code>removeItem()</code>, then again run <code>nameDisplayCheck()</code> to update the display. Add this to the bottom:</p> + + <pre class="brush: js notranslate">// run function when the 'Forget' button is clicked +forgetBtn.addEventListener('click', function() { + // Remove the stored name from web storage + localStorage.removeItem('name'); + // run nameDisplayCheck() to sort out displaying the + // generic greeting again and updating the form display + nameDisplayCheck(); +});</pre> + </li> + <li> + <p>It is now time to define the <code>nameDisplayCheck()</code> function itself. Here we check whether the name item has been stored in web storage by using <code>localStorage.getItem('name')</code> as a conditional test. If it has been stored, this call will evaluate to <code>true</code>; if not, it will be <code>false</code>. If it is <code>true</code>, we display a personalized greeting, display the "forget" part of the form, and hide the "Say hello" part of the form. If it is <code>false</code>, we display a generic greeting and do the opposite. Again, put the following code at the bottom:</p> + + <pre class="brush: js notranslate">// define the nameDisplayCheck() function +function nameDisplayCheck() { + // check whether the 'name' data item is stored in web Storage + if(localStorage.getItem('name')) { + // If it is, display personalized greeting + let name = localStorage.getItem('name'); + h1.textContent = 'Welcome, ' + name; + personalGreeting.textContent = 'Welcome to our website, ' + name + '! We hope you have fun while you are here.'; + // hide the 'remember' part of the form and show the 'forget' part + forgetDiv.style.display = 'block'; + rememberDiv.style.display = 'none'; + } else { + // if not, display generic greeting + h1.textContent = 'Welcome to our website '; + personalGreeting.textContent = 'Welcome to our website. We hope you have fun while you are here.'; + // hide the 'forget' part of the form and show the 'remember' part + forgetDiv.style.display = 'none'; + rememberDiv.style.display = 'block'; + } +}</pre> + </li> + <li> + <p>Last but not least, we need to run the <code>nameDisplayCheck()</code> function every time the page is loaded. If we don't do this, then the personalized greeting will not persist across page reloads. Add the following to the bottom of your code:</p> + + <pre class="brush: js notranslate">document.body.onload = nameDisplayCheck;</pre> + </li> +</ol> + +<p>Your example is finished — well done! All that remains now is to save your code and test your HTML page in a browser. You can see our <a href="https://mdn.github.io/learning-area/javascript/apis/client-side-storage/web-storage/personal-greeting.html">finished version running live here</a>.</p> + +<div class="note"> +<p><strong>Note</strong>: There is another, slightly more complex example to explore at <a href="/en-US/docs/Web/API/Web_Storage_API/Using_the_Web_Storage_API">Using the Web Storage API</a>.</p> +</div> + +<div class="note"> +<p><strong>Note</strong>: In the line <code><script src="index.js" defer></script></code> of the source for our finished version, the <code>defer</code> attribute specifies that the contents of the {{htmlelement("script")}} element will not execute until the page has finished loading.</p> +</div> + +<h2 id="Storing_complex_data_—_IndexedDB">Storing complex data — IndexedDB</h2> + +<p>The <a href="/en-US/docs/Web/API/IndexedDB_API">IndexedDB API</a> (sometimes abbreviated IDB) is a complete database system available in the browser in which you can store complex related data, the types of which aren't limited to simple values like strings or numbers. You can store videos, images, and pretty much anything else in an IndexedDB instance.</p> + +<p>However, this does come at a cost: IndexedDB is much more complex to use than the Web Storage API. In this section, we'll really only scratch the surface of what it is capable of, but we will give you enough to get started.</p> + +<h3 id="Working_through_a_note_storage_example">Working through a note storage example</h3> + +<p>Here we'll run you through an example that allows you to store notes in your browser and view and delete them whenever you like, getting you to build it up for yourself and explaining the most fundamental parts of IDB as we go along.</p> + +<p>The app looks something like this:</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/15744/idb-demo.png" style="border-style: solid; border-width: 1px; display: block; margin: 0px auto;"></p> + +<p>Each note has a title and some body text, each individually editable. The JavaScript code we'll go through below has detailed comments to help you understand what's going on.</p> + +<h3 id="Getting_started">Getting started</h3> + +<ol> + <li>First of all, make local copies of our <code><a href="https://github.com/mdn/learning-area/blob/master/javascript/apis/client-side-storage/indexeddb/notes/index.html">index.html</a></code>, <code><a href="https://github.com/mdn/learning-area/blob/master/javascript/apis/client-side-storage/indexeddb/notes/style.css">style.css</a></code>, and <code><a href="https://github.com/mdn/learning-area/blob/master/javascript/apis/client-side-storage/indexeddb/notes/index-start.js">index-start.js</a></code> files into a new directory on your local machine.</li> + <li>Have a look at the files. You'll see that the HTML is pretty simple: a web site with a header and footer, as well as a main content area that contains a place to display notes, and a form for entering new notes into the database. The CSS provides some simple styling to make it clearer what is going on. The JavaScript file contains five declared constants containing references to the {{htmlelement("ul")}} element the notes will be displayed in, the title and body {{htmlelement("input")}} elements, the {{htmlelement("form")}} itself, and the {{htmlelement("button")}}.</li> + <li>Rename your JavaScript file to <code>index.js</code>. You are now ready to start adding code to it.</li> +</ol> + +<h3 id="Database_initial_set_up">Database initial set up</h3> + +<p>Now let's look at what we have to do in the first place, to actually set up a database.</p> + +<ol> + <li> + <p>Below the constant declarations, add the following lines:</p> + + <pre class="brush: js notranslate">// Create an instance of a db object for us to store the open database in +let db;</pre> + + <p>Here we are declaring a variable called <code>db</code> — this will later be used to store an object representing our database. We will use this in a few places, so we've declared it globally here to make things easier.</p> + </li> + <li> + <p>Next, add the following to the bottom of your code:</p> + + <pre class="brush: js notranslate">window.onload = function() { + +};</pre> + + <p>We will write all of our subsequent code inside this <code>window.onload</code> event handler function, called when the window's {{event("load")}} event fires, to make sure we don't try to use IndexedDB functionality before the app has completely finished loading (it could fail if we don't).</p> + </li> + <li> + <p>Inside the <code>window.onload</code> handler, add the following:</p> + + <pre class="brush: js notranslate">// Open our database; it is created if it doesn't already exist +// (see onupgradeneeded below) +let request = window.indexedDB.open('notes_db', 1);</pre> + + <p>This line creates a <code>request</code> to open version <code>1</code> of a database called <code>notes_db</code>. If this doesn't already exist, it will be created for you by subsequent code. You will see this request pattern used very often throughout IndexedDB. Database operations take time. You don't want to hang the browser while you wait for the results, so database operations are {{Glossary("asynchronous")}}, meaning that instead of happening immediately, they will happen at some point in the future, and you get notified when they're done.</p> + + <p>To handle this in IndexedDB, you create a request object (which can be called anything you like — we called it <code>request</code> so it is obvious what it is for). You then use event handlers to run code when the request completes, fails, etc., which you'll see in use below.</p> + + <div class="note"> + <p><strong>Note</strong>: The version number is important. If you want to upgrade your database (for example, by changing the table structure), you have to run your code again with an increased version number, different schema specified inside the <code>onupgradeneeded</code> handler (see below), etc. We won't cover upgrading databases in this simple tutorial.</p> + </div> + </li> + <li> + <p>Now add the following event handlers just below your previous addition — again inside the <code>window.onload</code> handler:</p> + + <pre class="brush: js notranslate">// onerror handler signifies that the database didn't open successfully +request.onerror = function() { + console.log('Database failed to open'); +}; + +// onsuccess handler signifies that the database opened successfully +request.onsuccess = function() { + console.log('Database opened successfully'); + + // Store the opened database object in the db variable. This is used a lot below + db = request.result; + + // Run the displayData() function to display the notes already in the IDB + displayData(); +};</pre> + + <p>The {{domxref("IDBRequest.onerror", "request.onerror")}} handler will run if the system comes back saying that the request failed. This allows you to respond to this problem. In our simple example, we just print a message to the JavaScript console.</p> + + <p>The {{domxref("IDBRequest.onsuccess", "request.onsuccess")}} handler on the other hand will run if the request returns successfully, meaning the database was successfully opened. If this is the case, an object representing the opened database becomes available in the {{domxref("IDBRequest.result", "request.result")}} property, allowing us to manipulate the database. We store this in the <code>db</code> variable we created earlier for later use. We also run a custom function called <code>displayData()</code>, which displays the data in the database inside the {{HTMLElement("ul")}}. We run it now so that the notes already in the database are displayed as soon as the page loads. You'll see this defined later on.</p> + </li> + <li> + <p>Finally for this section, we'll add probably the most important event handler for setting up the database: {{domxref("IDBOpenDBRequest.onupgradeneeded", "request.onupdateneeded")}}. This handler runs if the database has not already been set up, or if the database is opened with a bigger version number than the existing stored database (when performing an upgrade). Add the following code, below your previous handler:</p> + + <pre class="brush: js notranslate">// Setup the database tables if this has not already been done +request.onupgradeneeded = function(e) { + // Grab a reference to the opened database + let db = e.target.result; + + // Create an objectStore to store our notes in (basically like a single table) + // including a auto-incrementing key + let objectStore = db.createObjectStore('notes_os', { keyPath: 'id', autoIncrement:true }); + + // Define what data items the objectStore will contain + objectStore.createIndex('title', 'title', { unique: false }); + objectStore.createIndex('body', 'body', { unique: false }); + + console.log('Database setup complete'); +};</pre> + + <p>This is where we define the schema (structure) of our database; that is, the set of columns (or fields) it contains. Here we first grab a reference to the existing database from <code>e.target.result</code> (the event target's <code>result</code> property), which is the <code>request</code> object. This is equivalent to the line <code>db = request.result;</code> inside the <code>onsuccess</code> handler, but we need to do this separately here because the <code>onupgradeneeded</code> handler (if needed) will run before the <code>onsuccess</code> handler, meaning that the <code>db</code> value wouldn't be available if we didn't do this.</p> + + <p>We then use {{domxref("IDBDatabase.createObjectStore()")}} to create a new object store inside our opened database called <code>notes_os</code>. This is equivalent to a single table in a conventional database system. We've given it the name notes, and also specified an <code>autoIncrement</code> key field called <code>id</code> — in each new record this will automatically be given an incremented value — the developer doesn't need to set this explicitly. Being the key, the <code>id</code> field will be used to uniquely identify records, such as when deleting or displaying a record.</p> + + <p>We also create two other indexes (fields) using the {{domxref("IDBObjectStore.createIndex()")}} method: <code>title</code> (which will contain a title for each note), and <code>body</code> (which will contain the body text of the note).</p> + </li> +</ol> + +<p>So with this simple database schema set up, when we start adding records to the database; each one will be represented as an object along these lines:</p> + +<pre class="brush: js notranslate"><span class="message-body-wrapper"><span class="message-flex-body"><span class="devtools-monospace message-body"><span class="objectBox objectBox-object"><span class="objectLeftBrace">{ + </span><span class="nodeName">title</span><span class="objectEqual">: </span><span class="objectBox objectBox-string">"Buy milk"</span>, + <span class="nodeName">body</span><span class="objectEqual">: </span><span class="objectBox objectBox-string">"Need both cows milk and soya."</span>, + <span class="nodeName">id</span><span class="objectEqual">: </span><span class="objectBox objectBox-number">8</span></span></span></span></span><span class="message-body-wrapper"><span class="message-flex-body"><span class="devtools-monospace message-body"><span class="objectBox objectBox-object"><span class="objectRightBrace"> +}</span></span></span></span></span></pre> + +<h3 id="Adding_data_to_the_database">Adding data to the database</h3> + +<p>Now let's look at how we can add records to the database. This will be done using the form on our page.</p> + +<p>Below your previous event handler (but still inside the <code>window.onload</code> handler), add the following line, which sets up an <code>onsubmit</code> handler that runs a function called <code>addData()</code> when the form is submitted (when the submit {{htmlelement("button")}} is pressed leading to a successful form submission):</p> + +<pre class="brush: js notranslate">// Create an onsubmit handler so that when the form is submitted the addData() function is run +form.onsubmit = addData;</pre> + +<p>Now let's define the <code>addData()</code> function. Add this below your previous line:</p> + +<pre class="brush: js notranslate">// Define the addData() function +function addData(e) { + // prevent default - we don't want the form to submit in the conventional way + e.preventDefault(); + + // grab the values entered into the form fields and store them in an object ready for being inserted into the DB + let newItem = { title: titleInput.value, body: bodyInput.value }; + + // open a read/write db transaction, ready for adding the data + let transaction = db.transaction(['notes_os'], 'readwrite'); + + // call an object store that's already been added to the database + let objectStore = transaction.objectStore('notes_os'); + + // Make a request to add our newItem object to the object store + var request = objectStore.add(newItem); + request.onsuccess = function() { + // Clear the form, ready for adding the next entry + titleInput.value = ''; + bodyInput.value = ''; + }; + + // Report on the success of the transaction completing, when everything is done + transaction.oncomplete = function() { + console.log('Transaction completed: database modification finished.'); + + // update the display of data to show the newly added item, by running displayData() again. + displayData(); + }; + + transaction.onerror = function() { + console.log('Transaction not opened due to error'); + }; +}</pre> + +<p>This is quite complex; breaking it down, we:</p> + +<ul> + <li>Run {{domxref("Event.preventDefault()")}} on the event object to stop the form actually submitting in the conventional manner (this would cause a page refresh and spoil the experience).</li> + <li>Create an object representing a record to enter into the database, populating it with values from the form inputs. note that we don't have to explicitly include an <code>id</code> value — as we explained earlier, this is auto-populated.</li> + <li>Open a <code>readwrite</code> transaction against the <code>notes_os</code> object store using the {{domxref("IDBDatabase.transaction()")}} method. This transaction object allows us to access the object store so we can do something to it, e.g. add a new record.</li> + <li>Access the object store using the {{domxref("IDBTransaction.objectStore()")}} method, saving the result in the <code>objectStore</code> variable.</li> + <li>Add the new record to the database using {{domxref("IDBObjectStore.add()")}}. This creates a request object, in the same fashion as we've seen before.</li> + <li>Add a bunch of event handlers to the <code>request</code> and the <code>transaction</code> to run code at critical points in the lifecycle. Once the request has succeeded, we clear the form inputs ready for entering the next note. Once the transaction has completed, we run the <code>displayData()</code> function again to update the display of notes on the page.</li> +</ul> + +<h3 id="Displaying_the_data">Displaying the data</h3> + +<p>We've referenced <code>displayData()</code> twice in our code already, so we'd probably better define it. Add this to your code, below the previous function definition:</p> + +<pre class="brush: js notranslate">// Define the displayData() function +function displayData() { + // Here we empty the contents of the list element each time the display is updated + // If you didn't do this, you'd get duplicates listed each time a new note is added + while (list.firstChild) { + list.removeChild(list.firstChild); + } + + // Open our object store and then get a cursor - which iterates through all the + // different data items in the store + let objectStore = db.transaction('notes_os').objectStore('notes_os'); + objectStore.openCursor().onsuccess = function(e) { + // Get a reference to the cursor + let cursor = e.target.result; + + // If there is still another data item to iterate through, keep running this code + if(cursor) { + // Create a list item, h3, and p to put each data item inside when displaying it + // structure the HTML fragment, and append it inside the list + let listItem = document.createElement('li'); + let h3 = document.createElement('h3'); + let para = document.createElement('p'); + + listItem.appendChild(h3); + listItem.appendChild(para); + list.appendChild(listItem); + + // Put the data from the cursor inside the h3 and para + h3.textContent = cursor.value.title; + para.textContent = cursor.value.body; + + // Store the ID of the data item inside an attribute on the listItem, so we know + // which item it corresponds to. This will be useful later when we want to delete items + listItem.setAttribute('data-note-id', cursor.value.id); + + // Create a button and place it inside each listItem + let deleteBtn = document.createElement('button'); + listItem.appendChild(deleteBtn); + deleteBtn.textContent = 'Delete'; + + // Set an event handler so that when the button is clicked, the deleteItem() + // function is run + deleteBtn.onclick = deleteItem; + + // Iterate to the next item in the cursor + cursor.continue(); + } else { + // Again, if list item is empty, display a 'No notes stored' message + if(!list.firstChild) { + let listItem = document.createElement('li'); + listItem.textContent = 'No notes stored.'; + list.appendChild(listItem); + } + // if there are no more cursor items to iterate through, say so + console.log('Notes all displayed'); + } + }; +}</pre> + +<p>Again, let's break this down:</p> + +<ul> + <li>First we empty out the {{htmlelement("ul")}} element's content, before then filling it with the updated content. If you didn't do this, you'd end up with a huge list of duplicated content being added to with each update.</li> + <li>Next, we get a reference to the <code>notes_os</code> object store using {{domxref("IDBDatabase.transaction()")}} and {{domxref("IDBTransaction.objectStore()")}} like we did in <code>addData()</code>, except here we are chaining them together in one line.</li> + <li>The next step is to use {{domxref("IDBObjectStore.openCursor()")}} method to open a request for a cursor — this is a construct that can be used to iterate over the records in an object store. We chain an <code>onsuccess</code> handler on to the end of this line to make the code more concise — when the cursor is successfully returned, the handler is run.</li> + <li>We get a reference to the cursor itself (an {{domxref("IDBCursor")}} object) using let <code>cursor = e.target.result</code>.</li> + <li>Next, we check to see if the cursor contains a record from the datastore (<code>if(cursor){ ... }</code>) — if so, we create a DOM fragment, populate it with the data from the record, and insert it into the page (inside the <code><ul></code> element). We also include a delete button that, when clicked, will delete that note by running the <code>deleteItem()</code> function, which we will look at in the next section.</li> + <li>At the end of the <code>if</code> block, we use the {{domxref("IDBCursor.continue()")}} method to advance the cursor to the next record in the datastore, and run the content of the <code>if</code> block again. If there is another record to iterate to, this causes it to be inserted into the page, and then <code>continue()</code> is run again, and so on.</li> + <li>When there are no more records to iterate over, <code>cursor</code> will return <code>undefined</code>, and therefore the <code>else</code> block will run instead of the <code>if</code> block. This block checks whether any notes were inserted into the <code><ul></code> — if not, it inserts a message to say no note was stored.</li> +</ul> + +<h3 id="Deleting_a_note">Deleting a note</h3> + +<p>As stated above, when a note's delete button is pressed, the note is deleted. This is achieved by the <code>deleteItem()</code> function, which looks like so:</p> + +<pre class="brush: js notranslate">// Define the deleteItem() function +function deleteItem(e) { + // retrieve the name of the task we want to delete. We need + // to convert it to a number before trying it use it with IDB; IDB key + // values are type-sensitive. + let noteId = Number(e.target.parentNode.getAttribute('data-note-id')); + + // open a database transaction and delete the task, finding it using the id we retrieved above + let transaction = db.transaction(['notes_os'], 'readwrite'); + let objectStore = transaction.objectStore('notes_os'); + let request = objectStore.delete(noteId); + + // report that the data item has been deleted + transaction.oncomplete = function() { + // delete the parent of the button + // which is the list item, so it is no longer displayed + e.target.parentNode.parentNode.removeChild(e.target.parentNode); + console.log('Note ' + noteId + ' deleted.'); + + // Again, if list item is empty, display a 'No notes stored' message + if(!list.firstChild) { + let listItem = document.createElement('li'); + listItem.textContent = 'No notes stored.'; + list.appendChild(listItem); + } + }; +}</pre> + +<ul> + <li>The first part of this could use some explaining — we retrieve the ID of the record to be deleted using <code>Number(e.target.parentNode.getAttribute('data-note-id'))</code> — recall that the ID of the record was saved in a <code>data-note-id</code> attribute on the <code><li></code> when it was first displayed. We do however need to pass the attribute through the global built-in <code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number">Number()</a></code> object as it is of datatype string, and therefore wouldn't be recognized by the database, which expects a number.</li> + <li>We then get a reference to the object store using the same pattern we've seen previously, and use the {{domxref("IDBObjectStore.delete()")}} method to delete the record from the database, passing it the ID.</li> + <li>When the database transaction is complete, we delete the note's <code><li></code> from the DOM, and again do the check to see if the <code><ul></code> is now empty, inserting a note as appropriate.</li> +</ul> + +<p>So that's it! Your example should now work.</p> + +<p>If you are having trouble with it, feel free to <a href="https://mdn.github.io/learning-area/javascript/apis/client-side-storage/indexeddb/notes/">check it against our live example</a> (see the <a href="https://github.com/mdn/learning-area/blob/master/javascript/apis/client-side-storage/indexeddb/notes/index.js">source code</a> also).</p> + +<h3 id="Storing_complex_data_via_IndexedDB">Storing complex data via IndexedDB</h3> + +<p>As we mentioned above, IndexedDB can be used to store more than just simple text strings. You can store just about anything you want, including complex objects such as video or image blobs. And it isn't much more difficult to achieve than any other type of data.</p> + +<p>To demonstrate how to do it, we've written another example called <a href="https://github.com/mdn/learning-area/tree/master/javascript/apis/client-side-storage/indexeddb/video-store">IndexedDB video store</a> (see it <a href="https://mdn.github.io/learning-area/javascript/apis/client-side-storage/indexeddb/video-store/">running live here also</a>). When you first run the example, it downloads all the videos from the network, stores them in an IndexedDB database, and then displays the videos in the UI inside {{htmlelement("video")}} elements. The second time you run it, it finds the videos in the database and gets them from there instead before displaying them — this makes subsequent loads much quicker and less bandwidth-hungry.</p> + +<p>Let's walk through the most interesting parts of the example. We won't look at it all — a lot of it is similar to the previous example, and the code is well-commented.</p> + +<ol> + <li> + <p>For this simple example, we've stored the names of the videos to fetch in an array of objects:</p> + + <pre class="brush: js notranslate">const videos = [ + { 'name' : 'crystal' }, + { 'name' : 'elf' }, + { 'name' : 'frog' }, + { 'name' : 'monster' }, + { 'name' : 'pig' }, + { 'name' : 'rabbit' } +];</pre> + </li> + <li> + <p>To start with, once the database is successfully opened we run an <code>init()</code> function. This loops through the different video names, trying to load a record identified by each name from the <code>videos</code> database.</p> + + <p>If each video is found in the database (easily checked by seeing whether <code>request.result</code> evaluates to <code>true</code> — if the record is not present, it will be <code>undefined</code>), its video files (stored as blobs) and the video name are passed straight to the <code>displayVideo()</code> function to place them in the UI. If not, the video name is passed to the <code>fetchVideoFromNetwork()</code> function to ... you guessed it — fetch the video from the network.</p> + + <pre class="brush: js notranslate">function init() { + // Loop through the video names one by one + for(let i = 0; i < videos.length; i++) { + // Open transaction, get object store, and get() each video by name + let objectStore = db.transaction('videos_os').objectStore('videos_os'); + let request = objectStore.get(videos[i].name); + request.onsuccess = function() { + // If the result exists in the database (is not undefined) + if(request.result) { + // Grab the videos from IDB and display them using displayVideo() + console.log('taking videos from IDB'); + displayVideo(request.result.mp4, request.result.webm, request.result.name); + } else { + // Fetch the videos from the network + fetchVideoFromNetwork(videos[i]); + } + }; + } +}</pre> + </li> + <li> + <p>The following snippet is taken from inside <code>fetchVideoFromNetwork()</code> — here we fetch MP4 and WebM versions of the video using two separate {{domxref("fetch()", "WindowOrWorkerGlobalScope.fetch()")}} requests. We then use the {{domxref("blob()", "Body.blob()")}} method to extract each response's body as a blob, giving us an object representation of the videos that can be stored and displayed later on.</p> + + <p>We have a problem here though — these two requests are both asynchronous, but we only want to try to display or store the video when both promises have fulfilled. Fortunately there is a built-in method that handles such a problem — {{jsxref("Promise.all()")}}. This takes one argument — references to all the individual promises you want to check for fulfillment placed in an array — and is itself promise-based.</p> + + <p>When all those promises have fulfilled, the <code>all()</code> promise fulfills with an array containing all the individual fulfillment values. Inside the <code>all()</code> block, you can see that we then call the <code>displayVideo()</code> function like we did before to display the videos in the UI, then we also call the <code>storeVideo()</code> function to store those videos inside the database.</p> + + <pre class="brush: js notranslate">let mp4Blob = fetch('videos/' + video.name + '.mp4').then(response => + response.blob() +); +let webmBlob = fetch('videos/' + video.name + '.webm').then(response => + response.blob() +); + +// Only run the next code when both promises have fulfilled +Promise.all([mp4Blob, webmBlob]).then(function(values) { + // display the video fetched from the network with displayVideo() + displayVideo(values[0], values[1], video.name); + // store it in the IDB using storeVideo() + storeVideo(values[0], values[1], video.name); +});</pre> + </li> + <li> + <p>Let's look at <code>storeVideo()</code> first. This is very similar to the pattern you saw in the previous example for adding data to the database — we open a <code>readwrite</code> transaction and get a reference to our <code>videos_os</code> object store, create an object representing the record to add to the database, then simply add it using {{domxref("IDBObjectStore.add()")}}.</p> + + <pre class="brush: js notranslate">function storeVideo(mp4Blob, webmBlob, name) { + // Open transaction, get object store; make it a readwrite so we can write to the IDB + let objectStore = db.transaction(['videos_os'], 'readwrite').objectStore('videos_os'); + // Create a record to add to the IDB + let record = { + mp4 : mp4Blob, + webm : webmBlob, + name : name + } + + // Add the record to the IDB using add() + let request = objectStore.add(record); + + ... + +};</pre> + </li> + <li> + <p>Last but not least, we have <code>displayVideo()</code>, which creates the DOM elements needed to insert the video in the UI and then appends them to the page. The most interesting parts of this are those shown below — to actually display our video blobs in a <code><video></code> element, we need to create object URLs (internal URLs that point to the video blobs stored in memory) using the {{domxref("URL.createObjectURL()")}} method. Once that is done, we can set the object URLs to be the values of our {{htmlelement("source")}} element's <code>src</code> attributes, and it works fine.</p> + + <pre class="brush: js notranslate">function displayVideo(mp4Blob, webmBlob, title) { + // Create object URLs out of the blobs + let mp4URL = URL.createObjectURL(mp4Blob); + let webmURL = URL.createObjectURL(webmBlob); + + ... + + let video = document.createElement('video'); + video.controls = true; + let source1 = document.createElement('source'); + source1.src = mp4URL; + source1.type = 'video/mp4'; + let source2 = document.createElement('source'); + source2.src = webmURL; + source2.type = 'video/webm'; + + ... +}</pre> + </li> +</ol> + +<h2 id="Offline_asset_storage">Offline asset storage</h2> + +<p>The above example already shows how to create an app that will store large assets in an IndexedDB database, avoiding the need to download them more than once. This is already a great improvement to the user experience, but there is still one thing missing — the main HTML, CSS, and JavaScript files still need to downloaded each time the site is accessed, meaning that it won't work when there is no network connection.</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/15759/ff-offline.png" style="border-style: solid; border-width: 1px; display: block; height: 307px; margin: 0px auto; width: 765px;"></p> + +<p>This is where <a href="/en-US/docs/Web/API/Service_Worker_API">Service workers</a> and the closely-related <a href="/en-US/docs/Web/API/Cache">Cache API</a> come in.</p> + +<p>A service worker is a JavaScript file that, simply put, is registered against a particular origin (web site, or part of a web site at a certain domain) when it is accessed by a browser. When registered, it can control pages available at that origin. It does this by sitting between a loaded page and the network and intercepting network requests aimed at that origin.</p> + +<p>When it intercepts a request, it can do anything you wish to it (see <a href="/en-US/docs/Web/API/Service_Worker_API#Other_use_case_ideas">use case ideas</a>), but the classic example is saving the network responses offline and then providing those in response to a request instead of the responses from the network. In effect, it allows you to make a web site work completely offline.</p> + +<p>The Cache API is a another client-side storage mechanism, with a bit of a difference — it is designed to save HTTP responses, and so works very well with service workers.</p> + +<div class="note"> +<p><strong>Note</strong>: Service workers and Cache are supported in most modern browsers now. At the time of writing, Safari was still busy implementing it, but it should be there soon.</p> +</div> + +<h3 id="A_service_worker_example">A service worker example</h3> + +<p>Let's look at an example, to give you a bit of an idea of what this might look like. We have created another version of the video store example we saw in the previous section — this functions identically, except that it also saves the HTML, CSS, and JavaScript in the Cache API via a service worker, allowing the example to run offline!</p> + +<p>See <a href="https://mdn.github.io/learning-area/javascript/apis/client-side-storage/cache-sw/video-store-offline/">IndexedDB video store with service worker running live</a>, and also <a href="https://github.com/mdn/learning-area/tree/master/javascript/apis/client-side-storage/cache-sw/video-store-offline">see the source code</a>.</p> + +<h4 id="Registering_the_service_worker">Registering the service worker</h4> + +<p>The first thing to note is that there's an extra bit of code placed in the main JavaScript file (see <a href="https://github.com/mdn/learning-area/blob/master/javascript/apis/client-side-storage/cache-sw/video-store-offline/index.js">index.js</a>). First we do a feature detection test to see if the <code>serviceWorker</code> member is available in the {{domxref("Navigator")}} object. If this returns true, then we know that at least the basics of service workers are supported. Inside here we use the {{domxref("ServiceWorkerContainer.register()")}} method to register a service worker contained in the <code>sw.js</code> file against the origin it resides at, so it can control pages in the same directory as it, or subdirectories. When its promise fulfills, the service worker is deemed registered.</p> + +<pre class="brush: js notranslate"> // Register service worker to control making site work offline + + if('serviceWorker' in navigator) { + navigator.serviceWorker + .register('/learning-area/javascript/apis/client-side-storage/cache-sw/video-store-offline/sw.js') + .then(function() { console.log('Service Worker Registered'); }); + }</pre> + +<div class="note"> +<p><strong>Note</strong>: The given path to the <code>sw.js</code> file is relative to the site origin, not the JavaScript file that contains the code. The service worker is at <code>https://mdn.github.io/learning-area/javascript/apis/client-side-storage/cache-sw/video-store-offline/sw.js</code>. The origin is <code>https://mdn.github.io</code>, and therefore the given path has to be <code>/learning-area/javascript/apis/client-side-storage/cache-sw/video-store-offline/sw.js</code>. If you wanted to host this example on your own server, you'd have to change this accordingly. This is rather confusing, but it has to work this way for security reasons.</p> +</div> + +<h4 id="Installing_the_service_worker">Installing the service worker</h4> + +<p>The next time any page under the service worker's control is accessed (e.g. when the example is reloaded), the service worker is installed against that page, meaning that it will start controlling it. When this occurs, an <code>install</code> event is fired against the service worker; you can write code inside the service worker itself that will respond to the installation.</p> + +<p>Let's look at an example, in the <a href="https://github.com/mdn/learning-area/blob/master/javascript/apis/client-side-storage/cache-sw/video-store-offline/sw.js">sw.js</a> file (the service worker). You'll see that the install listener is registered against <code>self</code>. This <code>self</code> keyword is a way to refer to the global scope of the service worker from inside the service worker file.</p> + +<p>Inside the <code>install</code> handler we use the {{domxref("ExtendableEvent.waitUntil()")}} method, available on the event object, to signal that the browser shouldn't complete installation of the service worker until after the promise inside it has fulfilled successfully.</p> + +<p>Here is where we see the Cache API in action. We use the {{domxref("CacheStorage.open()")}} method to open a new cache object in which responses can be stored (similar to an IndexedDB object store). This promise fulfills with a {{domxref("Cache")}} object representing the <code>video-store</code> cache. We then use the {{domxref("Cache.addAll()")}} method to fetch a series of assets and add their responses to the cache.</p> + +<pre class="brush: js notranslate">self.addEventListener('install', function(e) { + e.waitUntil( + caches.open('video-store').then(function(cache) { + return cache.addAll([ + '/learning-area/javascript/apis/client-side-storage/cache-sw/video-store-offline/', + '/learning-area/javascript/apis/client-side-storage/cache-sw/video-store-offline/index.html', + '/learning-area/javascript/apis/client-side-storage/cache-sw/video-store-offline/index.js', + '/learning-area/javascript/apis/client-side-storage/cache-sw/video-store-offline/style.css' + ]); + }) + ); +});</pre> + +<p>That's it for now, installation done.</p> + +<h4 id="Responding_to_further_requests">Responding to further requests</h4> + +<p>With the service worker registered and installed against our HTML page, and the relevant assets all added to our cache, we are nearly ready to go. There is only one more thing to do, write some code to respond to further network requests.</p> + +<p>This is what the second bit of code in <code>sw.js</code> does. We add another listener to the service worker global scope, which runs the handler function when the <code>fetch</code> event is raised. This happens whenever the browser makes a request for an asset in the directory the service worker is registered against.</p> + +<p>Inside the handler we first log the URL of the requested asset. We then provide a custom response to the request, using the {{domxref("FetchEvent.respondWith()")}} method.</p> + +<p>Inside this block we use {{domxref("CacheStorage.match()")}} to check whether a matching request (i.e. matches the URL) can be found in any cache. This promise fulfills with the matching response if a match is not found, or <code>undefined</code> if it isn't.</p> + +<p>If a match is found, we simply return it as the custom response. If not, we <a href="/en-US/docs/Web/API/WindowOrWorkerGlobalScope/fetch">fetch()</a> the response from the network and return that instead.</p> + +<pre class="brush: js notranslate">self.addEventListener('fetch', function(e) { + console.log(e.request.url); + e.respondWith( + caches.match(e.request).then(function(response) { + return response || fetch(e.request); + }) + ); +});</pre> + +<p>And that is it for our simple service worker. There is a whole load more you can do with them — for a lot more detail, see the <a href="https://serviceworke.rs/">service worker cookbook</a>. And thanks to Paul Kinlan for his article <a href="https://developers.google.com/web/fundamentals/codelabs/offline/">Adding a Service Worker and Offline into your Web App</a>, which inspired this simple example.</p> + +<h4 id="Testing_the_example_offline">Testing the example offline</h4> + +<p>To test our <a href="https://mdn.github.io/learning-area/javascript/apis/client-side-storage/cache-sw/video-store-offline/">service worker example</a>, you'll need to load it a couple of times to make sure it is installed. Once this is done, you can:</p> + +<ul> + <li>Try unplugging your network/turning your Wifi off.</li> + <li>Select <em>File > Work Offline</em> if you are using Firefox.</li> + <li>Go to the devtools, then choose <em>Application > Service Workers</em>, then check the <em>Offline</em> checkbox if you are using Chrome.</li> +</ul> + +<p>If you refresh your example page again, you should still see it load just fine. Everything is stored offline — the page assets in a cache, and the videos in an IndexedDB database.</p> + +<h2 id="Summary">Summary</h2> + +<p>That's it for now. We hope you've found our rundown of client-side storage technologies useful.</p> + +<h2 id="See_also">See also</h2> + +<ul> + <li><a href="/en-US/docs/Web/API/Web_Storage_API">Web storage API</a></li> + <li><a href="/en-US/docs/Web/API/IndexedDB_API">IndexedDB API</a></li> + <li><a href="/en-US/docs/Web/HTTP/Cookies">Cookies</a></li> + <li><a href="/en-US/docs/Web/API/Service_Worker_API">Service worker API</a></li> +</ul> + +<p>{{PreviousMenu("Learn/JavaScript/Client-side_web_APIs/Video_and_audio_APIs", "Learn/JavaScript/Client-side_web_APIs")}}</p> + +<h2 id="In_this_module">In this module</h2> + +<ul> + <li><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Introduction">Introduction to web APIs</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Manipulating_documents">Manipulating documents</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Fetching_data">Fetching data from the server</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Third_party_APIs">Third party APIs</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Drawing_graphics">Drawing graphics</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Video_and_audio_APIs">Video and audio APIs</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Client-side_storage">Client-side storage</a></li> +</ul> diff --git a/files/ko/learn/javascript/client-side_web_apis/index.html b/files/ko/learn/javascript/client-side_web_apis/index.html new file mode 100644 index 0000000000..a02e2bc0c4 --- /dev/null +++ b/files/ko/learn/javascript/client-side_web_apis/index.html @@ -0,0 +1,37 @@ +--- +title: Client-side web APIs +slug: Learn/JavaScript/Client-side_web_APIs +translation_of: Learn/JavaScript/Client-side_web_APIs +--- +<div>{{LearnSidebar}}</div> + +<p class="summary">웹 사이트 또는 응용 프로그램 용 client-side JavaScript를 작성할때 API (응용 프로그램 프로그래밍 인터페이스)를 사용하지 않으면 많은것을 만들기 어렵습니다. API는 사이트가 실행되고 있는 브라우저와 운영 체제의 다양한 부분 그리고 웹 사이트 혹은 서비스의 데이터를 다룰 수 있는 인터페이스입니다. 이번장에서 우리는 API가 무엇인지, 그리고 개발할 때 자주 접하게 될 보편적인 API를 사용하는 방법에 대해 살펴볼 것입니다.</p> + +<h2 id="선행사항">선행사항</h2> + +<p>다음의 문서를 미리 보고 오시는것을 권장합니다. (<a href="/ko/docs/Learn/JavaScript/First_steps">First steps</a>, <a href="/ko/docs/Learn/JavaScript/Building_blocks">Building blocks</a>, and <a href="/ko/docs/Learn/JavaScript/Objects">JavaScript objects</a>). 이 모듈은 클라이언트 측 JavaScript 예제를 사용하지 않고 유용하게 사용할 수 있기 때문에 간단한 API 사용법을 상당히 많이 사용합니다. 여기에서는 핵심 자바 스크립트 언어에 대한 지식이 있다고 가정하고 일반적인 웹 API를 좀 더 자세하게 살펴보면서 한 단계 올라갑니다. 이번장에서는 심플한 API사용방법을 여럿 보도록 하겠습니다. 이 API들은 client-side 자바스크립트를 만드는데 도움이 많이 될 것입니다.</p> + +<p><a href="/en-US/docs/Learn/HTML">HTM</a>과<a href="/en-US/docs/Learn/CSS">CSS</a>에 관한 기본지식이 있으면 좋습니다!</p> + +<div class="note"> +<p><strong>Note</strong>: 코드를 작성 할 수 없는 디바이스에서 작업하는 경우 <a href="http://jsbin.com/">JSBin</a> 또는 <a href="https://thimble.mozilla.org/">Thimble</a>.과 같은 온라인 코딩 프로그램에서 코드 예제를 시험해 볼 수 있습니다.</p> +</div> + +<h2 id="Guides">Guides</h2> + +<dl> + <dt><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Introduction">Introduction to web APIs</a></dt> + <dd>우선, 높은 수준의 API를 먼저 살펴볼 것입니다. API는 무엇이며, 어떻게 작동하며, 코드에서 어떻게 사용하고 구조화되어 있는지 확인합니다. 또한 API의 다른 주요 클래스가 무엇인지, 그리고 용도가 무엇인지 살펴볼 것입니다.</dd> + <dt><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Manipulating_documents">Manipulating documents</a></dt> + <dd>웹 페이지와 앱을 작성할 때 많이 하는 것중 하나는 웹 문서를 다루는 것입니다. 보통 {{domxref ( "Document")}} 객체를 많이 사용하는 HTML 및 스타일 정보를 제어하기위한 API 집합 인 DOM (Document Object Model)을 사용합니다. 여기서는 흥미로운 방식으로 환경을 변경할 수 있는 API와 함께 DOM을 사용하는 방법에 대해 자세히 설명합니다.</dd> + <dt><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Fetching_data">Fetching data from the server</a></dt> + <dd>최신 웹 사이트 및 응용 프로그램에서 필요한 작업중 하나는 완전히 새로운 페이지를 로드 할 필요없이 서버에서 개별 데이터를 가져와 웹 페이지의 일부분만 업데이트하는 것입니다. 이렇게 하면 사이트의 성능과 동작에 큰 영향을 줍니다. 여기서는 이 개념을 설명하고 {{domxref ( "XMLHttpRequest")}}나 <a href="https://developer.mozilla.org/ko/docs/Web/API/Fetch_API">Fetch API</a>와 같은 기술을 살펴 보겠습니다</dd> + <dt><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Third_party_APIs">Third party APIs</a></dt> + <dd>지금까지 살펴본 API는 브라우저에 내장되어 있지만 모든 API가 지원되지는 않습니다. 예를들면 Google Maps, Twitter, Facebook, PayPal 등과 같은 많은 대형 웹 사이트와 서비스가 있고 여기에는 개발자 자신의 데이터 (예 : 블로그에 트위터 스트림 표시) 또는 서비스 (예 : 사이트에 맞춤 Google지도 표시, Facebook 로그인을 사용하여 사용자 로그인)가 있습니다.여기서는 브라우저 API와 타사 API의 차이점을 살펴본 후 일반적인 API 사용법을 보겠습니다.</dd> + <dt><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Drawing_graphics">Drawing graphics</a></dt> + <dd>브라우저에는 <a href="https://developer.mozilla.org/en-US/docs/Web/SVG">SVG</a> (Scalable Vector Graphics) 언어부터 HTML {{htmlelement ( "canvas")}} 요소 (<a href="https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API">The Canvas API</a> 및 <a href="https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API">WebGL</a> 참조)를 그리는 데 필요한 API에 이르기까지 매우 강력한 그래픽 프로그래밍 도구가 포함되어 있습니다. 여기서는 Canvas API에 대한 소개와 더 많은 정보를 얻을 수있는 추가 자료를 제공합니다.</dd> + <dt><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Video_and_audio_APIs">Video and audio APIs</a></dt> + <dd>HTML5에는 문서 ({{htmlelement ( "video")}} 및 {{htmlelement ( "audio")}}에 미디어를 포함하기위한 요소가 포함되어 있으며 재생, 탐색 등을 제어하는 자체 API가 제공됩니다. 이문서에서는 사용자 커스텀 재생 컨트롤 만들기와 같은 일반적인 작업을 수행하는 방법을 보여줍니다.</dd> + <dt><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Client-side_storage">Client-side storage</a></dt> + <dd>최신 웹 브라우저에는 웹 사이트와 관련된 데이터를 저장하고 필요할 때 검색하여 장기간 데이터를 유지하고 오프라인으로 사이트를 저장하는 등 다양한 기술을 사용할 수 있습니다. 이 기사에서는 이러한 작업 방식에 대한 기본적인 내용을 설명합니다.</dd> +</dl> diff --git a/files/ko/learn/javascript/first_steps/a_first_splash/index.html b/files/ko/learn/javascript/first_steps/a_first_splash/index.html new file mode 100644 index 0000000000..fd29057f86 --- /dev/null +++ b/files/ko/learn/javascript/first_steps/a_first_splash/index.html @@ -0,0 +1,680 @@ +--- +title: 자바스크립트 기초 +slug: Learn/JavaScript/First_steps/A_first_splash +translation_of: Learn/JavaScript/First_steps/A_first_splash +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/JavaScript/First_steps/What_is_JavaScript", "Learn/JavaScript/First_steps/What_went_wrong", "Learn/JavaScript/First_steps")}}</div> + +<p class="summary">이제 우리는 자바스크립트에 대한 이론적인 몇몇 부분을 살펴볼 것이다. 이곳에서 무엇을 할 수 있는지 실용적인 연습을 통한 자바스크립의 기본적 사항들을 다루는 과정이 되겠다. 하나하나씩 "숫자맞추기" 게임을 간단하게 구성해나갈 것이다.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">알아야할 것들:</th> + <td>기본적인 컴퓨터 사용과 HTML CSS와 자바스크립트에 대해 알아야 함.</td> + </tr> + <tr> + <th scope="row">수업 목표:</th> + <td>자바스크립트로 코딩하는 것을 처음으로 알아보고 자바스크립트로 쓰여진 프로그램이 가지고 있는 특징들을 조금이라도 이해한다.</td> + </tr> + </tbody> +</table> + +<p>지금현재로서는 코드를 자세히 이해하려고 하지는 않을 것이다. 단지 지금은 넓게 개념을 이해하고, (다른 프로그래밍 언어를 포함해) 자바스크립트가 어떻게 운용되는지에 대한 아이디어가 필요하다. 자, 이제부터 자세한 부분에 대해 공부하고 알아보자!</p> + +<div class="note"> +<p>Note: 자바스크립트에서 보는 다양한 요소들은 여타 프로그래밍 언어와 거의 똑같다.(함수나 반복문 등) 언어마다 문법이 다를 뿐이지 개념은 넓은범위에서 보자면 일맥상통하다.</p> +</div> + +<h2 id="프로그래머처럼_사고하기">프로그래머처럼 사고하기</h2> + +<p>프로그래밍에서 가장 어려운 것은 우리가 배우려고 하는 문법이 아닌, 어떻게 실생활의 문제를 프로그래밍으로 적용시킬까하는 문제이다. 이제부터는 프로그래머처럼 생각하는 것이 필요하다. 이는 일반적으로 프로그램이 필요한 부분과 어떻게 코드가 문제를 해결하기위해 작동되고, 협업해야 되는지에 대한 설명을 알고있어야 된다는 것이다.</p> + +<p>이는 프로그래밍 문법에 대한 경험과 노력, 그리고 창의성을 비롯한 노력의 조합이 필요하다. 코드를 많이 작성할수록 얻는 것은 더 많아질 것이다. 지금 당장 "프로그래머의 사고능력"으로 발전시킨다고는 보장하지는 못하지만, 이 수업을 통해 여러분들에게 프로그래머처럼 생각하는 많은 연습의 기회는 줄 수 있다.</p> + +<p>이러한 개념을 마음속에 품고, 앞으로 우리가 만들어나갈 예제를 한번 살펴보자. 여기서 실생활의 문제를 프로그래밍할 수 있도록 쪼개는 일반적인 과정을 볼 것이다.</p> + +<h2 id="예제-숫자맞추기">예제-숫자맞추기</h2> + +<p>아래 보이는 간단한 게임을 통해, 프로그램을 구성하는 방법을 알아볼 것이다.</p> + +<div class="hidden"> +<h6 id="Top_hidden_code">Top hidden code</h6> + + + +<pre class="brush: html"><!DOCTYPE html> +<html> + +<head> + <meta charset="utf-8"> + <title>Number guessing game</title> + <style> + html { + font-family: sans-serif; + } + + body { + width: 50%; + max-width: 800px; + min-width: 480px; + margin: 0 auto; + } + + .lastResult { + color: white; + padding: 3px; + } + </style> +</head> + +<body> + <h1>Number guessing game</h1> + <p>We have selected a random number between 1 and 100. See if you can guess it in 10 turns or less. We'll tell you if your guess was too high or too low.</p> + <div class="form"> <label for="guessField">Enter a guess: </label><input type="text" id="guessField" class="guessField"> <input type="submit" value="Submit guess" class="guessSubmit"> </div> + <div class="resultParas"> + <p class="guesses"></p> + <p class="lastResult"></p> + <p class="lowOrHi"></p> + </div> +</body> +<script> + // Your JavaScript goes here + var randomNumber = Math.floor(Math.random() * 100) + 1; + var guesses = document.querySelector('.guesses'); + var lastResult = document.querySelector('.lastResult'); + var lowOrHi = document.querySelector('.lowOrHi'); + var guessSubmit = document.querySelector('.guessSubmit'); + var guessField = document.querySelector('.guessField'); + var guessCount = 1; + var resetButton; + + function checkGuess() { + var userGuess = Number(guessField.value); + if (guessCount === 1) { + guesses.textContent = 'Previous guesses: '; + } + + guesses.textContent += userGuess + ' '; + + if (userGuess === randomNumber) { + lastResult.textContent = 'Congratulations! You got it right!'; + lastResult.style.backgroundColor = 'green'; + lowOrHi.textContent = ''; + setGameOver(); + } else if (guessCount === 10) { + lastResult.textContent = '!!!GAME OVER!!!'; + lowOrHi.textContent = ''; + setGameOver(); + } else { + lastResult.textContent = 'Wrong!'; + lastResult.style.backgroundColor = 'red'; + if(userGuess < randomNumber) { + lowOrHi.textContent='Last guess was too low!' ; + } else if(userGuess > randomNumber) { + lowOrHi.textContent = 'Last guess was too high!'; + } + } + + guessCount++; + guessField.value = ''; + } + + guessSubmit.addEventListener('click', checkGuess); + + function setGameOver() { + guessField.disabled = true; + guessSubmit.disabled = true; + resetButton = document.createElement('button'); + resetButton.textContent = 'Start new game'; + document.body.appendChild(resetButton); + resetButton.addEventListener('click', resetGame); + } + + function resetGame() { + guessCount = 1; + var resetParas = document.querySelectorAll('.resultParas p'); + for(var i = 0 ; i < resetParas.length ; i++) { + resetParas[i].textContent=''; + } + + resetButton.parentNode.removeChild(resetButton); + guessField.disabled = false; + guessSubmit.disabled = false; + guessField.value=''; + guessField.focus(); + lastResult.style.backgroundColor='white'; + randomNumber=Math.floor(Math.random() * 100) + 1; + } +</script> + +</html></pre> + + +</div> + +<p>{{ EmbedLiveSample('Top_hidden_code', '100%', 320) }}</p> + +<p>한 번 실행해서 어떻게 이루어져 있는지 살펴보고 알아보자.</p> + +<p>만약 너의 상사가 예제에 관련되어 다음의 짦은 안내만 주어졌다고 생각해보자.</p> + +<blockquote> +<p>나는 간단하게 숫자 맞추기 게임을 만들고 싶다.1과 100사의 수 중에서 무작위로 선택되어야하고, 플레이어는 10번의 기회안에 그 숫자를 맞춰야 한다. 각 순서마다 숫자를 맞춰는지 틀렸는지는 당연히 알려줘야 하고, 틀렸다면 큰지 작은지도 포함해서 말해야 한다.또한 이전에 써냈던 번호들도 보여줘야 한다. 게임은 플레이어가 숫자를 맞추던가, 기회를 모두 소진하면 끝나게 된다. 게임이 끝나면 플레이어가 다시 게임을 할 것인지 묻게된다.</p> +</blockquote> + +<p>위의 안내문을 보고, 우선 문제를 가능한 한 작게 쪼개서 간단한 작업으로 만드는 것부터 시작하자.</p> + +<ol> + <li>1과 100사이의 숫자 중 무작위로 추출한다.</li> + <li>1부터 플레이어의 차례를 기록한다.</li> + <li>플레이어에게 숫자를 맞출 수 있게 한다.</li> + <li>숫자를 맞추면 어딘가에 저장하고, 사용자는 이전의 추측한 숫자를 볼 수 있도록 한다.</li> + <li>그다음, 숫자가 일치한지 확인한다.</li> + <li>만약 일치한다면: + <ol> + <li>축하 메시지를 표시한다.</li> + <li>더 이상 숫자를 맞출필요가 없다.</li> + <li>플레이어가 다시 게임을 할지 묻는다.</li> + </ol> + </li> + <li>숫자가 틀렸고, 차례가 남아있다면: + <ol> + <li>틀렸다고 알린다.</li> + <li>다른 숫자를 입력할 수 있도록 한다.</li> + <li>차례가 1 증가한다.</li> + </ol> + </li> + <li>숫자가 틀렸고, 차례가 없다면: + <ol> + <li>게임이 종료되었음을 알린다.</li> + <li>더 이상 숫자를 맞출필요가 없다..</li> + <li>플레이어가 다시 게임을 할지 묻는다.</li> + </ol> + </li> + <li>게임이 재시작 되면, 게임의 구조와 UI는 완전히 리셋되며, step1 부터 다시 로직이 시작된다.</li> +</ol> + +<p>이제 다음 단계로 넘어가서 각 단계들을 코드로 어떻게 만들고, 예제 소스와 통합하며, 그와 관련된 자바 스크립트 기능은 무엇인지 살펴보도록 하겠다.</p> + +<h3 id="초기_구성">초기 구성</h3> + +<p>수업에 앞서, 로컬에 <a href="https://github.com/mdn/learning-area/blob/master/javascript/introduction-to-js-1/first-splash/number-guessing-game-start.html">number-guessing-game-start.html</a> 파일을 저장하길 바란다. (<a href="http://mdn.github.io/learning-area/javascript/introduction-to-js-1/first-splash/number-guessing-game-start.html">see it live here</a>). 그러고 파일을 에디터와 브라우저에서 동시에 열어보자. 간단하게 요약된 설명과 추측하는 폼을 볼 때, 아직 숫자를 입력하는 폼은 아무런 기능을 하지 않는다</p> + +<p>여러분들의 코드를 추가하는 부분은 HTML안의 {{htmlelement("script")}} 요소 사이에 있다. </p> + +<pre class="brush: html"><script> + + // Your JavaScript goes here + +</script> +</pre> + +<h3 id="데이터_저장을_위한_변수_추가">데이터 저장을 위한 변수 추가</h3> + +<p>이제 시작해보자! 먼저 {{htmlelement("script")}} 태그안에 다음의 코드들을 추가하자.</p> + +<pre class="brush: js">var randomNumber = Math.floor(Math.random() * 100) + 1; + +var guesses = document.querySelector('.guesses'); +var lastResult = document.querySelector('.lastResult'); +var lowOrHi = document.querySelector('.lowOrHi'); + +var guessSubmit = document.querySelector('.guessSubmit'); +var guessField = document.querySelector('.guessField'); + +var guessCount = 1; +var resetButton;</pre> + +<p>이 코드의 부분은 프로그램에서 사용될 데이터를 저장할 변수를 세팅해준다. 변수들은 기본적으로 값들을 저장하고 있다. (숫자나 문자열 등). 변수들은 var이라는 키워드를 변수의 이름앞에 붙여줌으로써 선언이된다. 변수 에 넣고자 하는 값 앞에 등호(=)를 통해 변수에 값을 지정할 수 있다.</p> + +<p>예제에서</p> + +<ul> + <li>첫번째 변수 <code>randomNumber</code>는 수학적 알고리즘을 통해 계산해 1과 100사이의 임의의 수를 지정한다 .</li> + <li>다음의 세 개의 변수들은 각각 HTML에서 결과 문장을 저장하는 기준으로 저장되고, 코드상에서 나중에 문장에 추가되도록 사용된다. + <pre class="brush: html"><p class="guesses"></p> +<p class="lastResult"></p> +<p class="lowOrHi"></p></pre> + </li> + <li>다음의 2개 변수는 다음의 입력과 버튼을 받고, 추측된 값을 나중에 받도록 하는 역할을 한다. + <pre class="brush: html"><label for="guessField">Enter a guess: </label><input type="text" id="guessField" class="guessField"> +<input type="submit" value="Submit guess" class="guessSubmit"></pre> + </li> + <li>마지막 2개의 변수에는 (얼마나 많은 추측을 했는지) 추측 개수와, 아직은 있지않은 버튼을 리셋하는 변수가 있다.</li> +</ul> + +<div class="note"> +<p><strong>주의</strong>: 앞으로 변수에 대해서는 더 많이 배울 것이다. <a href="https://developer.mozilla.org/en-US/docs/user:chrisdavidmills/variables">next article</a>를 참고해보자.</p> +</div> + +<h3 id="함수">함수</h3> + +<p>다음으로, 아래의 자바스크립트 코드를 추가하자.</p> + +<pre class="brush: js">function checkGuess() { + alert('I am a placeholder'); +}</pre> + +<p>함수는 재사용이 가능한 코드의 묶음으로 한 번만 명시하면 몇번이고 실행이 가능하여 전체적인 코드에서 반복을 줄일 수 있다 . 이는 매우 유용하다. 함수를 정의하는 방법에는 여러가지가 있지만, 일단 여기서는 가장 간단한 방법을 집중적으로 살펴볼 것이다. 앞에 <code>function</code>키워드를 사용하고, 함수의 이름을 작성하며, 함수의 이름 뒤에 괄호를 넣어줌으로서 함수를 정의할 수 있다.그러고 나서 중괄호로 묶어준다. 중괄호 안에는 함수가 호출되면 실행되는 반복적인 코드들이 들어있다.</p> + +<p>코드는 괄호 앞에 위치한 함수의 이름을 적음으로 실행된다.</p> + +<p>코드를 저장하고 브라우저에서 새로고침을 통해 실행해보자.</p> + +<p><a href="/en-US/docs/Learn/Common_questions/What_are_browser_developer_tools">developer tools JavaScript console</a>에 들어가서 다음의 문장을 입력해보자</p> + +<pre class="brush: js">checkGuess();</pre> + +<p>"I am a placeholder"라고 알리는 alert를 볼 수 있을 것이다. 여기서는 함수가 호출되면 alert가 생성되는 함수로 정의되어 있다.</p> + +<div class="note"> +<p><strong>Note</strong>:더 많은 함수에 대한 내용은 차후의 학습에서 볼 수 있을 것이다.</p> +</div> + +<h3 id="연산자">연산자</h3> + +<p>자바스크립트의 연산자는 테스트를 진행하고, 수학적인 것을 다루고, 문자열을 결합하는 등의 것들을 가능케한다.</p> + +<p>다음의 코드를 저장하고 브라우저의 페이지에서 보이도록 새로고침 해보자. <a href="/en-US/docs/Learn/Common_questions/What_are_browser_developer_tools">개발자 도구 JavaScript 콘솔</a>을 열고 아래 표시된 에제를 입력 해보자. 표시된대로 정확히 입력하고 Return/Enter 키를 누른 후 어떤 결과가 반환되는지 보자. 브라우저 개발자 도구에 쉽게 액세스 할 수 없는 경우, 아래 표시된 간단한 콘솔을 사용 할 수 있다:</p> + +<div class="hidden"> +<h6 id="Hidden_code">Hidden code</h6> + +<pre class="brush: html"><!DOCTYPE html> +<html> + <head> + <meta charset="utf-8"> + <title>JavaScript console</title> + <style> + * { + box-sizing: border-box; + } + + html { + background-color: #0C323D; + color: #809089; + font-family: monospace; + } + + body { + max-width: 700px; + } + + p { + margin: 0; + width: 1%; + padding: 0 1%; + font-size: 16px; + line-height: 1.5; + float: left; + } + + .input p { + margin-right: 1%; + } + + .output p { + width: 100%; + } + + .input input { + width: 96%; + float: left; + border: none; + font-size: 16px; + line-height: 1.5; + font-family: monospace; + padding: 0; + background: #0C323D; + color: #809089; + } + + div { + clear: both; + } + + </style> + </head> + <body> + + + </body> + + <script> + var geval = eval; + + function createInput() { + var inputDiv = document.createElement('div'); + var inputPara = document.createElement('p'); + var inputForm = document.createElement('input'); + + inputDiv.setAttribute('class','input'); + inputPara.textContent = '>'; + inputDiv.appendChild(inputPara); + inputDiv.appendChild(inputForm); + document.body.appendChild(inputDiv); + inputDiv.focus(); + + inputForm.addEventListener('change', executeCode); + } + + function executeCode(e) { + try { + var result = geval(e.target.value); + } catch(e) { + var result = 'error — ' + e.message; + } + + var outputDiv = document.createElement('div'); + var outputPara = document.createElement('p'); + + outputDiv.setAttribute('class','output'); + outputPara.textContent = 'Result: ' + result; + outputDiv.appendChild(outputPara); + document.body.appendChild(outputDiv); + + e.target.disabled = true; + e.target.parentNode.style.opacity = '0.5'; + + createInput() + } + + createInput(); + + </script> +</html></pre> +</div> + +<p>{{ EmbedLiveSample('Hidden_code', '100%', 300) }}</p> + +<p>먼저 산술 연산자를 살펴보자.</p> + +<table class="standard-table"> + <thead> + <tr> + <th scope="col">연산자</th> + <th scope="col">이름</th> + <th scope="col">예</th> + </tr> + </thead> + <tbody> + <tr> + <td><code>+</code></td> + <td>더하기 </td> + <td><code>6 + 9</code></td> + </tr> + <tr> + <td><code>-</code></td> + <td>빼기</td> + <td><code>20 - 15</code></td> + </tr> + <tr> + <td><code>*</code></td> + <td>곱하기</td> + <td><code>3 * 7</code></td> + </tr> + <tr> + <td><code>/</code></td> + <td>나누기</td> + <td><code>10 / 5</code></td> + </tr> + </tbody> +</table> + +<p>또한 + 연산자는 문자열들을 서로 연결할때에도 사용된다.(이를 프로그래밍에서 '문자열접합'이라고 한다.) 다음 코드를 입력해보자.</p> + +<pre class="brush: js">var name = 'Bingo'; +name; +var hello = ' says hello!'; +hello; +var greeting = name + hello; +greeting;</pre> + +<p>그리고 '복합 대입 연산자' 라고 불리는 소스를 간단하게 하는 연산자도 있다. 예를 들어, 단순히 새로운 문자열을 기존에 있는 문자열에 추가하고, 그 결과를 반환받는 일을 하고 있다면 다음 코드를 사용할 수 있다.</p> + +<pre class="brush: js">name += ' says hello!';</pre> + +<p>이 코드는 다음 코드와 같은 의미이다.</p> + +<pre class="brush: js">name = name + ' says hello!';</pre> + +<p>참/거짓을 판명할때 (조건문이 있을 때 — {{anch("Conditionals", "아래")}}를 참조하자) , 비교연산자를 사용한다.</p> + +<table class="standard-table"> + <thead> + <tr> + <th scope="col">Operator</th> + <th scope="col">Name</th> + <th scope="col">Example</th> + </tr> + <tr> + <td><code>===</code></td> + <td>Strict equality (is it exactly the same?)</td> + <td><code>5 === 2 + 4</code></td> + </tr> + <tr> + <td><code>!==</code></td> + <td>Non-equality (is it not the same?)</td> + <td><code>'Chris' !== 'Ch' + 'ris'</code></td> + </tr> + <tr> + <td><code><</code></td> + <td>Less than</td> + <td><code>10 < 6</code></td> + </tr> + <tr> + <td><code>></code></td> + <td>Greater than</td> + <td><code>10 > 20</code></td> + </tr> + </thead> +</table> + +<h3 id="조건문">조건문</h3> + +<p>함수가 반환되었을때, 자리표시자 메시지(Placeholder Message, 텍스트를 입력할 때 무엇을 입력해야되는지 알려주는 기능 - 역자)를 표시하지 않는 것이 더 좋을 것이라고 본다 . 우리는 사용자의 추측이 옳은지, 틀린지만 보고 적절하게 응답하도록만 할 것이다.</p> + +<p>이 시점에서 이제, 현재 checkGuess()함수를 다음과 같이 수정해보자.</p> + +<pre class="brush: js">function checkGuess() { + var userGuess = Number(guessField.value); + if (guessCount === 1) { + guesses.textContent = 'Previous guesses: '; + } + guesses.textContent += userGuess + ' '; + + if (userGuess === randomNumber) { + lastResult.textContent = 'Congratulations! You got it right!'; + lastResult.style.backgroundColor = 'green'; + lowOrHi.textContent = ''; + setGameOver(); + } else if (guessCount === 10) { + lastResult.textContent = '!!!GAME OVER!!!'; + setGameOver(); + } else { + lastResult.textContent = 'Wrong!'; + lastResult.style.backgroundColor = 'red'; + if(userGuess < randomNumber) { + lowOrHi.textContent = 'Last guess was too low!'; + } else if(userGuess > randomNumber) { + lowOrHi.textContent = 'Last guess was too high!'; + } + } + + guessCount++; + guessField.value = ''; + guessField.focus(); +}</pre> + +<p>꽤 코드가 길다. 각 부분별로 이제 하나하나씩 파헤쳐보자!</p> + +<ul> + <li>2번 줄까지는 userGuess변수를 선언하고, 텍스트 필드에서 입력된 현재 값들을 변수의 값으로 지정한다. 여기서는 빌트인된 <code>Number()</code>메소드(값이 숫자라는 것을 알 수 있다.)로 실행된다.</li> + <li>그러고나서, 처음으로 조건문을 맞딱드린다. (3-5번 줄). 조건문 블록은 조건이 옳은지 그른지에 따라 선택적으로 코드가 실행된다. 함수와 비슷하나, 꼭 그렇지는 않다. 가장 간단한 조건문의 형태는 키워드 <code>if</code>를 사용하고, 괄호가 있고, 중괄호가 있다. 괄호안에는 조건이 삽입된다. 만약 조건문이 옳다면, 중괄호안의 코드들이 실행된다. 거짓이라면, 다음 코드로 넘어가게 된다. 이 코드에서 조건문은 <code>guessCount변수가 1인지 이다.</code> (즉, 현재 플레이어의 게임이 처음인지 아닌지를 판단하는 조건)</li> +</ul> + +<pre class="brush: js">guessCount === 1</pre> + +<p>참이라면, guessess 변수의 텍스트는 "Previous guesses: "가 된다. 그렇지 않다면, 실행되지 않는다.</p> + +<ul> + <li>6번 줄에서는 현재의 userGuess 값에 마지막 guesses 문장을 추가하고, 끝에 공백을 더함으로서 각각의 추측한 수끼리 간격을 두고 보여진다.</li> + <li>다음 블록도 함번 살펴보자(8-24번 줄) + <ul> + <li>첫 <code>if(){ }</code> 는 처음에 지정한 <code>randomNumber</code>과 사용자가 추측한 값(<code>userGuess</code>)이 값은지 본다. 참이라고 계산되면, 플레이어는 숫자를 맞춘것이고 게임을 이기게 된다. 따라서 플레이어에게 초록색, 인포메이션 박스로 축하메시지를 보여주고, 게임을 더할지와 관련된 <code>setGameOver() </code>함수를 불러온다.</li> + <li>이제 <code>else if(){ }</code> 구조를 사용하여 다른 조건문을 추가하게 된다. 이 조건은 사용자가 마지막 순서인지를 계산한다. 참이라면 프로그램은 이전과 같은 블록을 실행한다. 대신 게임을 이기지는 않았기 때문에 축하메시지를 제외된다</li> + <li>마지막 블록은 (the <code>else { }</code>)로 앞선 두 개의 조건이 모두 거짓일 때 실행된다. (i.e. 숫자를 맞추지도 못하고 차례가 남았을 때). 이 경우, 틀렸음을 알려주고, 정답보다 숫자가 큰지 작은지도 계산하여 적절한 메시지를 표시하도록 한다.</li> + </ul> + </li> + <li>함수상의 마지막 3줄(26-28번 줄)은 다음 숫자 추측을 위한 것이다. guessCount 변수에 1을 더함으로, 사용자의 차례가 지나갔음을 안다. (<code>++</code>이란 증감연사자이다. - 1을 더함). 그리고 값에 상관없이 텍스트필드를 공란으로 만들고, 커서를 위치시키므로, 다음값이 입력될 수 있도록 한다.</li> +</ul> + +<h3 id="이벤트">이벤트</h3> + +<p>여기서 우리는 <code>checkGuess()</code> 함수를 잘 구현해 보았지만, 아직 호출하지 않았기 때문에 아무런 역할을 하지 않는다. 실제로는 "Submit guess" 버튼이 눌러져야 호출받도록 할 것이므로, 이벤트를 사용해서 구현할 것이다. 이벤트란 버튼을 클릭하고, 페이지가 로딩되고, 비디오가 실행되는 등 코드가 실행되기 위한 응답으로 브라우저상에서 일어나는 액션이다. 이벤트가 발생하여 발생된 이벤트를 처리하는 것을 <strong>이벤트 리스너(event listeners)</strong>라 하고, 이벤트가 발생했을 때 실행되는 코드 블록을 <strong>이벤트 핸들러(event handlers)</strong>라고 한다.</p> + +<p><code>checkGuess()</code>함수의 중괄호가 끝난뒤, 다음의 코드를 추가해보자.</p> + +<pre class="brush: js">guessSubmit.addEventListener('click', checkGuess);</pre> + +<p><code>이는 guessSubmit</code> 버튼에 이벤트 리스너를 추가하는 과정이다. 두개의 입력(인수)를 가지는 <code>addEventListner</code>메소드이다. 문자열로서 클릭을 처리하는 이벤트이고, 이벤트가 발생했을 때 실행하고자 하는 코드는 <code>checkGuess()</code> 함수이다. 특히, {{domxref("EventTarget.addEventListener", "addEventListener()")}}안에서는 함수의 괄호가 필요없다는 것에 주의하자.</p> + +<p>코드를 저장하고 새로고침해보자, 예제가 실행됨을 볼 수 있다. 아직 게임이 종료되면 실행되는 setGameOver() 함수가 정의되지 않았으므로, 정답을 맞췄을때나 추측에 상관없이 실행되었다면 프로그램의 실행이 멈춰야 한다. 필요한 코드를 작성하고 함수를 추가해보자.</p> + +<h3 id="함수로_프로그램_종료하기">함수로 프로그램 종료하기</h3> + +<p><code>setGameOver()</code>함수를 코드 아래쪽에 추가하고 살펴보자. 자바크스립트 코드의 맨 마지막에 추가하도록 하자.</p> + +<pre class="brush: js">function setGameOver() { + guessField.disabled = true; + guessSubmit.disabled = true; + resetButton = document.createElement('button'); + resetButton.textContent = 'Start new game'; + document.body.appendChild(resetButton); + resetButton.addEventListener('click', resetGame); +}</pre> + +<ul> + <li>2-3번 줄은 텍스트 입력과 버튼의 diabled 속성을 true로 함으로써 작동되지 않도록 한다. 그렇지 않다면 사용자들이 게임이 종료된 후에도 계속 정답을 제출할 것이기 때문에 필수적이다. </li> + <li>4-6번 줄은 새로운 {{htmlelement("button")}} 엘리먼트를 생성하고, "Start new game"라고 표시되게 지정하고 현재의 HTML 아래쪽에 추가하도록 한다.</li> + <li>7번 줄은 새 버튼으로 하여금 이벤트 리스너를 지정하여 클릭되면 <code>resetGame() </code>함수가 실행되도록 한다.</li> +</ul> + +<p>물론 이 함수도 정의해야 한다. 또다시 코드의 가장 아래에 다음 코드를 추가하자.</p> + +<pre class="brush: js">function resetGame() { + guessCount = 1; + + var resetParas = document.querySelectorAll('.resultParas p'); + for (var i = 0 ; i < resetParas.length ; i++) { + resetParas[i].textContent = ''; + } + + resetButton.parentNode.removeChild(resetButton); + + guessField.disabled = false; + guessSubmit.disabled = false; + guessField.value = ''; + guessField.focus(); + + lastResult.style.backgroundColor = 'white'; + + randomNumber = Math.floor(Math.random() * 100) + 1; +}</pre> + +<p>앞서 보는 함수 블록 코드는 게임이 어떻게 시작되고 사용자가 다시 시작할 수 있도록 초기화하는 코드이다.</p> + +<ul> + <li><code>guessCount 변수를 1로 한다.</code></li> + <li>표시된 정보를 모두 초기화한다.</li> + <li>코드상에서 초기화 버튼을 제거한다.</li> + <li>폼 작성을 위해 텍스트를 입력하는 곳을 비워놓고 커서를 위치시킨다.</li> + <li><code>lastResult</code>변수 상의 문장<code> </code>배경색을 제거한다.</li> + <li>임의의 수를 다시 지정함으로, 앞썬 <code>randomNumber</code>와 겹치지 않도록 다시 설정한다.</li> +</ul> + +<p><strong>축하한다! 이제 여기까지 완료됬다면 프로그램이 정상적으로 작동될 것이다.</strong></p> + +<p>이제 살펴볼 것은 코드에서 볼 수 있는 중요한 부분중 하나이다.</p> + +<h3 id="반복문">반복문</h3> + +<p>위 코드상에서 자세히 살펴볼 것 중 하나는 <a href="/en-US/docs/Web/JavaScript/Reference/Statements/for">for</a> 반복문에 관한 부분이다. 반복문은 프로그래머가 지정한 코드의 부분을 조건에 부합할때까지 계속 실행시키는 등 프로그래밍에서 중요한 개념 중 하나이다.</p> + +<p>시작에 앞서, <a href="/en-US/docs/Learn/Common_questions/What_are_browser_developer_tools">browser developer tools JavaScript console</a>에 들어가서, 다음을 입력해보자.</p> + +<pre class="brush: js">for (var i = 1 ; i < 21 ; i++) { console.log(i) }</pre> + +<p>어떤 일이 일어났는가? 숫자 1부터 20까지 차례대로 콘솔창에 표시됨을 볼 수 있다.이는 반복이라는 컨셉 때문이다. for 반복문에는 세 개의 입력값(아규먼트)이 있다.</p> + +<ol> + <li><strong>시작값</strong>: 위 코드에서는 1부터 시작하였지만, 프로그래머 임의대로 지정할 수 있다. i 대신 다른 변수를 사용할 수 있지만, 짧고 기억하기 쉬운 관습으로 인해 간단한 알파벳 i가 주로 사용된다.</li> + <li><strong>종료 조건</strong>: 여기서는 <code>i < 21 라고 명시되었다. 이는 i가 21보다 작을때까지 반복이 이루어진다는 말이다. i가 21이 되었을 때, 반복은 종료된다.</code></li> + <li><strong>증감식</strong>: <code>i++이라 명시된 것은 i에 1씩 더하라는 의미이다.반복은 i의 값에 따라 i가 21이 될때까지 반복된다</code>. 여기서는 {{domxref("Console.log", "console.log()")}} 를 사용하여 콘솔창에 반복적으로 i의 값을 출력시키는 간단한 예제를 보였다.</li> +</ol> + +<p>숫자 맞추기 프로그램의 앞선 <code>resetGame()</code> 함수에서 반복문을 한 번 살펴보자.</p> + +<pre class="brush: js">var resetParas = document.querySelectorAll('.resultParas p'); +for (var i = 0 ; i < resetParas.length ; i++) { + resetParas[i].textContent = ''; +}</pre> + +<p>이 코드에서는 {{domxref("Document.querySelectorAll", "querySelectorAll()")}} 메소드를 사용하여 <code><div class="resultParas"></code>안의 모든 문장들의 배열을 변수로 만들고 있다. 그러고 반복을 통해 각각의 배열 원소에 접근하여, 내용을 제거하게 된다.</p> + +<h3 id="객체에_대한_간단한_고찰">객체에 대한 간단한 고찰</h3> + +<p>이제 마지막으로 한단계 더 나아갈 수 있는 부분을 배워보자. <code>var resetButton; </code>아래에 다음 코드를 추가해보자.(코드 위쪽에 있으니 참고하고, 저장까지 해보자)</p> + +<pre class="brush: js">guessField.focus();</pre> + +<p>여기서는 {{domxref("HTMLElement.focus", "focus()")}} 메소드를 통해 자동으로 커서를 페이지가 뜨자마자 {{htmlelement("input")}} 텍스트 필드에 위치시킬 수 있기때문에, 사용자가 처음에 폼 필드를 클릭할 필요없이 바로 글을 쓸 수 있게 된다. 아무것도 아닌 것처럼 보이지만, 사용자에게 굉장히 편리함을 주기 때문에 프로그램에서 좋은 효과를 가져다 준다.</p> + +<p>여기서 이루어지는 일들을 좀 더 자세히 분석해보자. 자바스크립트에서는 모든 것이 객체이다. 객체란 하나의 그룹안에 관계되는 기능(함수)들을 모아놓은 것이다.혼자서 객체를 생성할 수 있겠지만, 아직은 이르기 때문에 나중에 살펴보자. 지금은 간단히 브라우저에 내장된 객체를 사용함으로서 좀 더 많은 일들을 해보는 것에 중점을 두자.</p> + +<p><code><font face="Open Sans, Arial, sans-serif">여기서는, 먼저 HTML의 입력 폼 필드의 정보를 저장하는 </font>guessField</code> 변수를 생성해보자. (다음 코드는 맨 위의 변수 선언문에서 볼 수 있다.)</p> + +<pre class="brush: js">var guessField = document.querySelector('.guessField');</pre> + +<p>이 정보를 얻기 위해, {{domxref("document")}} 객체의 {{domxref("document.querySelector", "querySelector()")}}메소드를 사용한다. <code>querySelector()는 특정 정보(필요한 요소를 추출하는 </code><a href="/en-US/docs/Learn/CSS/Introduction_to_CSS/Selectors">CSS selector</a>)<code>를 가져오는 역할을 한다.</code></p> + +<p><code>이제 </code>{{htmlelement("input")}} 요소의 정보를 담고 있기 때문에, 속성(기본적으로 객체안의 변수나 변수 변경이 없는 경우)과 메소드(기본적으로 객체안의 함수)를 접근할 수 있게 된다. 입력 요소에 이용 가능한 메소드 중 하나가 <code>focus()이며</code>, 따라서 이 메소드를 통해 텍스트 입력에 커서를 가져다 놓을 수 있는 것이다.</p> + +<pre class="brush: js">guessField.focus();</pre> + +<p>폼 요소의 정보를 가지고 있지 않은 변수는 <code>focus()</code> 를 사용할 수 없다. 예를 들어, <code>guesses </code>변수는 {{htmlelement("p")}} 요소의 정보를 가지고 있고, <code>guessCount</code> 변수는 단순한 숫자를 포함하고 있다.</p> + +<h3 id="브라우저_객체로_다루기">브라우저 객체로 다루기</h3> + +<p>이제 브라우저를 객체로서 다뤄보자.</p> + +<ol> + <li>먼저, 브라우저에서 프로그램을 연다</li> + <li>다음 <a href="/en-US/docs/Learn/Common_questions/What_are_browser_developer_tools">browser developer tools</a>을 실행하고, 자바스크립트 콘솔창을 활성화한다.</li> + <li> <code>guessField</code>의 입력과 콘솔에서 {{htmlelement("input")}} 요소를 포함한 변수를 보여줄 것이다. 변수를 포함한 실행환경 상에 존재하는 객체이름을 콘솔이 자동으로 완성하는 것도 알아야한다.</li> + <li>다음 코드를 입력하자 + <pre class="brush: js">guessField.value = 'Hello';</pre> + <code>value</code> 속성은 텍스트 필드를 통해 입력되는 현재값을 나타낸다. 커맨드 창에 입력하고 어떤 일이 일어나는지 살펴보자.</li> + <li><code>guesses</code>에 입력하고 반환값을 살펴보자. 콘솔 창에서 변수가 {{htmlelement("p")}} 요소가 있음을 보여줄 것이다.</li> + <li>다음 코드를 입력하자. + <pre class="brush: js">guesses.value</pre> + 브라우저에서 아무런 문장이 없기 때문에, undefined라고 리턴될 것이다.</li> + <li>대신, 다음 코드에서 문자를 변경/추가하기 위해서는 {{domxref("Node.textContent", "textContent")}} 속성을 사용한다. + <pre class="brush: js">guesses.textContent = 'Where is my paragraph?';</pre> + </li> + <li>그러면 이제 다양한 작업을 할 수 있으니, 하나하나 시도해보자. + <pre class="brush: js">guesses.style.backgroundColor = 'yellow'; +guesses.style.fontSize = '200%'; +guesses.style.padding = '10px'; +guesses.style.boxShadow = '3px 3px 6px black';</pre> + 페이지의 모든 요소들을 <code>style</code> 속성을 가지고 있기때문에, 모든 요소에 적용가능한 인라인 CSS 스타일을 포함한 속성을 가진 객체를 포함하고 있음을 알 수 있다. 이는 자바스크립트 상에서 CSS 스타일을 동적으로 지정할 수 있음을 알 수 있다.</li> +</ol> + +<h2 id="결론">결론</h2> + +<p>여기까지 예제를 빌드해보는 과정이었다. 마지막으로 작성된 코드를 실행해보거나,<a href="http://mdn.github.io/learning-area/javascript/introduction-to-js-1/first-splash/number-guessing-game.html">play with our finished version here</a>. 만약 코드가 실행되지 않는다면, <a href="https://github.com/mdn/learning-area/blob/master/javascript/introduction-to-js-1/first-splash/number-guessing-game-start.html">source code</a>를 참고하자.</p> + +<p>{{PreviousMenuNext("Learn/JavaScript/First_steps/What_is_JavaScript", "Learn/JavaScript/First_steps/What_went_wrong", "Learn/JavaScript/First_steps")}}</p> diff --git a/files/ko/learn/javascript/first_steps/arrays/index.html b/files/ko/learn/javascript/first_steps/arrays/index.html new file mode 100644 index 0000000000..0cc11ca43f --- /dev/null +++ b/files/ko/learn/javascript/first_steps/arrays/index.html @@ -0,0 +1,664 @@ +--- +title: Arrays +slug: Learn/JavaScript/First_steps/Arrays +translation_of: Learn/JavaScript/First_steps/Arrays +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/JavaScript/First_steps/Useful_string_methods", "Learn/JavaScript/First_steps/Silly_story_generator", "Learn/JavaScript/First_steps")}}</div> + +<p class="summary">배열은 하나의 변수에 다수의 데이터를 저장하는 좋은 방법이며, 이 글에서 배열의 생성, 검색, 추가, 삭제 등과 같은 내용을 통해 배열에 대해 알아볼 것입니다.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">선행요소:</th> + <td>기초 컴퓨터 활용지식, HTML, CSS 그리고 JavaScript에 대한 기초 지식.</td> + </tr> + <tr> + <th scope="row">목적:</th> + <td>배열이 무엇인지 이해를 하고 JavaScript에서 어떻게 활용하는지 배운다.</td> + </tr> + </tbody> +</table> + +<h2 id="배열이란">배열이란?</h2> + +<p>배열은 다수의 변수들을 가지고 있는 하나의 객체이다("list-like objects"). 배열 객체는 변수에 저장 해서 사용 할 수 있고, 변수에 저장된 다른 값들과 거의 동일한 방식으로 쓸 수 있다. 일반적인 값들과 배열의 다른점은 내부의 값에 각각 접근할 수 있으며, 루프를 통해 매우 효율적으로 작업이 가능하다는 것이다. 예를 들어 우리가 흔히 보는 영수증의 제품목록, 가격 등이 배열이라고 볼 수 있으며 그 가격들의 총합을 루프를 통하여 구할 수 있다.</p> + +<p>만약 배열이 없다면 다수의 값이 있을 때 각 값의 하나의 변수에 일일이 저장해야 하는 문제가 생길 것이며, 해당 값들을 출력하거나 연산할 때 한땀한땀 개고생 해야한다. 이때문에 코드를 작성하는데 오래걸리며, 비효율적이고 실수를 할 가능성이 높아진다. 오늘 산 물건이 10개 정도라면 값을 더하는데 얼마 걸리지 않겠지만, 100개나 1000개 쯤 구입을 했다면? 잠은 다잔거다.</p> + +<p>이전에 배웠던 것처럼, JavaScript 콘솔에서 몇가지 예제를 통해 배열의 쌩기초 부터 알아보자. 아래에 우리가 제공하는 콘솔이 하나 있다.(<a href="https://mdn.github.io/learning-area/javascript/introduction-to-js-1/variables/index.html">이 콘솔</a>을 새 탭이나 창을 열어서 사용 하거나, 당신이 선호하는 <a href="/en-US/docs/Learn/Common_questions/What_are_browser_developer_tools">개발자 콘솔</a>을 사용하면된다.)</p> + +<div class="hidden"> +<h6 id="Hidden_code">Hidden code</h6> + +<pre class="brush: html"><!DOCTYPE html> +<html> + <head> + <meta charset="utf-8"> + <title>JavaScript console</title> + <style> + * { + box-sizing: border-box; + } + + html { + background-color: #0C323D; + color: #809089; + font-family: monospace; + } + + body { + max-width: 700px; + } + + p { + margin: 0; + width: 1%; + padding: 0 1%; + font-size: 16px; + line-height: 1.5; + float: left; + } + + .input p { + margin-right: 1%; + } + + .output p { + width: 100%; + } + + .input input { + width: 96%; + float: left; + border: none; + font-size: 16px; + line-height: 1.5; + font-family: monospace; + padding: 0; + background: #0C323D; + color: #809089; + } + + div { + clear: both; + } + + </style> + </head> + <body> + + + </body> + + <script> + var geval = eval; + function createInput() { + var inputDiv = document.createElement('div'); + var inputPara = document.createElement('p'); + var inputForm = document.createElement('input'); + + inputDiv.setAttribute('class','input'); + inputPara.textContent = '>'; + inputDiv.appendChild(inputPara); + inputDiv.appendChild(inputForm); + document.body.appendChild(inputDiv); + + if(document.querySelectorAll('div').length > 1) { + inputForm.focus(); + } + + inputForm.addEventListener('change', executeCode); + } + + function executeCode(e) { + try { + var result = geval(e.target.value); + } catch(e) { + var result = 'error — ' + e.message; + } + + var outputDiv = document.createElement('div'); + var outputPara = document.createElement('p'); + + outputDiv.setAttribute('class','output'); + outputPara.textContent = 'Result: ' + result; + outputDiv.appendChild(outputPara); + document.body.appendChild(outputDiv); + + e.target.disabled = true; + e.target.parentNode.style.opacity = '0.5'; + + createInput() + } + + createInput(); + + </script> +</html></pre> +</div> + +<p>{{ EmbedLiveSample('Hidden_code', '100%', 300, "", "", "hide-codepen-jsfiddle") }}</p> + +<h3 id="배열_만들기">배열 만들기</h3> + +<p>배열은 대괄호로 구성되며 쉼표로 구분 된 항목들을 포함합니다.</p> + +<ol> + <li>쇼핑 목록을 배열에 저장하고 싶다면 다음과 같이하면됩니다. 콘솔에 다음 행을 입력하십시오. + <pre class="brush: js">var shopping = ['bread', 'milk', 'cheese', 'hummus', 'noodles']; +shopping;</pre> + </li> + <li>아래 배열의 각 항목은 문자열이지만 배열의 모든 항목 (문자열, 숫자, 개체, 다른 변수, 심지어 다른 배열)을 저장할 수 있습니다. 동일한 형태의 항목만 넣거나(아래 sequence처럼) 다양한 형태의 항목을 함께 넣을수(아래 random 처럼) 있습니다. 모두 숫자, 문자열 등일 필요는 없습니다. 다음을 입력해보세요. + <pre class="brush: js">var sequence = [1, 1, 2, 3, 5, 8, 13]; +var random = ['tree', 795, [0, 1, 2]];</pre> + </li> + <li>다음으로 넘어가기 전 여러분 마음대로 배열을 만들어 보세요</li> +</ol> + +<h3 id="배열_항목의_접근과_수정">배열 항목의 접근과 수정 </h3> + +<p>그런 다음 <a href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/First_steps/Useful_string_methods#Retrieving_a_specific_string_character">문자열의 문자에 접근했던 것</a>과 같은 방법으로 괄호 표기법을 사용하여 배열의 개별 항목을 접근 할 수 있습니다.</p> + +<ol> + <li>콘솔에 다음을 입력하세요: + <pre class="brush: js">shopping[0]; +// returns "bread"</pre> + </li> + <li>단일 배열 항목에 새 값을 제공하여, 배열의 항목을 수정할 수도 있습니다.<br> + 한번 해보세요 : + <pre class="brush: js">shopping[0] = 'tahini'; +shopping; +// shopping will now return [ "tahini", "milk", "cheese", "hummus", "noodles" ]</pre> + + <div class="note"><strong>참고</strong>: 전에도 말했지만, 컴퓨터는 숫자를 셀때 0 부터 시작한다!</div> + </li> + <li>배열 내부의 배열을 다중배열이라고 합니다.대괄호 두개를 함께 연결하여 다른 배열 안에있는 배열 내부의 항목에 접근 할 수 있습니다.예를 들어 <code>무작위</code> 배열(<code>random</code> array) 안의 세 번째 항목 인 배열 내부 항목 중 하나에 접근하려면(앞 섹션 참조) 다음과 같이 할 수 있습니다.: + <pre class="brush: js">random[2][2];</pre> + </li> + <li>다음 단계로 넘어가기 전에 충분히 배열 예제를 연습해보세요.</li> +</ol> + +<h3 id="배열의_갯수_알아내기">배열의 갯수 알아내기</h3> + +<p>{{jsxref("Array.prototype.length","length")}} 속성을 사용해서 배열에 들어 있는 문자열의 갯수를 알아낼 수 있다.(갯수가 얼마나 많이 있던지) 다음을 보자.:</p> + +<pre class="brush: js">sequence.length; +// should return 7</pre> + +<p>다른 용도로 사용되기도 하는데, loop문으로 배열의 모든 항목을 반복적으로 값을 대입하는데 일반적으로 사용한다. 예를 들면:</p> + +<pre class="brush: js">var sequence = [1, 1, 2, 3, 5, 8, 13]; +for (var i = 0; i < sequence.length; i++) { + console.log(sequence[i]); +}</pre> + +<p>다음 article에서 반복문에 대해서 자세히 다루겠지만 다음과 같이 요약할 수 있다.</p> + +<ol> + <li>배열을 반복문으로 돌릴때 item의 시작번호는 0 입니다.</li> + <li>배열의 갯수와 같은 번호일때 반복문을 중단하세요. 어떤 길이의 배열에서도 반복문이 돌지만, 이 경우에선 반복문이 7번 돌고 멈춥니다.(반복문을 끝내기를 원하는 마지막 item의 숫자는 6입니다.)</li> + <li>각각의 item에 대해 <code>console.log()</code>을 사용해 브라우저 콘솔창으로 확인해보세요.</li> +</ol> + +<h2 id="유용한_배열_method">유용한 배열 method</h2> + +<p>이번 섹션에서는 문자열을 배열 항목으로 분할하고, 다시 배열 항목을 문자열로 변환하며 새로운 항목을 배열에 추가할 수 있는 배열 관련 method를 알아봅니다.</p> + +<h3 id="문자열을_배열로_배열을_문자열로_변환하기">문자열을 배열로, 배열을 문자열로 변환하기</h3> + +<p>프로그램을 만들다보면 종종 긴 문자열로 이루어진 원시 데이터를 제공받게 될 것이고, 원시 데이터를 정제하여 더 유용한 데이터를 추출해 테이블 형태로 표시하는 등 작업을 수행해야 합니다. 이러한 작업을 위해 {{jsxref("String.prototype.split()","split()")}} method를 사용할 수 있습니다. {{jsxref("String.prototype.split()","split()")}} method는 사용자가 원하는 매개변수로 문자열을 분리하여 배열로 표현해줍니다.</p> + +<div class="note"> +<p><strong>Note</strong>: 사실 String method이지만, 배열과 함께 사용하기 때문에 여기에 넣었습니다.</p> +</div> + +<ol> + <li>{{jsxref("String.prototype.split()","split()")}} method가 어떻게 작동하는지 살펴봅시다. 우선 콘솔에서 아래와 같은 문자열을 만듭니다: + <pre class="brush: js">var myData = 'Manchester,London,Liverpool,Birmingham,Leeds,Carlisle';</pre> + </li> + <li>콤마로 분리하기 위해 단일 매개변수를 집어넣습니다.: + <pre class="brush: js">var myArray = myData.split(','); +myArray;</pre> + </li> + <li>마지막으로 새로운 배열의 길이를 찾고 이 배열에서 몇 가지 항목을 검색해 봅니다.: + <pre class="brush: js">myArray.length; +myArray[0]; // the first item in the array +myArray[1]; // the second item in the array +myArray[myArray.length-1]; // the last item in the array</pre> + </li> + <li>또한 아래 방법처럼 {{jsxref("Array.prototype.join()","join()")}} method를 사용하여 배열을 다시 문자열로 만들 수 있습니다. : + <pre class="brush: js">var myNewString = myArray.join(','); +myNewString;</pre> + </li> + <li>배열을 문자열로 변환하는 또 다른 방법은 {{jsxref("Array.prototype.toString()","toString()")}} method를 사용하는 것 입니다. <code>toString()</code> 은 <code>join()</code> 과 달리 매개변수가 필요 없어서 더 간단하지만, 제한이 더 많습니다. <code>join()</code> 을 사용하면 다른 구분자를 지정할 수 있습니다. (콤마 말고 다른 매개변수를 사용하여 4단계를 실행 해보세요.) + <pre class="brush: js">var dogNames = ['Rocket','Flash','Bella','Slugger']; +dogNames.toString(); //Rocket,Flash,Bella,Slugger</pre> + </li> +</ol> + +<h3 id="배열에_item을_추가하고_제거하기">배열에 item을 추가하고 제거하기</h3> + +<p>이번엔 배열에 item을 추가하고 제거하는 방법을 알아볼 차례 입니다. 위에서 만든 <code>myArray</code> 를 다시 사용하겠습니다. 섹션을 순서대로 진행하지 않았다면 아래와 같은 배열을 만들어주세요.:</p> + +<pre class="brush: js">var myArray = ['Manchester', 'London', 'Liverpool', 'Birmingham', 'Leeds', 'Carlisle'];</pre> + +<p>먼저, 배열의 맨 끝에 item을 추가하거나 제거하기 위해 각각{{jsxref("Array.prototype.push()","push()")}} and {{jsxref("Array.prototype.pop()","pop()")}} 를 사용할 수 있습니다.</p> + +<ol> + <li>먼저 <code>push()</code> 를 사용합니다. — 배열의 끝에 추가할 item을 반드시 하나 이상 포함해야 한다는 점을 기억하고 아래와 같이 따라해보세요: + + <pre class="brush: js">myArray.push('Cardiff'); +myArray; +myArray.push('Bradford', 'Brighton'); +myArray; +</pre> + </li> + <li>method 호출이 완료되면 배열의 item이 변한것을 확인할 수 있습니다. 새로운 변수에 배열을 저장하려면 아래와 같이 사용합니다.: + <pre class="brush: js">var newLength = myArray.push('Bristol'); +myArray; +newLength;</pre> + </li> + <li>배열의 마지막 item을 제거하는 방법은 <code>pop()</code>으로 매우 간단합니다. 아래와 같이 따라해보세요: + <pre class="brush: js">myArray.pop();</pre> + </li> + <li>method호출이 완료되면 배열에서 item이 제거된 것을 확인할 수 있습니다. 아래 방법을 사용하여 제거될 item을 변수에 저장할 수 있습니다.: + <pre class="brush: js">var removedItem = myArray.pop(); +myArray; +removedItem;</pre> + </li> +</ol> + +<p>{{jsxref("Array.prototype.unshift()","unshift()")}} 와{{jsxref("Array.prototype.shift()","shift()")}}는 <code>push()</code> 와 <code>pop()</code>과 유사하게 동작합니다. 다만, 배열의 맨 끝이 아닌 제일 처음 부분의 item을 추가하거나 제거합니다..</p> + +<ol> + <li>먼저 <code>unshift()</code> 를 사용해봅니다.: + + <pre class="brush: js">myArray.unshift('Edinburgh'); +myArray;</pre> + </li> + <li>이제 <code>shift()</code>를 사용해봅니다.! + <pre class="brush: js">var removedItem = myArray.shift(); +myArray; +removedItem;</pre> + </li> +</ol> + +<h2 id="Active_learning_Printing_those_products!">Active learning: Printing those products!</h2> + +<p>Let's return to the example we described earlier — printing out product names and prices on an invoice, then totaling the prices and printing them at the bottom. In the editable example below there are comments containing numbers — each of these marks a place where you have to add something to the code. They are as follows:</p> + +<ol> + <li>Below the <code>// number 1</code> comment are a number of strings, each one containing a product name and price separated by a colon. We'd like you to turn this into an array and store it in an array called <code>products</code>.</li> + <li>On the same line as the <code>// number 2</code> comment is the beginning of a for loop. In this line we currently have <code>i <= 0</code>, which is a conditional test that causes the <a href="/en-US/Learn/JavaScript/First_steps/A_first_splash#Loops">for loop</a> to stop immediately, because it is saying "stop when <code>i</code> is no longer less than or equal to 0", and <code>i</code> starts at 0. We'd like you to replace this with a conditional test that stops the loop when <code>i</code> is no longer less than the <code>products</code> array's length.</li> + <li>Just below the <code>// number 3</code> comment we want you to write a line of code that splits the current array item (<code>name:price</code>) into two separate items, one containing just the name and one containing just the price. If you are not sure how to do this, consult the <a href="/en-US/docs/Learn/JavaScript/First_steps/Useful_string_methods">Useful string methods</a> article for some help, or even better, look at the {{anch("Converting between strings and arrays")}} section of this article.</li> + <li>As part of the above line of code, you'll also want to convert the price from a string to a number. If you can't remember how to do this, check out the <a href="/en-US/Learn/JavaScript/First_steps/Strings#Numbers_versus_strings">first strings article</a>.</li> + <li>There is a variable called <code>total</code> that is created and given a value of 0 at the top of the code. Inside the loop (below <code>// number 4</code>) we want you to add a line that adds the current item price to that total in each iteration of the loop, so that at the end of the code the correct total is printed onto the invoice. You might need an <a href="/en-US/Learn/JavaScript/First_steps/Math#Assignment_operators">assignment operator</a> to do this.</li> + <li>We want you to change the line just below <code>// number 5</code> so that the <code>itemText</code> variable is made equal to "current item name — $current item price", for example "Shoes — $23.99" in each case, so the correct information for each item is printed on the invoice. This is just simple string concatenation, which should be familiar to you.</li> +</ol> + +<div class="hidden"> +<h6 id="Playable_code">Playable code</h6> + +<pre class="brush: html"><h2>Live output</h2> + +<div class="output" style="min-height: 150px;"> + +<ul> + +</ul> + +<p></p> + +</div> + +<h2>Editable code</h2> + +<p class="a11y-label">Press Esc to move focus away from the code area (Tab inserts a tab character).</p> + +<textarea id="code" class="playable-code" style="height: 410px;width: 95%"> +var list = document.querySelector('.output ul'); +var totalBox = document.querySelector('.output p'); +var total = 0; +list.innerHTML = ''; +totalBox.textContent = ''; +// number 1 + 'Underpants:6.99' + 'Socks:5.99' + 'T-shirt:14.99' + 'Trousers:31.99' + 'Shoes:23.99'; + +for (var i = 0; i <= 0; i++) { // number 2 + // number 3 + + // number 4 + + // number 5 + itemText = 0; + + var listItem = document.createElement('li'); + listItem.textContent = itemText; + list.appendChild(listItem); +} + +totalBox.textContent = 'Total: $' + total.toFixed(2); +</textarea> + +<div class="playable-buttons"> + <input id="reset" type="button" value="Reset"> + <input id="solution" type="button" value="Show solution"> +</div> +</pre> + +<pre class="brush: js">var textarea = document.getElementById('code'); +var reset = document.getElementById('reset'); +var solution = document.getElementById('solution'); +var code = textarea.value; +var userEntry = textarea.value; + +function updateCode() { + eval(textarea.value); +} + +reset.addEventListener('click', function() { + textarea.value = code; + userEntry = textarea.value; + solutionEntry = jsSolution; + solution.value = 'Show solution'; + updateCode(); +}); + +solution.addEventListener('click', function() { + if(solution.value === 'Show solution') { + textarea.value = solutionEntry; + solution.value = 'Hide solution'; + } else { + textarea.value = userEntry; + solution.value = 'Show solution'; + } + updateCode(); +}); + +var jsSolution = 'var list = document.querySelector(\'.output ul\');\nvar totalBox = document.querySelector(\'.output p\');\nvar total = 0;\nlist.innerHTML = \'\';\ntotalBox.textContent = \'\';\n\nvar products = [\'Underpants:6.99\',\n \'Socks:5.99\',\n \'T-shirt:14.99\',\n \'Trousers:31.99\',\n \'Shoes:23.99\'];\n\nfor(var i = 0; i < products.length; i++) {\n var subArray = products[i].split(\':\');\n var name = subArray[0];\n var price = Number(subArray[1]);\n total += price;\n itemText = name + \' — $\' + price;\n\n var listItem = document.createElement(\'li\');\n listItem.textContent = itemText;\n list.appendChild(listItem);\n}\n\ntotalBox.textContent = \'Total: $\' + total.toFixed(2);'; +var solutionEntry = jsSolution; + +textarea.addEventListener('input', updateCode); +window.addEventListener('load', updateCode); + +// stop tab key tabbing out of textarea and +// make it write a tab at the caret position instead + +textarea.onkeydown = function(e){ + if (e.keyCode === 9) { + e.preventDefault(); + insertAtCaret('\t'); + } + + + if (e.keyCode === 27) { + textarea.blur(); + } +}; + +function insertAtCaret(text) { + var scrollPos = textarea.scrollTop; + var caretPos = textarea.selectionStart; + + var front = (textarea.value).substring(0, caretPos); + var back = (textarea.value).substring(textarea.selectionEnd, textarea.value.length); + textarea.value = front + text + back; + caretPos = caretPos + text.length; + textarea.selectionStart = caretPos; + textarea.selectionEnd = caretPos; + textarea.focus(); + textarea.scrollTop = scrollPos; +} + +// Update the saved userCode every time the user updates the text area code + +textarea.onkeyup = function(){ + // We only want to save the state when the user code is being shown, + // not the solution, so that solution is not saved over the user code + if(solution.value === 'Show solution') { + userEntry = textarea.value; + } else { + solutionEntry = textarea.value; + } + + updateCode(); +};</pre> + +<pre class="brush: css">html { + font-family: sans-serif; +} + +h2 { + font-size: 16px; +} + +.a11y-label { + margin: 0; + text-align: right; + font-size: 0.7rem; + width: 98%; +} + +body { + margin: 10px; + background-color: #f5f9fa; +}</pre> +</div> + +<p>{{ EmbedLiveSample('Playable_code', '100%', 730, "", "", "hide-codepen-jsfiddle") }}</p> + +<h2 id="실습_Top_5_searches">실습: Top 5 searches</h2> + +<p>A good use for array methods like {{jsxref("Array.prototype.push()","push()")}} and {{jsxref("Array.prototype.pop()","pop()")}} is when you are maintaining a record of currently active items in a web app. In an animated scene for example, you might have an array of objects representing the background graphics currently displayed, and you might only want 50 displayed at once, for performance or clutter reasons. As new objects are created and added to the array, older ones can be deleted from the array to maintain the desired number.</p> + +<p>In this example we're going to show a much simpler use — here we're giving you a fake search site, with a search box. The idea is that when terms are entered in the search box, the top 5 previous search terms are displayed in the list. When the number of terms goes over 5, the last term starts being deleted each time a new term is added to the top, so the 5 previous terms are always displayed.</p> + +<div class="note"> +<p><strong>Note</strong>: In a real search app, you'd probably be able to click the previous search terms to return to previous searches, and it would display actual search results! We are just keeping it simple for now.</p> +</div> + +<p>To complete the app, we need you to:</p> + +<ol> + <li>Add a line below the <code>// number 1</code> comment that adds the current value entered into the search input to the start of the array. This can be retrieved using <code>searchInput.value</code>.</li> + <li>Add a line below the <code>// number 2</code> comment that removes the value currently at the end of the array.</li> +</ol> + +<div class="hidden"> +<h6 id="Playable_code_2">Playable code 2</h6> + +<pre class="brush: html"><h2>Live output</h2> +<div class="output" style="min-height: 150px;"> + +<input type="text"><button>Search</button> + +<ul> + +</ul> + +</div> + +<h2>Editable code</h2> + +<p class="a11y-label">Press Esc to move focus away from the code area (Tab inserts a tab character).</p> + + +<textarea id="code" class="playable-code" style="height: 370px; width: 95%"> +var list = document.querySelector('.output ul'); +var searchInput = document.querySelector('.output input'); +var searchBtn = document.querySelector('.output button'); + +list.innerHTML = ''; + +var myHistory = []; + +searchBtn.onclick = function() { + // we will only allow a term to be entered if the search input isn't empty + if (searchInput.value !== '') { + // number 1 + + // empty the list so that we don't display duplicate entries + // the display is regenerated every time a search term is entered. + list.innerHTML = ''; + + // loop through the array, and display all the search terms in the list + for (var i = 0; i < myHistory.length; i++) { + itemText = myHistory[i]; + var listItem = document.createElement('li'); + listItem.textContent = itemText; + list.appendChild(listItem); + } + + // If the array length is 5 or more, remove the oldest search term + if (myHistory.length >= 5) { + // number 2 + + } + + // empty the search input and focus it, ready for the next term to be entered + searchInput.value = ''; + searchInput.focus(); + } +} +</textarea> + +<div class="playable-buttons"> + <input id="reset" type="button" value="Reset"> + <input id="solution" type="button" value="Show solution"> +</div></pre> + +<pre class="brush: css">html { + font-family: sans-serif; +} + +h2 { + font-size: 16px; +} + +.a11y-label { + margin: 0; + text-align: right; + font-size: 0.7rem; + width: 98%; +} + +body { + margin: 10px; + background: #f5f9fa; +}</pre> + +<pre class="brush: js">var textarea = document.getElementById('code'); +var reset = document.getElementById('reset'); +var solution = document.getElementById('solution'); +var code = textarea.value; +var userEntry = textarea.value; + +function updateCode() { + eval(textarea.value); +} + +reset.addEventListener('click', function() { + textarea.value = code; + userEntry = textarea.value; + solutionEntry = jsSolution; + solution.value = 'Show solution'; + updateCode(); +}); + +solution.addEventListener('click', function() { + if(solution.value === 'Show solution') { + textarea.value = solutionEntry; + solution.value = 'Hide solution'; + } else { + textarea.value = userEntry; + solution.value = 'Show solution'; + } + updateCode(); +}); + +var jsSolution = 'var list = document.querySelector(\'.output ul\');\nvar searchInput = document.querySelector(\'.output input\');\nvar searchBtn = document.querySelector(\'.output button\');\n\nlist.innerHTML = \'\';\n\nvar myHistory= [];\n\nsearchBtn.onclick = function() {\n if(searchInput.value !== \'\') {\n myHistory.unshift(searchInput.value);\n\n list.innerHTML = \'\';\n\n for(var i = 0; i < myHistory.length; i++) {\n itemText = myHistory[i];\n var listItem = document.createElement(\'li\');\n listItem.textContent = itemText;\n list.appendChild(listItem);\n }\n\n if(myHistory.length >= 5) {\n myHistory.pop();\n }\n\n searchInput.value = \'\';\n searchInput.focus();\n }\n}'; +var solutionEntry = jsSolution; + +textarea.addEventListener('input', updateCode); +window.addEventListener('load', updateCode); + +// stop tab key tabbing out of textarea and +// make it write a tab at the caret position instead + +textarea.onkeydown = function(e){ + if (e.keyCode === 9) { + e.preventDefault(); + insertAtCaret('\t'); + } + + if (e.keyCode === 27) { + textarea.blur(); + } +}; + +function insertAtCaret(text) { + var scrollPos = textarea.scrollTop; + var caretPos = textarea.selectionStart; + + var front = (textarea.value).substring(0, caretPos); + var back = (textarea.value).substring(textarea.selectionEnd, textarea.value.length); + textarea.value = front + text + back; + caretPos = caretPos + text.length; + textarea.selectionStart = caretPos; + textarea.selectionEnd = caretPos; + textarea.focus(); + textarea.scrollTop = scrollPos; +} + +// Update the saved userCode every time the user updates the text area code + +textarea.onkeyup = function(){ + // We only want to save the state when the user code is being shown, + // not the solution, so that solution is not saved over the user code + if(solution.value === 'Show solution') { + userEntry = textarea.value; + } else { + solutionEntry = textarea.value; + } + + updateCode(); +};</pre> +</div> + +<p>{{ EmbedLiveSample('Playable_code_2', '100%', 700, "", "", "hide-codepen-jsfiddle") }}</p> + +<h2 id="결론">결론</h2> + +<p>위에 글 읽어보니, 배열이 꽤 유용해 보인다는거 알꺼임; JavaScript에서 배열은 겁나 많이 쓰인다. 배열의 모든 항목 마다 똑같은 작업을 수행하려고 루프(loop)를 돌리니까 같이 알아놓으면 개꿀. 다음 모듈(챕터)에서 루프(loop)에 관한 기초부터 알려줄꺼니까 쫄지 말고 달려. 갈 길이 멀다. 이 모듈은 이제 다 봤어!</p> + +<p>이제 여기서 남은건 이 모듈의 평가뿐이야. 앞에 보여준 글(articles)을 얼마나 이해 했는지 테스트 할꺼임.</p> + +<h2 id="참고">참고</h2> + +<ul> + <li><a href="/en-US/docs/Web/JavaScript/Guide/Indexed_collections">Indexed collections</a> — an advanced level guide to arrays and their cousins, typed arrays.</li> + <li>{{jsxref("Array")}} — the <code>Array</code> object reference page — for a detailed reference guide to the features discussed in this page, and many more.</li> +</ul> + +<p>{{PreviousMenuNext("Learn/JavaScript/First_steps/Useful_string_methods", "Learn/JavaScript/First_steps/Silly_story_generator", "Learn/JavaScript/First_steps")}}</p> + +<h2 id="이번_모듈에서_배울것들">이번 모듈에서 배울것들</h2> + +<ul> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/What_is_JavaScript">JavaScript란 무엇인가?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/A_first_splash">JavaScript를 시작해보자</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/What_went_wrong">뭐가 잘못 되었지? Troubleshooting JavaScript(잘못된 걸 고쳐보자)</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Variables">원하는 정보를 저장하기 — 변</a>수</li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Math">JavaScript의 수학 기초 — 숫자와 연산자</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Strings">문자 다루기 — JavaScript에서의 문자</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Useful_string_methods">유용한 문자 메소드</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Arrays">배열</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Silly_story_generator">평가: 짧은 글 랜덤 생성기</a></li> +</ul> diff --git a/files/ko/learn/javascript/first_steps/index.html b/files/ko/learn/javascript/first_steps/index.html new file mode 100644 index 0000000000..42f6e67418 --- /dev/null +++ b/files/ko/learn/javascript/first_steps/index.html @@ -0,0 +1,60 @@ +--- +title: JavaScript 첫걸음 +slug: Learn/JavaScript/First_steps +tags: + - Article + - Beginner + - CodingScripting + - Guide + - JavaScript + - Landing + - 'l10n:priority' +translation_of: Learn/JavaScript/First_steps +--- +<div>{{LearnSidebar}}</div> + +<p class="summary">첫 과정에서는 "JavaScript가 뭔가요?", "어떻게 생겼나요?", "뭘 할 수 있나요?"와 같은 근본적인 질문을 먼저 해결한 뒤에 JavaScript를 직접 사용해봅니다. 그 다음으로는 변수, 문자열, 숫자, 배열 등 중요한 구성 성분을 하나씩 자세히 알아봅니다.</p> + +<h2 id="준비_과정">준비 과정</h2> + +<p>이번 과정을 시작하기 전에 JavaScript에 대해 몰라도 되지만, HTML, CSS와는 어느 정도 친숙해야 합니다. 우선 다음 과정부터 진행하시는게 좋습니다.</p> + +<ul> + <li><a href="https://developer.mozilla.org/ko/docs/Learn/Getting_started_with_the_web">Web으로 시작하기</a> (아주 기본적인 <a href="/ko/docs/Learn/Getting_started_with_the_web/JavaScript_basics">JavaScript 소개</a>도 포함)</li> + <li><a href="/ko/docs/Learn/HTML/Introduction_to_HTML">HTML 소개</a></li> + <li><a href="/ko/docs/Learn/CSS/Introduction_to_CSS">CSS 소개</a></li> +</ul> + +<div class="note"> +<p><strong>참고</strong>: 파일을 만들 수 없는 컴퓨터나 태블릿, 기타 장치에서 작업을 하신다면 예제 코드의 대부분을 <a href="https://jsbin.com">JSBin</a>이나 <a href="https://thimble.mozilla.org/">Thimble</a> 같은 온라인 코딩 프로그램에서도 시험할 수 있습니다.</p> +</div> + +<h2 id="구성">구성</h2> + +<dl> + <dt><a href="/ko/docs/Learn/JavaScript/First_steps/What_is_JavaScript">JavaScript가 뭔가요?</a></dt> + <dd>MDN의 JavaScript 초급자 과정에 오신 걸 환영합니다! 첫 글은 JavaScript를 넓게 보면서 "뭔가요?", "뭘 하나요?"와 같은 질문을 답변하고, 여러분이 JavaScript에 친숙해지도록 도와드립니다.</dd> + <dt><a href="/ko/docs/Learn/JavaScript/First_steps/A_first_splash">JavaScript에 발 담그기</a></dt> + <dd>JavaScript에 관한 이론과 용도를 약간 배우셨으니, 실용적인 따라해보기와 함께 하는 기초과정 단기 특강을 제공해드리겠습니다. 여기서는 간단한 "숫자 알아맞히기" 게임을 단계별로 차근차근 만들어봅니다.</dd> + <dt><a href="/ko/docs/Learn/JavaScript/First_steps/What_went_wrong">어떤게 잘못됐나요? JavaScript 문제해결</a></dt> + <dd>이전 글에서 "숫자 알아맞히기" 게임을 만든 뒤에, 프로그램이 돌아가지 않는다는 것을 발견하실 겁니다. 두려워하지 마세요. 세 번째 글에서 JavaScript 프로그램의 오류를 찾고 고치는 팁을 배울 수 있습니다.</dd> + <dt><a href="/ko/docs/Learn/JavaScript/First_steps/Variables">필요한 정보 저장하기 — 변수</a></dt> + <dd>앞선 글을 모두 읽으셨으면 이제 JavaScript가 뭔지, 뭘 할 수 있는지, 다른 웹 기술과 함께 어떻게 사용하는지, 주요 기능이 어떻게 생겼는지 등 넓은 윤곽을 그리실 수 있을겁니다. 이제 진짜 기초로 돌아가, JavaScript의 제일 기본적인 구성 요소를 어떻게 사용하는지 알아보겠습니다. 바로 변수입니다.</dd> + <dt><a href="/ko/docs/Learn/JavaScript/First_steps/Math">JavaScript의 기본 수학 — 숫자와 연산자</a></dt> + <dd>여기서는 JavaScript에서의 수학을 이야기하면서, 연산자와 다른 기능을 이리 저리 조합하여 숫자를 여러분의 뜻에 맞게 바꾸는 법을 배웁니다.</dd> + <dt><a href="/ko/docs/Learn/JavaScript/First_steps/Strings">텍스트 다루기 — 문자열</a></dt> + <dd>우리의 시선을 이제 문자열로 돌릴 차례입니다. 프로그래밍에서 텍스트를 일컫는 단어죠. 이번 글에서는 JavaScript를 배울 때 문자열에 대해 알아둬야 하는 것, 예를 들어 문자열 생성, 문자열 안의 따옴표 처리, 문자열 합치기 등을 알아봅니다.</dd> + <dt><a href="/ko/docs/Learn/JavaScript/First_steps/Useful_string_methods">유용한 문자열 메서드</a></dt> + <dd>문자열의 기초를 탐구했으니, 한 단계 더 나아가 문자열의 길이 찾기, 문자열 합치고 나누기, 문자를 다른 문자로 치환하기 등 내장 메서드로 할 수 있는 유용한 작업에 대해 생각해봅니다.</dd> + <dt><a href="/ko/docs/Learn/JavaScript/First_steps/Arrays">배열</a></dt> + <dd>본 과정의 마지막 글에서는 배열에 대해 알아봅니다. 배열은 하나의 변수 이름 아래에 여러 데이터 목록을 저장하는 깔끔한 방법입니다. 배열이 왜 유용한지, 배열을 어떻게 생성하는지, 저장한 데이터를 회수하고, 추가하고, 제거하는 법 등을 배웁니다.</dd> +</dl> + +<h2 id="평가">평가</h2> + +<p>다음 평가를 통해 JavaScript의 기초를 얼마나 이해했는지 시험할 수 있습니다.</p> + +<dl> + <dt><a href="/ko/docs/Learn/JavaScript/First_steps/Silly_story_generator">바보같은 이야기 생성기</a></dt> + <dd>각자 배운 내용을 돌이켜보면서, 바보같은 이야기를 무작위로 만들어내는 앱을 제작해야 합니다. 행운을 빌어요!</dd> +</dl> diff --git a/files/ko/learn/javascript/first_steps/math/index.html b/files/ko/learn/javascript/first_steps/math/index.html new file mode 100644 index 0000000000..b240481e50 --- /dev/null +++ b/files/ko/learn/javascript/first_steps/math/index.html @@ -0,0 +1,422 @@ +--- +title: 자바스크립트의 기본적인 연산 - 숫자와 연산자 +slug: Learn/JavaScript/First_steps/Math +tags: + - 연산자 + - 자바스크립트 + - 진수 +translation_of: Learn/JavaScript/First_steps/Math +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/JavaScript/First_steps/Variables", "Learn/JavaScript/First_steps/Strings", "Learn/JavaScript/First_steps")}}</div> + +<p class="summary">이 장은 자바스크립트의 연산에 대해 다룹니다. 능숙하게 숫자를 다루기 위해 어떻게 {{Glossary("Operator","operators")}} 와 그 외 기능을 사용하는지 알아봅니다.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">필요조건:</th> + <td>기본적인 커퓨터 지식, HTML과 CSS에 대한 기본적인 이해, JavaScript의 이해</td> + </tr> + <tr> + <th scope="row">목표:</th> + <td>자바스크립트 연산에 익숙해지기</td> + </tr> + </tbody> +</table> + +<h2 id="모두가_수학을_좋아합니다">모두가 수학을 좋아합니다</h2> + +<p>좋아요, 아닐수도 있습니다. 일부는 좋아하겠죠. 몇몇 사람들은 구구단을 배울 때부터 싫어했을 겁니다. 그리고 몇몇은 이 사이 어딘가 있겠죠. 그러나 누구도 수학이 삶을 살아가는데 필수적 요소라는건 부정할 수 없을겁니다. 우리가 자바스크립트(혹은 다른 프로그래밍 언어)를 배울때 특히 그렇습니다. 우리가 하는 일의 상당 부분은 수치형 데이터를 처리하고, 값을 계산하거나 하는 일에 의지합니다. </p> + +<p>이 장은 당장 알아야 하는 부분만 다룹니다.</p> + +<h3 id="숫자의_종류">숫자의 종류</h3> + +<p>프로그래밍에서, 우리가 잘 알고있는 십진법 체계라도 당신이 생각한 것보다 복잡합니다.</p> + +<ul> + <li><strong>정수(Integers)</strong>는 10, 400, 혹은 -5 같은 모든 숫자입니다.</li> + <li><strong>실수(Floats)</strong>는 12.5, 6.7786543과 같이 소수점과 소수 자릿수가 있습니다.</li> + <li><strong>실수(Doubles)</strong>는 IEEE 754 표준 부동소수점보다 더 정확한 정밀도를 가지고 있는 특별한 데이터 타입입니다. (<strong>Doubles</strong>은<strong> Floats</strong> 보다 더 많은 소수 자릿수를 표현할 수 있어서 소수점 표현에는 <strong>Doubles</strong>가 더 정확합니다.).</li> +</ul> + +<p>자바스크립트는 심지어 다른 숫자 타입을 지원합니다. 10진수는 10을 기준으로 합니다. (숫자 0~9을 쓴다는 뜻입니다.), 하지만 자바스크립트는 아래와 같은 데이터 타입을 지원합니다.</p> + +<ul> + <li><strong>2진수(Binary)</strong> — 10진수를 0과 1를 이용해 나타내는 데이터 타입입니다.</li> + <li><strong>8진수(Octal)</strong> — 10진수를 0부터 7까지의 수를 이용해 나타내는 데이터 타입입니다.</li> + <li><strong>16진수(Hexadecimal)</strong> — 10진수를 0부터 15까지의 수를 이용해 나타내는 데이터 타입입니다.(1~10, A~F) . <a href="/en-US/Learn/CSS/Introduction_to_CSS/Values_and_units#Hexadecimal_values">CSS의 색상</a>을 지정할 때 쉽게 볼 수 있습니다.</li> +</ul> + +<p><strong>어려워서 힘들다고 느끼기 전에, 잠시 멈추세요!</strong> 시작하기 위해서 우리는 이제부터 10진수만 사용하도록 하겠습니다. 다른 유형에 대해 생각할 필요가 없습니다.</p> + +<p>두 번째 좋은 소식은 다른 프로그래밍 언어와 달리, 자바스크립트는 실수와 정수 모두 {{jsxref("Number")}}라는 하나의 데이터 타입만 사용합니다. 실수와 정수 모두 같은 데이터 타입이기 때문에 하나의 방법으로 동작하게 할 수 있다는 뜻입니다.</p> + +<h3 id="나를_위한_숫자들">나를 위한 숫자들</h3> + + + +<p>우리가 필요한 기본 구문을 다시 익히기 위해 몇 가지 숫자를 빠르게 생각해 봅시다. <a href="/en-US/docs/Learn/Common_questions/What_are_browser_developer_tools">developer tools JavaScript console</a> 에 들어가서 아래의 나열된 명령어를 입력해주세요.</p> + +<ol> + <li>먼저, 두 개의 변수를 선언합니다. 그리고 두 개의 변수를 정수와 실수로 초기화해줍니다. 각각 변수명을 콘솔 창에 입력해주세요. 그리고 어떤 값이 나오는지 확인해주세요. + <pre class="brush: js notranslate">var myInt = 5; +var myFloat = 6.667; +myInt; +myFloat;</pre> + </li> + <li>숫자는 따옴표(" 또는 ')가 없습니다. — 계속 하기 전에 여러 개의 변수를 선언하고 숫자를 초기화 해주세요.</li> + <li>우리들의 변수들의 데이터 타입을 확인합니다. 자바스크립트에서는 데이터 타입을 확인하기 위해 {{jsxref("Operators/typeof", "typeof")}} 라는 키워드를 사용합니다. 아래와 같이 입력해 주세요: + <pre class="brush: js notranslate">typeof myInt; +typeof myFloat;</pre> + <code>"number"</code> 는 정수와 실수인 경우에 나옵니다. — 이것들은 정수와 실수가 다른 데이터 타입일 때 보다 다루기 쉽게 해줍니다. 그리고 다른 데이터 타입일 때 다른 방법으로 다뤄야만 합니다. 호우~!</li> +</ol> + +<h2 id="산술_연산자">산술 연산자</h2> + +<p>산술연산자들의 기본적인 용도는 덧셈을 할 때 입니다.</p> + +<table class="standard-table"> + <thead> + <tr> + <th scope="col">Operator</th> + <th scope="col">Name</th> + <th scope="col">Purpose</th> + <th scope="col">Example</th> + </tr> + </thead> + <tbody> + <tr> + <td><code>+</code></td> + <td>Addition</td> + <td>두 개의 숫자를 더합니다.</td> + <td><code>6 + 9</code></td> + </tr> + <tr> + <td><code>-</code></td> + <td>Subtraction</td> + <td>왼쪽에 있는 수를 오른쪽 수로 뺍니다.</td> + <td><code>20 - 15</code></td> + </tr> + <tr> + <td><code>*</code></td> + <td>Multiplication</td> + <td>두 개의 숫자를 곱합니다.</td> + <td><code>3 * 7</code></td> + </tr> + <tr> + <td><code>/</code></td> + <td>Division</td> + <td>왼쪽의 숫자를 오른쪽 숫자로 나눠서 몫을 구합니다.</td> + <td><code>10 / 5</code></td> + </tr> + <tr> + <td><code>%</code></td> + <td>Remainder (sometimes called modulo)</td> + <td> + <p>왼쪽의 숫자를 오른쪽 숫자로 나눠서 나머지를 구합니다.</p> + </td> + <td><code>8 % 3</code><br> + ( 2를 반환합니다, 8을 3으로 나눴을 때 몫이 2이기 때문입니다.)</td> + </tr> + </tbody> +</table> + +<div class="note"> +<p><strong>팁</strong>: 연산에 관계된 수를 피연산자라고 부릅니다.<br> + 참고 - {{Glossary("Operand", "operands")}}.</p> +</div> + +<p>아직 수학을 공부할 필요는 없습니다. 하지만 우리는 문법 확인을 해야합니다. 아래의 명령어들을 <a href="/en-US/docs/Learn/Common_questions/What_are_browser_developer_tools">developer tools JavaScript console</a> 에 입력해주세요. </p> + +<ol> + <li>아래의 명령어를 콘솔창에 입력해주세요. + <pre class="brush: js notranslate">10 + 7 +9 * 8 +60 % 3</pre> + </li> + <li>You can also try declaring and initializing some numbers inside variables, and try using those in the sums — the variables will behave exactly like the values they hold for the purposes of the sum. For example: + <pre class="brush: js notranslate">var num1 = 10; +var num2 = 50; +9 * num1; +num2 / num1;</pre> + </li> + <li>Last for this section, try entering some more complex expressions, such as: + <pre class="brush: js notranslate">5 + 10 * 3; +num2 % 9 * num1; +num2 + num1 / 8 + 2;</pre> + </li> +</ol> + +<p>Some of this last set of sums might not give you quite the result you were expecting; the below section might well give the answer as to why.</p> + +<h3 id="Operator_precedence">Operator precedence</h3> + +<p>Let's look at the last example from above, assuming that <code>num2</code> holds the value 50 and <code>num1</code> holds the value 10 (as originally stated above):</p> + +<pre class="brush: js notranslate">num2 + num1 / 8 + 2;</pre> + +<p>As a human being, you may read this as <em>"50 plus 10 equals 60"</em>, then <em>"8 plus 2 equals 10"</em>, and finally <em>"60 divided by 10 equals 6"</em>.</p> + +<p>But the browser does <em>"10 divided by 8 equals 1.25"</em>, then <em>"50 plus 1.25 plus 2 equals 53.25"</em>.</p> + +<p>This is because of <strong>operator precedence</strong> — some operators will be applied before others when calculating the result of a sum (referred to as an expression, in programming). Operator precedence in JavaScript is the same as is taught in math classes in school — Multiply and divide are always done first, then add and subtract (the sum is always evaluated from left to right).</p> + +<p>If you want to override operator precedence, you can put parentheses round the parts that you want to be explicitly dealt with first. So to get a result of 6, we could do this:</p> + +<pre class="brush: js notranslate">(num2 + num1) / (8 + 2);</pre> + +<p>Try it and see.</p> + +<div class="note"> +<p><strong>Note</strong>: A full list of all JavaScript operators and their precedence can be found in <a href="/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators#Operator_precedence">Expressions and operators</a>.</p> +</div> + +<h2 id="Increment_and_decrement_operators">Increment and decrement operators</h2> + +<p>Sometimes you'll want to repeatedly add or subtract one to/from a numeric variable value. This can be conveniently done using the increment (<code>++</code>) and decrement(<code>--</code>) operators. We used <code>++</code> in our "Guess the number" game back in our <a href="/en-US/docs/Learn/JavaScript/Introduction_to_JavaScript_1/A_first_splash">first splash into JavaScript</a> article, when we added 1 to our <code>guessCount</code> variable to keep track of how many guesses the user has left after each turn.</p> + +<pre class="brush: js notranslate">guessCount++;</pre> + +<div class="note"> +<p><strong>Note</strong>: They are most commonly used in <a href="/en-US/docs/Web/JavaScript/Guide/Loops_and_iteration">loops</a>, which you'll learn about later on in the course. For example, say you wanted to loop through a list of prices, and add sales tax to each one. You'd use a loop to go through each value in turn and do the necessary calculation for adding the sales tax in each case. The incrementor is used to move to the next value when needed. We've actually provided a simple example showing how this is done — check it out live, and look at the source code to see if you can spot the incrementors! We'll look at loops in detail later on in the course.</p> +</div> + +<p>Let's try playing with these in your console. For a start, note that you can't apply these directly to a number, which might seem strange, but we are assigning a variable a new updated value, not operating on the value itself. The following will return an error:</p> + +<pre class="brush: js notranslate">3++;</pre> + +<p>So, you can only increment an existing variable. Try this:</p> + +<pre class="brush: js notranslate">var num1 = 4; +num1++;</pre> + +<p>Okay, strangeness number 2! When you do this, you'll see a value of 4 returned — this is because the browser returns the current value, <em>then</em> increments the variable. You can see that it's been incremented if you return the variable value again:</p> + +<pre class="brush: js notranslate">num1;</pre> + +<p>The same is true of <code>--</code> : try the following</p> + +<pre class="brush: js notranslate">var num2 = 6; +num2--; +num2;</pre> + +<div class="note"> +<p><strong>Note</strong>: You can make the browser do it the other way round — increment/decrement the variable <em>then</em> return the value — by putting the operator at the start of the variable instead of the end. Try the above examples again, but this time use <code>++num1</code> and <code>--num2</code>.</p> +</div> + +<h2 id="Assignment_operators">Assignment operators</h2> + +<p>Assignment operators are operators that assign a value to a variable. We have already used the most basic one, <code>=</code>, loads of times — it simply assigns the variable on the left the value stated on the right:</p> + +<pre class="brush: js notranslate">var x = 3; // x contains the value 3 +var y = 4; // y contains the value 4 +x = y; // x now contains the same value y contains, 4</pre> + +<p>But there are some more complex types, which provide useful shortcuts to keep your code neater and more efficient. The most common are listed below:</p> + +<table class="standard-table"> + <thead> + <tr> + <th scope="col">Operator</th> + <th scope="col">Name</th> + <th scope="col">Purpose</th> + <th scope="col">Example</th> + <th scope="col">Shortcut for</th> + </tr> + </thead> + <tbody> + <tr> + <td><code>+=</code></td> + <td>Addition assignment</td> + <td>Adds the value on the right to the variable value on the left, then returns the new variable value</td> + <td><code>x = 3;<br> + x += 4;</code></td> + <td><code>x = 3;<br> + x = x + 4;</code></td> + </tr> + <tr> + <td><code>-=</code></td> + <td>Subtraction assignment</td> + <td>Subtracts the value on the right from the variable value on the left, and returns the new variable value</td> + <td><code>x = 6;<br> + x -= 3;</code></td> + <td><code>x = 6;<br> + x = x - 3;</code></td> + </tr> + <tr> + <td><code>*=</code></td> + <td>Multiplication assignment</td> + <td>Multiples the variable value on the left by the value on the right, and returns the new variable value</td> + <td><code>x = 2;<br> + x *= 3;</code></td> + <td><code>x = 2;<br> + x = x * 3;</code></td> + </tr> + <tr> + <td><code>/=</code></td> + <td>Division assignment</td> + <td>Divides the variable value on the left by the value on the right, and returns the new variable value</td> + <td><code>x = 10;<br> + x /= 5;</code></td> + <td><code>x = 10;<br> + x = x / 5;</code></td> + </tr> + </tbody> +</table> + +<p>Try typing some of the above examples into your console, to get an idea of how they work. In each case, see if you can guess what the value is before you type in the second line.</p> + +<p>Note that you can quite happily use other variables on the right hand side of each expression, for example:</p> + +<pre class="brush: js notranslate">var x = 3; // x contains the value 3 +var y = 4; // y contains the value 4 +x *= y; // x now contains the value 12</pre> + +<div class="note"> +<p><strong>Note</strong>: There are lots of <a href="/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators#Assignment_operators">other assignment operators available</a>, but these are the basic ones you should learn now.</p> +</div> + +<h2 id="Active_learning_sizing_a_canvas_box">Active learning: sizing a canvas box</h2> + +<p>In this exercise, you will manipulate some numbers and operators to change the size of a box. The box is drawn using a browser API called the {{domxref("Canvas API", "", "", "true")}}. There is no need to worry about how this works — just concentrate on the math for now. The width and height of the box (in pixels) are defined by the variables <code>x</code> and <code>y</code>, which are initially both given a value of 50.</p> + +<p>{{EmbedGHLiveSample("learning-area/javascript/introduction-to-js-1/maths/editable_canvas.html", '100%', 520)}}</p> + +<p><strong><a href="https://mdn.github.io/learning-area/javascript/introduction-to-js-1/maths/editable_canvas.html">Open in new window</a></strong></p> + +<p>In the editable code box above, there are two lines marked with a comment that we'd like you to update to make the box grow/shrink to certain sizes, using certain operators and/or values in each case. Let's try the following:</p> + +<ul> + <li>Change the line that calculates x so the box is still 50px wide, but the 50 is calculated using the numbers 43 and 7 and an arithmetic operator.</li> + <li>Change the line that calculates y so the box is 75px high, but the 75 is calculated using the numbers 25 and 3 and an arithmetic operator.</li> + <li>Change the line that calculates x so the box is 250px wide, but the 250 is calculated using two numbers and the remainder (modulo) operator.</li> + <li>Change the line that calculates y so the box is 150px high, but the 150 is calculated using three numbers and the subtraction and division operators.</li> + <li>Change the line that calculates x so the box is 200px wide, but the 200 is calculated using the number 4 and an assignment operator.</li> + <li>Change the line that calculates y so the box is 200px high, but the 200 is calculated using the numbers 50 and 3, the multiplication operator, and the addition assignment operator.</li> +</ul> + +<p>Don't worry if you totally mess the code up. You can always press the Reset button to get things working again. After you've answered all the above questions correctly, feel free to play with the code some more or create your own challenges.</p> + +<h2 id="Comparison_operators">Comparison operators</h2> + +<p>Sometimes we will want to run true/false tests, then act accordingly depending on the result of that test — to do this we use <strong>comparison operators</strong>.</p> + +<table class="standard-table"> + <thead> + <tr> + <th scope="col">Operator</th> + <th scope="col">Name</th> + <th scope="col">Purpose</th> + <th scope="col">Example</th> + </tr> + <tr> + <td><code>===</code></td> + <td>Strict equality</td> + <td>Tests whether the left and right values are identical to one another</td> + <td><code>5 === 2 + 4</code></td> + </tr> + <tr> + <td><code>!==</code></td> + <td>Strict-non-equality</td> + <td>Tests whether the left and right values <strong>not</strong> identical to one another</td> + <td><code>5 !== 2 + 3</code></td> + </tr> + <tr> + <td><code><</code></td> + <td>Less than</td> + <td>Tests whether the left value is smaller than the right one.</td> + <td><code>10 < 6</code></td> + </tr> + <tr> + <td><code>></code></td> + <td>Greater than</td> + <td>Tests whether the left value is greater than the right one.</td> + <td><code>10 > 20</code></td> + </tr> + <tr> + <td><=</td> + <td>Less than or equal to</td> + <td>Tests whether the left value is smaller than or equal to the right one.</td> + <td><code>3 <= 2</code></td> + </tr> + <tr> + <td>>=</td> + <td>Greater than or equal to</td> + <td>Tests whether the left value is greater than or equal to the right one.</td> + <td><code>5 >= 4</code></td> + </tr> + </thead> +</table> + +<div class="note"> +<p><strong>Note</strong>: You may see some people using <code>==</code> and <code>!=</code> in their tests for equality and non-equality. These are valid operators in JavaScript, but they differ from <code>===</code>/<code>!==</code>. The former versions test whether the values are the same but not whether the values' datatypes are the same. The latter, strict versions test the equality of both the values and their datatypes. The strict versions tend to result in fewer errors, so we recommend you use them.</p> +</div> + +<p>If you try entering some of these values in a console, you'll see that they all return <code>true</code>/<code>false</code> values — those booleans we mentioned in the last article. These are very useful, as they allow us to make decisions in our code, and they are used every time we want to make a choice of some kind. For example, booleans can be used to:</p> + +<ul> + <li>Display the correct text label on a button depending on whether a feature is turned on or off</li> + <li>Display a game over message if a game is over or a victory message if the game has been won</li> + <li>Display the correct seasonal greeting depending what holiday season it is</li> + <li>Zoom a map in or out depending on what zoom level is selected</li> +</ul> + +<p>We'll look at how to code such logic when we look at conditional statements in a future article. For now, let's look at a quick example:</p> + +<pre class="brush: html notranslate"><button>Start machine</button> +<p>The machine is stopped.</p> +</pre> + +<pre class="brush: js notranslate">var btn = document.querySelector('button'); +var txt = document.querySelector('p'); + +btn.addEventListener('click', updateBtn); + +function updateBtn() { + if (btn.textContent === 'Start machine') { + btn.textContent = 'Stop machine'; + txt.textContent = 'The machine has started!'; + } else { + btn.textContent = 'Start machine'; + txt.textContent = 'The machine is stopped.'; + } +}</pre> + +<p>{{EmbedGHLiveSample("learning-area/javascript/introduction-to-js-1/maths/conditional.html", '100%', 100)}}</p> + +<p><strong><a href="https://mdn.github.io/learning-area/javascript/introduction-to-js-1/maths/conditional.html">Open in new window</a></strong></p> + +<p>You can see the equality operator being used just inside the <code>updateBtn()</code> function. In this case, we are not testing if two mathemetical expressions have the same value — we are testing whether the text content of a button contains a certain string — but it is still the same principle at work. If the button is currently saying "Start machine" when it is pressed, we change its label to "Stop machine", and update the label as appropriate. If the button is currently saying "Stop machine" when it is pressed, we swap the display back again.</p> + +<div class="note"> +<p><strong>Note</strong>: Such a control that swaps between two states is generally referred to as a <strong>toggle</strong>. It toggles between one state and another — light on, light off, etc.</p> +</div> + +<h2 id="Summary">Summary</h2> + +<p>In this article we have covered the fundamental information you need to know about numbers in JavaScript, for now. You'll see numbers used again and again, all the way through your JavaScript learning, so it's a good idea to get this out of the way now. If you are one of those people that doesn't enjoy math, you can take comfort in the fact that this chapter was pretty short.</p> + +<p>In the next article, we'll explore text and how JavaScript allows us to manipulate it.</p> + +<div class="note"> +<p><strong>Note</strong>: If you do enjoy math and want to read more about how it is implemented in JavaScript, you can find a lot more detail in MDN's main JavaScript section. Great places to start are our <a href="/en-US/docs/Web/JavaScript/Guide/Numbers_and_dates">Numbers and dates</a> and <a href="/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators">Expressions and operators</a> articles.</p> +</div> + +<p>{{PreviousMenuNext("Learn/JavaScript/First_steps/Variables", "Learn/JavaScript/First_steps/Strings", "Learn/JavaScript/First_steps")}}</p> + +<h2 id="In_this_module">In this module</h2> + +<ul> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/What_is_JavaScript">What is JavaScript?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/A_first_splash">A first splash into JavaScript</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/What_went_wrong">What went wrong? Troubleshooting JavaScript</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Variables">Storing the information you need — Variables</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Math">Basic math in JavaScript — numbers and operators</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Strings">Handling text — strings in JavaScript</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Useful_string_methods">Useful string methods</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Arrays">Arrays</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Silly_story_generator">Assessment: Silly story generator</a></li> +</ul> diff --git a/files/ko/learn/javascript/first_steps/silly_story_generator/index.html b/files/ko/learn/javascript/first_steps/silly_story_generator/index.html new file mode 100644 index 0000000000..a6f2318602 --- /dev/null +++ b/files/ko/learn/javascript/first_steps/silly_story_generator/index.html @@ -0,0 +1,192 @@ +--- +title: Silly story generator +slug: Learn/JavaScript/First_steps/Silly_story_generator +translation_of: Learn/JavaScript/First_steps/Silly_story_generator +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenu("Learn/JavaScript/First_steps/Arrays", "Learn/JavaScript/First_steps")}}</div> + +<p class="summary">이 모듈에서 배운 지식들을 바탕으로 랜덤하게 꾸며진 이야기(silly stories)가 만들어지는 재미있는 앱을 만들어 볼거에요. 즐겨봅시다!!</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">선행요소:</th> + <td>이 평가에 시도하기 전에 이 모듈에서 배운 항목을 모두 수행해봐야 합니다.</td> + </tr> + <tr> + <th scope="row">목적:</th> + <td>변수, 숫자, 연산자, 문자열 및 배열 같은 자바스크립트의 기본항목들에 대한 전반적인 이해를 테스트합니다.</td> + </tr> + </tbody> +</table> + +<h2 id="시작하기">시작하기</h2> + +<p>이 평가하기(assements)를 시작하기 전에, 아래와 같은 것을 해야 합니다:</p> + +<ul> + <li>HTML 예제 파일이 있는 사이트(<a href="https://github.com/mdn/learning-area/blob/master/javascript/introduction-to-js-1/assessment-start/index.html">grab the HTML file</a>)로 이동하여 파일을 복사하여 자기 컴퓨터에 새 디렉토리를 만들고 파일이름 <code>index.html</code> 로 저장합니다. 이 안에는 예제를 위한 CSS가 포함되어 있습니다.</li> + <li>또 다른 가공 전의 텍스트가 있는 사이트 (<a href="https://github.com/mdn/learning-area/blob/master/javascript/introduction-to-js-1/assessment-start/raw-text.txt">page containing the raw text</a>) 로 가서 별도의 브라우저 탭으로 열어 놓으세요. 이것은 나중에 필요합니다.</li> +</ul> + +<p>위 방법 대신에, 여러분은 테스트에 <a href="http://jsbin.com/">JSBin</a> 또는 <a href="https://glitch.com/">Glitch</a> 같은 사이트를 이용할 수 있습니다. 이 온라인 에디터들 내부에 HTML, CSS 그리고 JavaScript를 붙여넣을 수 있습니다. 만약 당신이 사용하는 온라인 에디터가 Javascript 패널(또는 탭)을 갖고 있지 않다면, 자유롭게 HTML 페이지 내부에 <code><script></code> 엘리멘트를 넣을 수 있습니다.</p> + +<div class="note"> +<p><strong>Note</strong>: 만약 평가가 막힌다면, 우리에게 도움을 요청하세요— 이 페이지 밑에 {{anch("Assessment or further help")}} 섹션을 보세요.</p> +</div> + +<h2 id="프로젝트에_대한_간략한_설명">프로젝트에 대한 간략한 설명</h2> + +<p>이제 프로젝트 시작을 위해 가공하지 않은 HTML/CSS 그리고 몇몇 텍스트를 만들고 확인했습니다. 이제 아래와 같은 기능을 하는 프로그램을 만들기 위해 JavaScript를 코딩해야 합니다.</p> + +<ul> + <li>"랜덤한 이야기 만들기('Generate random story') 버튼를 누를 때 마다 꾸며진 이야기(silly stories)를 만들어야 합니다.</li> + <li>"Enter custome name" 필드에 값이 입력되어있지 않을 경우 기본 이름을 Bob으로 지정합니다. "랜덤한 이야기 만들기('Generate random story')" 버튼을 클릭 하면 아래 사진에서 "Chris saw the ~.." 로 시작하는 문장이 "Bob saw the ~.."로 표시되게 합니다.</li> + <li>"랜덤한 이야기 만들기('Generate random story')" 을 클릭하면 프로그램이 "US", "UK" 라디오 체크버튼을 확인하여 각 국가에 맞는 온도, 수량, 무게 등 단위를 설정하세요. 아래 사진의 예를 들면 "~ weights 300 pounds, and ~" 부분이 해당됩니다.</li> + <li>"랜덤한 이야기 만들기('Generate random story')" 을 누르면 꾸며진 이야기('silly stories')가 랜덤하게 계속 만들어지게 하세요.</li> +</ul> + +<p>이 스크린샷은 프로그램 출력의 예시 입니다:</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/13667/assessment-1.png" style="border-style: solid; border-width: 1px; display: block; margin: 0px auto;"></p> + +<p>더 많은 아이디어를 얻으려면, 완성된 예(<a href="http://mdn.github.io/learning-area/javascript/introduction-to-js-1/assessment-finished/">have a look at the finished example</a> )를 참고하세요(소스코드는 엿보기 없기!)</p> + +<h2 id="완료하기">완료하기</h2> + +<p>이번 섹션에선 프로젝트를 어떻게 진행해야 하는지 자세하게 설명합니다.</p> + +<p>기본 설정:</p> + +<ol> + <li><code>index.html</code> <font face="Open Sans">파</font>일과 같은 디렉토리에 <code>main.js</code> 라는 이름의 파일을 새로 만듭니다.</li> + <li>HTML 파일(<code>index.html</code>)에 <a href="https://developer.mozilla.org/ko/docs/Web/HTML/Element/script"><script></a> 엘리먼트를 삽입하여 <code>main.js</code> 를 참조하도록 외부 자바스크립트 파일(<code>main.js</code>)을 적용합니다. <code></body></code> 태그 바로 앞에 배치하세요.</li> +</ol> + +<p>초기 변수와 함수:</p> + +<ol> + <li> + <p>가공 전의 텍스트 파일에서, "1. COMPLETE VARIABLE AND FUNCTION DEFINITIONS" 바로 밑의 코드를 모두 복사해서 <code>main.js</code> 파일의 맨 위에 붙여넣습니다. 이 내용은 세 개의 변수 제공하는데, <code>customName</code> 변수는 "Enter custom name" 텍스트 필드 값을 저장하고, <code>randomize</code> 변수에는 "Generate random story" 버튼 오브젝트를 저장하고, HTML 바디에 끝에 있는 클래스가 <code>story</code>인 <a href="https://developer.mozilla.org/ko/docs/Web/HTML/Element/p"><p></a> 엘리먼트는 story 변수에 저장하며 해당 엘리먼트에는 랜덤한 이야기가 복사됩니다. 또한, randomValueFromArray() 함수는 배열을 가져와서 배열이 가진 항목 중 하나를 랜덤하게 반환합니다.</p> + </li> + <li> + <p>가공전 텍스트 파일의 두번째 섹션 "2. RAW TEXT STRINGS"에는 프로그램에 자동으로 입력되어 랜덤 이야기 엘리먼트에 출력하는 문자열이 포함되어 있습니다. <code>main.js</code> 에 아래 설명대로 변수를 만듭니다:</p> + + <ol> + <li>먼저 <code>storyText</code>변수에 가장 긴 문자열("It was 94 fahrenheit outside, so ~~" 로 시작하는 문장)을 저장합니다.</li> + <li><code>insertX</code> 배열에 세 개의 문자열 집단의 첫번째(Willy the Goblin, Big Daddy, Father Christmas)를 저장합니다.</li> + <li><code>insertY</code> 배열에 세 개의 문자열 집단의 두번째(the soup kitchen, Disneyland, the White House)을 저장합니다.</li> + <li><code>insertZ</code> 배열에 세 개의 문자열 집단의 세번째(spontaneously combusted, melted into a puddle on the sidewalk, turned into a slug and crawled away)를 저장합니다.</li> + </ol> + </li> +</ol> + +<p>이벤트 핸들러와 완성되지 않은 함수 정리:</p> + +<ol> + <li>가공전 텍스트 파일("raw text file")로 돌아가자.</li> + <li>"3. EVENT LISTENER AND PARTIAL FUNCTION DEFINITION" 밑의 코드를 복사하고, <code>main.js</code> 파일의 맨 밑에다 붙여 넣으세요: + <ul> + <li><code>randomize</code> 변수에 클릭 이벤트 리스너를 추가하세요. 그러면 버튼이 클릭되었을 때, <code>result()</code> 함수가 실행됩니다.</li> + <li>코드에 부분적으로 완료된 <code>result()</code> 함수를 추가하세요. 이 평가의 뒤 부분에서 함수가 완성되고 정상적으로 동작하도록 내용을 추가할 것입니다.</li> + </ul> + </li> +</ol> + +<p><code>result()</code> 함수 완성하기: </p> + +<ol> + <li><code>newStory</code>라 불리는 새 변수를 만들고, 이것의 값(value)를 <code>storyText</code> 와 똑같이 설정하세요. 이것은 버튼을 누르고 함수가 수행(run)될 때 마다 새 이야기('story')가 랜덤하게 만들어 질 수 있게 합니다. <code>storyText</code>를 직접 변경했다면, 새로운 이야기('story')를 한번만 만들 수 있습니다(함수를 통해서 하지 않으면 정적인 값만 유지한다는 의미).</li> + <li>세 개의 새로운 변수 <code>xItem</code>, <code>yItem</code>, 와 <code>zItem</code>를 만들고 이 세 개의 변수는 <code>randomValueFromArray()</code> 를 반환 결과인 세개의 배열과 같도록 만듭니다(각 경우의 호출 결과는 각 배열에 임의의 아이템). 예를 들어 <code>randomValueFromArray(insertX) </code>함수를 호출하면 <code>insertX</code> 에서 문자열의 하나를 랜덤하게 가질 수 있다.</li> + <li>그 다음으로 <code>newStory</code> 문자열에 있는 세 개의 placeholders— <code>:insertx:</code>, <code>:inserty:<font face="Arial, x-locale-body, sans-serif"><span style="background-color: #ffffff;">, </span></font></code><code>:insertz:</code> —저장된 <code>xItem</code>, <code>yItem </code>와 <code>zItem</code> 문자열을 이용하여 로 변환하세요. 여기서 특정 문자열 함수가 도움될 것입니다. 이 함수는 각 경우에 <code>newStory</code>와 같게되며(대입), 호출 시 마다 <code>newStory</code> 의 원래 값과 동일하지만 대체 될 수 있습니다(랜덤으로 값이 변경되는 것을 표현하는 것으로 추정됨) 그러므로 버튼이 눌러질때마다, 이 placeholder는 꾸며진('silly') 문자열로 랜덤하게 교체되게 됩니다. 추가적인 힌트로, 이 문제의 함수는 하위 문자열에서 찾아진 첫번째 인스턴스만 변경되므로, 아마도 두번 이상 이 함수를 호출해야 할 수도 있습니다.</li> + <li>첫번째 <code>if</code> 블록에서, <code>newStory</code> 의 'Bob'이라는 이름을 <code>name</code> 변수를 사용하여 변환하는 함수를 추가하세요. 이 블록에서 말하는 내용은 "만약 <code>customName</code> 텍스트 입력에 값이 들어가 있다면, 이야기속의 Bob을 사용자가 정의한 이름으로 바꾸세요" 라는 의미입니다.</li> + <li>두번째 <code>if</code> 블록에서는 <code>uk</code> 라디오 버튼이 선택되었는지 확인합시다. <code>uk</code> 라디오 버튼이 눌려졌다면, 이야기('story') 상의 무게('weight')와 온도('temperature') 값 들인 파운드('pounds')와 화씨온도(Fahrenheit) 를 'stones'과 섭씨온도('centigrade')를 바꾸어야 합니다. 필요한 것은 아래와 같습니다: + <ol> + <li>파운드(pound)를 stone, 화씨온도(Fahrenheit) 를 섭씨온도(centigrade)로 변환하는 공식을 참조하라.</li> + <li> <code>weight</code> 변수를 정의하는 라인에서는, 300를 300 파운드를 stones 변환하라. 변환 결과값을 <code>Math.round()</code> 를 실행한 결과값 끝에 <code>' stone'</code> 을 결합한다(문자열 더하기 연산 또는 concat())</li> + <li> <code>temperature</code> 변수를 정의하는 라인에서는, 94를 화씨(Fahrenheit) 94도를 섭씨온도(centigrade)로 변환하라. 변환 결과값을 <code>Math.round()</code> 를 실행한 결과값 끝에 <code>' centigrade'</code>을 결합한다(문자열 더하기 연산 또는 concat())</li> + <li>두 변수 정의 바로 밑에, '94 화씨온도('farenheit')로 <code>temperature</code> 변수의 내용을 변환하는 것과, '300 pounds'을 <code>weight</code> 변수의 내용을 바꾸는 두줄의 문자열 변환라인을 추가한다 .</li> + </ol> + </li> + <li>마지막으로, 함수의 끝 두 줄에 <code>story</code> 변수의 <code>textContent</code> 속성(property)을 <code>newStory</code>와 같게 만드세요.</li> +</ol> + +<h2 id="힌트와_팁">힌트와 팁</h2> + +<ul> + <li>JavaScript 내용 외에는 HTML을 수정할 필요가 없습니다.</li> + <li>만약 JavaScript가 정상적으로 HTML에 적용되었는지 의심스럽다면, 일시적으로 JavaScript의 내용을 지우고, 단순하고 짧은 효과가 명확한 내용을 추가해서, 저장하고 새로고침을 해보세요. 아래 예제는 {{htmlelement("html")}} 의 배경을 빨강색으로 바꿉니다 — 정상적으로 JavaScript가 적용되었다면 브라우저 전체 윈도우가 빨강색으로 바뀌게 될겁니다: + <pre class="brush: js notranslate">document.querySelector('html').style.backgroundColor = 'red';</pre> + </li> + <li><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/round">Math.round()</a> 는 가장 가까운 정수로 단순하게 반올림한 결과를 반환하는 JavaScript 내장함수 입니다. </li> + <li>변환이 필요한 세 개의 문장이 문제 있습니다. 아마도 <code>replace()</code> 함수를 반복적으로 실행 하거나 정규 표현식을 사용할 수 있습니다. 예를 들어 <code>var text = 'I am the biggest lover, I love my love'; text.replace(/love/g,'like');</code> 를 실행하면 인스턴스의 'love' 는 'like' 로 모두 바뀌게 될겁니다. 기억하세요, 문자열은 변하지 않습니다!(문자열은 새 변경할 수 없으며, 새 문자열이 생성되고 그 생성된 결과를 인스턴스가 갖게됨을 표현한 것으로 추정)</li> +</ul> + +<h2 id="평가_또는_추가_도움">평가 또는 추가 도움</h2> + +<p>만약 작업을 평가하길 원하거나 풀이가 막혀서 도움을 원하면:</p> + +<ol> + <li>온라인 공유가 가능한 <a href="https://codepen.io/">CodePen</a>, <a href="https://jsfiddle.net/">jsFiddle</a>, 또는 <a href="https://glitch.com/">Glitch</a> 같은 에디터에 작업한 것을 올려 두세요.</li> + <li>평가 또는 도움을 요청을 <a href="https://discourse.mozilla.org/c/mdn/learn">MDN Discourse forum Learning category</a> 에 포스트를 쓰세요. 당신의 글은 아래를 포함해야 합니다: + <ul> + <li>"Assessment wanted for Silly story generator"와 같은 서술적인 제목.</li> + <li>이미 시도해본 것에 대한 상세내용과 우리가 어떻게 하길 원하는 지.<br> + 예. 만약 당신이 풀이가 막히고 도움이 필요하다거나, 평가를 원한다는 것을.</li> + <li>평가를 받고 싶거나 도움이 필요한 예제를 갖고 있는 공유가능한 온라인 에디터 링크. (위에 1단계에서 언급한 것). 이것은 좋은 습관입니다. 그들의 코드를 보지못한다면 도움을 주기는 굉장히 어렵습니다.</li> + <li>실제 작업 또는 평가 페이지 링크, 그래야 우리가 당신이 도움받길 원하는 것을 찾을 수 있어요.</li> + </ul> + </li> +</ol> + +<p>{{PreviousMenu("Learn/JavaScript/First_steps/Arrays", "Learn/JavaScript/First_steps")}}</p> + +<h2 id="이_모듈에서">이 모듈에서</h2> + +<ul> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/What_is_JavaScript">What is JavaScript?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/A_first_splash">A first splash into JavaScript</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/What_went_wrong">What went wrong? Troubleshooting JavaScript</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Variables">Storing the information you need — Variables</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Math">Basic math in JavaScript — numbers and operators</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Strings">Handling text — strings in JavaScript</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Useful_string_methods">Useful string methods</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Arrays">Arrays</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Silly_story_generator">Assessment: Silly story generator</a></li> +</ul> + +<div id="dicLayer" style=""> +<div id="dicLayerContents"><dicword style="user-select: text;">What is JavaScript?</dicword><dicword style="user-select: text;"><dicimg id="play" style="background-image: url(chrome-extension://bmbdcffdhebhecemcchbkfnjlmdiiepe/play.gif);"></dicimg> <input>Eng<dicimg id="copy" style="background-image: url(chrome-extension://bmbdcffdhebhecemcchbkfnjlmdiiepe/copy.png);" title="copy"></dicimg></dicword><br> +<br> +<br> +<br> +자바 스크립트 란?</div> + +<div id="dicLayerSub"></div> +</div> + +<div id="dicRawData" style="display: none;">{"mean":["what<br/><br/>[대명사, 한정사]\n\t\t \t\t(의문문에서) 무엇; 몇; 어떤, 무슨\n\n\t\t 참조 which","be<br/><br/>[동사]\n\t\t there is/are\n\t\t \t\t있다, 존재하다","script<br/><br/>[명사]\n\t\t \t\t(연극영화방송강연 등의) 대본[원고]","is<br/><br/>참조 be","Java Script<br/><br/>(컴퓨터)\n\t\t \t\t자바 스크립트 ((미국 넷스케이프 커뮤니케이션스가 개발한 스크립트 언어))","TypeScript<br/><br/>[Proper noun] labelenscripting language A scripting programming language that is a strict superset of JavaScript and used to implement interactive features of Web pages."],"word":"What is JavaScript","soundUrl":"https://dict-dn.pstatic.net/v?_lsu_sa_=39682b535d673a26a89ab1563094c4fead4462b51a0a6f796ee2097e5bbb6bb1195cb75069a5ad7d792362a5c22ac0e7677a456c5837d53ff458f869cb3070278c86c07296cca27ab57925fedb326fd11c977e7d7a242a0e57b9d7f96c3e974376013120f37159780b34a104ca6074c614d78e8a098ad60cfcbe8ec73ef6b8cb","phoneticSymbol":""}</div> + +<div id="dicLayerLoader" style="top: 5596px; left: 281px;"></div> + +<div id="dicLayer"> +<div id="dicLayerContents"></div> + +<div id="dicLayerSub"></div> +</div> + +<div id="dicRawData" style="display: none;"></div> + +<div id="dicLayerLoader"></div> + +<div id="dicLayer"> +<div id="dicLayerContents"></div> + +<div id="dicLayerSub"></div> +</div> + +<div id="dicRawData" style="display: none;"></div> + +<div id="dicLayerLoader"></div> diff --git a/files/ko/learn/javascript/first_steps/strings/index.html b/files/ko/learn/javascript/first_steps/strings/index.html new file mode 100644 index 0000000000..0e24be92a8 --- /dev/null +++ b/files/ko/learn/javascript/first_steps/strings/index.html @@ -0,0 +1,294 @@ +--- +title: 문자열 다루기 — 문자열 +slug: Learn/JavaScript/First_steps/Strings +tags: + - 가이드 + - 강좌 + - 따옴표 + - 문자열 + - 자바스크립트 + - 초보자 + - 코딩 +translation_of: Learn/JavaScript/First_steps/Strings +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/JavaScript/First_steps/Math", "Learn/JavaScript/First_steps/Useful_string_methods", "Learn/JavaScript/First_steps")}}</div> + +<p class="summary">다음으로, 프로그래밍에서 어떤 텍스트가 호출되는지 문자열에 대해 알아볼까요? 이 게시물에서는 문자열 작성, 문자열의 따옴표 이스케이프 및 문자열 결합과 같이 JavaScript를 배울 때 문자열에 대해 알아야 할 모든 일반적인 사항을 살펴보겠습니다.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">선결요건:</th> + <td>기본 컴퓨터 활용능력, HTML 및 CSS에 대한 기본적인 이해, JavaScript에 대한 기초적인 이해.</td> + </tr> + <tr> + <th scope="row">목표:</th> + <td>JavaScript에서 문자열의 기초에 대해 익숙해지기.</td> + </tr> + </tbody> +</table> + +<h2 id="단어의_힘">단어의 힘</h2> + +<p>단어는 인간이 커뮤니케이션 함에 있어 커다란 하나의 부분이라고 할 수 있기에 매우 중요합니다. 웹은 사람들이 정보를 교환하고 공유할 수 있도록 설계된 텍스트 기반의 매체이므로, 웹에 표시되는 단어를 제어하는 것이 유용합니다. {{glossary ( "HTML")}}은 텍스트에 구조와 의미를 제공하며, {{glossary ( "CSS")}}는 텍스트에 스타일(일종의 디자인)을 적용할 수 있게 해주며, JavaScript는 문자열을 조작하기 위한 여러 가지 기능 (텍스트 레이블을 표시하고 용어를 원하는 순서로 정렬하는) 등 다양한 작업을 수행할 수 있습니다.</p> + + + +<p>지금까지 우리가 여러분에게 보여 줬던 거의 모든 프로그램은 문자열 조작과 관련이 있습니다.</p> + +<h2 id="문자열_—_기초">문자열 — 기초</h2> + +<p>문자열은 숫자와 유사하게 다루어지지만, 더 깊게 파고들면 눈에 띄는 차이점을 발견하기 시작할 것입니다. 먼저 몇 가지 기본 라인을 콘솔에 입력하여 우리와 친숙하게 만드는 것으로 시작하겠습니다. <a href="https://mdn.github.io/learning-area/javascript/introduction-to-js-1/variables/index.html">이 링크</a>를 통해 다른 탭이나 창에서 열 수 있고, <a href="/en-US/docs/Learn/Common_questions/What_are_browser_developer_tools">브라우저 개발자 도구</a>를 사용할 수도 있습니다).</p> + +<div class="hidden"> +<h6 id="Hidden_code">Hidden code</h6> + +<pre class="brush: html"><!DOCTYPE html> +<html> + <head> + <meta charset="utf-8"> + <title>JavaScript console</title> + <style> + * { + box-sizing: border-box; + } + + html { + background-color: #0C323D; + color: #809089; + font-family: monospace; + } + + body { + max-width: 700px; + } + + p { + margin: 0; + width: 1%; + padding: 0 1%; + font-size: 16px; + line-height: 1.5; + float: left; + } + + .input p { + margin-right: 1%; + } + + .output p { + width: 100%; + } + + .input input { + width: 96%; + float: left; + border: none; + font-size: 16px; + line-height: 1.5; + font-family: monospace; + padding: 0; + background: #0C323D; + color: #809089; + } + + div { + clear: both; + } + + </style> + </head> + <body> + + + </body> + + <script> + var geval = eval; + function createInput() { + var inputDiv = document.createElement('div'); + var inputPara = document.createElement('p'); + var inputForm = document.createElement('input'); + + inputDiv.setAttribute('class','input'); + inputPara.textContent = '>'; + inputDiv.appendChild(inputPara); + inputDiv.appendChild(inputForm); + document.body.appendChild(inputDiv); + + if(document.querySelectorAll('div').length > 1) { + inputForm.focus(); + } + + inputForm.addEventListener('change', executeCode); + } + + function executeCode(e) { + try { + var result = geval(e.target.value); + } catch(e) { + var result = 'error — ' + e.message; + } + + var outputDiv = document.createElement('div'); + var outputPara = document.createElement('p'); + + outputDiv.setAttribute('class','output'); + outputPara.textContent = 'Result: ' + result; + outputDiv.appendChild(outputPara); + document.body.appendChild(outputDiv); + + e.target.disabled = true; + e.target.parentNode.style.opacity = '0.5'; + + createInput() + } + + createInput(); + + </script> +</html></pre> +</div> + +<p>{{ EmbedLiveSample('Hidden_code', '100%', 300, "", "", "hide-codepen-jsfiddle") }}</p> + +<h3 id="문자열_만들기">문자열 만들기</h3> + +<ol> + <li>먼저 아래의 명령어를 입력하세요. + <pre class="brush: js">var string = 'The revolution will not be televised.'; +string;</pre> + 숫자에서 했던 것과 같게, 우리는 변수를 선언하고, 문자열을 초기화 하고, 값을 반환합니다. 차이점은 오직 숫자 대신 문자열을 넣었고, 문자열 값을 따옴표로 감싸주었습니다.</li> + <li>따옴표를 빼거나 잘못쓰면 에러가 뜰 것입니다. 아래의 코드를 입력해 보세요. + <pre class="brush: js example-bad">var badString = This is a test; +var badString = 'This is a test; +var badString = This is a test';</pre> + 따옴표로 감싸져 있지 않은 텍스트는 변수 이름, 속성 이름, 예약어와 유사하다고 가정하기 때문에 이러한 코드는 작동하지 않습니다. 만약 브라우저가 찾을 수 없다면 에러가 발생할 것입니다. (e.g. "missing ; before statement"). 만약 브라우저가 문자열이 시작하는 곳은 볼 수 있지만, 끝나는 곳을 찾지 못하면 에러를 던집니다.("unterminated string literal"). 만약 당신의 프로그램이 에러를 계속 만들어낸다면, 다시 돌아가 당신의 문자열에 빠진 따옴표가 없는지 찾아보십시오.</li> + <li>다음의 코드는 당신이 변수 <code>string</code> 을 선언했다면 작동할 것입니다. 아래의 코드를 입력해보세요 : + <pre class="brush: js">var badString = string; +badString;</pre> + <code>badString</code> 은 이제 <code>string</code> 과 같은 값으로 설정되었습니다.</li> +</ol> + +<h3 id="따옴표_vs_쌍따옴표">따옴표 vs 쌍따옴표</h3> + +<ol> + <li>자바스크립트에서는 따옴표와 쌍따옴표가 모두 허용됩니다. 다음의 코드는 문제 없이 작동할 것입니다. + <pre class="brush: js">var sgl = 'Single quotes.'; +var dbl = "Double quotes"; +sgl; +dbl;</pre> + </li> + <li>따옴표와 쌍따옴표는 차이점이 거의 없어, 편한대로 사용할 수 있습니다. 하지만 당신은 문자열을 감싸는데 한 종류의 따옴표만 사용해야 되며 그렇지 않으면 에러가 발생합니다. 아래의 코드를 실행해 보세요. + <pre class="brush: js example-bad">var badQuotes = 'What on earth?";</pre> + </li> + <li>브라우저는 다른종류의 따옴표가 감싸고 있어 문자열이 아직 끝나지 않았다고 생각합니다. 예를 들어, 아래 두 가지 모두 괜찮습니다. + <pre class="brush: js">var sglDbl = 'Would you eat a "fish supper"?'; +var dblSgl = "I'm feeling blue."; +sglDbl; +dblSgl;</pre> + </li> + <li>하지만, 당신은 같은 종류의 따옴표를 문자열에 포함시킬 수 없습니다. 브라우저는 어느 따옴표가 문자열이 끝났다는 것을 알리는지 혼돈하게 됩니다. 따라서 다음의 코드는 에러가 발생합니다. + <pre class="brush: js example-bad">var bigmouth = 'I've got no right to take my place...';</pre> + 이는 우리를 다음 문단으로 이끌어 줍니다.</li> +</ol> + +<h3 id="문자열_이스케이프_문자">문자열 이스케이프 문자</h3> + +<p>직전의 문제의 코드를 해결하기 위해, 우리는 따옴표를 이스케이프 문자로 만들어야 합니다. 이스케이프 문자란 어떤 한 문자를 코드가 아닌 문자열로 만들어주는 문자입니다. 자바스크립트에서는 역슬래시 ( \ )를 문자 바로 앞에 작성함으로써 코드가 아닌 문자열로 인식하게 합니다.</p> + +<pre class="brush: js">var bigmouth = 'I\'ve got no right to take my place...'; +bigmouth;</pre> + +<p>이것은 에러가 일어나지 않습니다. 당신은 <code>\"</code> 와 같게도 사용할 수 있습니다. 자세한 사항은 <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/String#Escape_notation">이스케이프 표기법</a>을 참고하십시오</p> + +<h2 id="문자열_연결하기">문자열 연결하기</h2> + +<ol> + <li>'Concatenate'는 '결합' 을 의미하는 프로프래밍 단어입니다. 자바스크립트에서 문자열을 함꼐 결합하려면 숫자를 더할 때 사용하는 것과 동일한 더하기 (+) 연산자를 사용하지만 이 상황에서는 다른 작업을 수행합니다. 콘솔에 예를 들어 보겠습니다. + <pre class="brush: js">var one = 'Hello, '; +var two = 'how are you?'; +var joined = one + two; +joined;</pre> + 변수 <code>joined</code> 의 값은 "Hello, how are you?" 입니다.</li> + <li>마지막 예에서는, 그저 두 개의 문자열을 결합했을 뿐이지만 각 문자열 사이에 +를 포함하기만 하면 원하는 만큼의 문자열을 결합할 수 있습니다. 다음을 시도해 보십시오. + <pre class="brush: js">var multiple = one + one + one + one + two; +multiple;</pre> + </li> + <li>또한 변수와 실제 문자열을 혼합하여 사용할 수도 있습니다. 다음을 시도해 보십시오. + <pre class="brush: js">var response = one + 'I am fine — ' + two; +response;</pre> + </li> +</ol> + +<div class="note"> +<p><strong>참고</strong>: 만약 코드에 따옴표나 쌍따옴표로 묶인 문자열을 입력하면 <strong>문자열 리터럴</strong> (string literal) 이라 불립니다.</p> +</div> + +<h3 id="문자열의_연결">문자열의 연결</h3> + +<p>실제 작업에 사용되는 연결 방법에 대해 살펴보겠습니다. 이 과정에 앞부분의 예는 다음과 같습니다.</p> + +<pre class="brush: html"><button>Press me</button></pre> + +<pre class="brush: js">var button = document.querySelector('button'); + +button.onclick = function() { + var name = prompt('What is your name?'); + alert('Hello ' + name + ', nice to see you!'); +}</pre> + +<p>{{ EmbedLiveSample('Concatenation_in_context', '100%', 50, "", "", "hide-codepen-jsfiddle") }}</p> + +<p>여기서 우리는 {{domxref("Window.prompt()", "Window.prompt()")}} 를 4번째 줄에 쓰는데, 그것은 팝업 대화 상자를 통해 질문에 응답하도록 요청한 다음 지정된 변수 내에 입력하는 텍스트를 저장합니다 — 이 경우에는 <code>name</code> 에 저장합니다. 우리는{{domxref("Window.alert()", "Window.alert()")}} 을 5번째 줄에 사용하여 두 개의 문자열 리터럴 및 변수의 값이 포함된 다른 팝업을 표시합니다.</p> + +<h3 id="숫자_vs_문자열">숫자 vs 문자열</h3> + +<ol> + <li>그러면 문자열과 숫자를 추가 (또는 연결) 하면 어떻게 될까요? 콘솔에서 사용해 보겠습니다. + <pre class="brush: js">'Front ' + 242; +</pre> + 이 경우 오류가 발생할 것으로 예상할 수 있지만 잘 작동합니다. 숫자로 문자열을 나타내려는 것은 말이 안되지만 숫자를 문자열로 표현하는 것은 의미가 있습니다. 그래서 브라우저는 숫자를 문자열로 변환하고 두 문자열을 서로 연결시킵니다.</li> + <li> 숫자 두 개로도 연결할 수 있습니다 — 따옴표로 감싸면 숫자를 강제로 문자열로 만들 수 있습니다. 아래 코드를 실행해보세요(아래 코드에서 변수가 숫자인지 문자열인지를 확인하기 위해 <code>typeof</code> 연산자를 사용합니다.): + <pre class="brush: js">var myDate = '19' + '67'; +typeof myDate;</pre> + </li> + <li>만약 코드에 문자열로 바꾸고 싶은 숫자형 변수가 있지만 변수 자체의 값을 바꾸고 싶지 않거나 숫자로 바꾸고 싶은 문자열 변수가 있지만 변수 자체의 값을 바꾸고 싶지 않으면 아래와 같은 생성자를 사용할 수 있습니다: + <ul> + <li>{{jsxref("Number")}} 객체는 가능하면 어떠한 입력값이건 숫자로 바꿉니다. 다음 코드를 실행해보세요: + <pre class="brush: js">var myString = '123'; +var myNum = Number(myString); +typeof myNum;</pre> + </li> + <li>반면, 모든 숫자는 <code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toString">toString()</a></code> 이라는 함수를 가지고 있습니다. 이 함수는 숫자를 동등한 문자열로 변환합니다. 다음 코드를 실행해보세요: + <pre class="brush: js">var myNum = 123; +var myString = myNum.toString(); +typeof myString;</pre> + </li> + </ul> + 이 생성자들은 어떤 상황에서는 정말 유용할 수 있습니다. 예를 들어, 만약 어떤 사용자가 숫자를 텍스트 필드 폼에 입력하면, 그 입력 값은 문자열일 것입니다. 하지만 만약 여러분이 이 숫자를 어떤 값에다 더하고 싶다면, 이 입력 값을 숫자로 변환해야 합니다. 이 경우 <code>Number()</code> 에 이 값을 넘겨줘서 이 문제를 해결할 수 있습니다.우리는 이미 <a href="https://github.com/mdn/learning-area/blob/master/javascript/introduction-to-js-1/first-splash/number-guessing-game.html#L61">Number Guessing Game, in line 61</a> 에서 이를 사용한 적이 있습니다.</li> +</ol> + +<h2 id="마치며">마치며</h2> + +<p>여기까지 자바스크립트에서 다루는 문자열의 기본이었습니다. 다음 글에서는 자바스크립트에서 문자열에 사용할 수 있는 기본 제공 메소드를 조작하는 방법에 대해 알아보겠습니다.</p> + +<p>{{PreviousMenuNext("Learn/JavaScript/First_steps/Math", "Learn/JavaScript/First_steps/Useful_string_methods", "Learn/JavaScript/First_steps")}}</p> + + + +<h2 id="In_this_module">In this module</h2> + +<ul> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/What_is_JavaScript">What is JavaScript?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/A_first_splash">A first splash into JavaScript</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/What_went_wrong">What went wrong? Troubleshooting JavaScript</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Variables">Storing the information you need — Variables</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Math">Basic math in JavaScript — numbers and operators</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Strings">Handling text — strings in JavaScript</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Useful_string_methods">Useful string methods</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Arrays">Arrays</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Silly_story_generator">Assessment: Silly story generator</a></li> +</ul> diff --git a/files/ko/learn/javascript/first_steps/useful_string_methods/index.html b/files/ko/learn/javascript/first_steps/useful_string_methods/index.html new file mode 100644 index 0000000000..81c18061a0 --- /dev/null +++ b/files/ko/learn/javascript/first_steps/useful_string_methods/index.html @@ -0,0 +1,461 @@ +--- +title: 문자열 제대로 다루기 +slug: Learn/JavaScript/First_steps/Useful_string_methods +translation_of: Learn/JavaScript/First_steps/Useful_string_methods +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/JavaScript/First_steps/Strings", "Learn/JavaScript/First_steps/Arrays", "Learn/JavaScript/First_steps")}}</div> + +<p class="summary"><span style="background-color: #fefefe; color: #000000; display: inline !important; float: none; font-family: Arial,Tahoma,Helvetica,sans-serif; font-size: 14px; font-style: normal; font-weight: normal; letter-spacing: normal; text-align: left; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal;">이제까지 문자열의 기초를 살펴보았습니다. 이제부터 - 텍스트 문자열의 길이 찾기, 문자열 합치기 및 쪼개기 등과 같은- 내장된 메서드를 사용하여 문자열에서 수행할 수 있는 유용한 작업에 대해 생각해 봅시다. 문자열의 한 문자를 다른 문자로 대체하는 등의 작업을 수행합니다.</span></p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row"><span style="color: #252525; display: inline !important; float: none; font-family: Roboto,arial,sans-serif; font-size: 18px; font-style: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal;">선수 과목 :</span></th> + <td> + <p><span style="color: #252525; display: inline !important; float: none; font-family: Roboto,arial,sans-serif; font-size: 18px; font-style: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal;">기본 컴퓨터 활용 능력, HTML 및 CSS에 대한 기본적인 이해, JavaScript가 무엇인지 이해합니다.</span></p> + </td> + </tr> + <tr> + <th scope="row"><span style="color: #252525; display: inline !important; float: none; font-family: Roboto,arial,sans-serif; font-size: 18px; font-style: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal;">목표:</span></th> + <td><span style="background-color: #fefefe; color: #000000; display: inline !important; float: none; font-family: Arial,Tahoma,Helvetica,sans-serif; font-size: 14px; font-style: normal; font-weight: normal; letter-spacing: normal; text-align: left; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal;">문자열이 객체임을 이해하고, 해당 객체에서 사용할 수있는 몇 가지 기본 메서드를 사용하여 문자열을 조작하는 방법을 배웁니다.</span></td> + </tr> + </tbody> +</table> + +<h2 id="Strings_as_objects">Strings as objects</h2> + +<p id="Useful_string_methods">이전에 말했지만, 다시 말하면 - JavaScript의 모든 것이 객체입니다. 문자열을 만들 때, 예를 들면</p> + +<pre class="brush: js notranslate">var string = 'This is my string';</pre> + +<p><span style="color: #252525; display: inline !important; float: none; font-family: Roboto,arial,sans-serif; font-size: 18px; font-style: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal;">변수가 문자열 객체 인스턴스되면, 결과적으로 수많은 속성과 메서드가 사용 가능하게 됩니다. <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String">String</a> 객체 페이지로 이동하여 페이지 측면의 목록을 내려다 보면 이것을 볼 수 있습니다!</span></p> + +<p><span style="color: #252525; display: inline !important; float: none; font-family: Roboto,arial,sans-serif; font-size: 18px; font-style: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal;">이제 뇌가 녹기 시작하기 전에, 걱정하지 마십시오! 학습 여행 중에 초기에 대부분을 알 필요가 없습니다. 그러나 여기에서 살펴볼 몇 가지 사항을 자주 사용하게 될 것입니다.</span></p> + +<p>콘솔에 예제를 작성해 보세요. 아래의 한 가지를 제공합니다(새 탭이나 새 창에서 콘솔을 열 수 있고, 브라우저의 개발자 콘솔을 사용할 수도 있습니다).</p> + +<div class="hidden"> +<h6 id="Hidden_code">Hidden code</h6> + +<pre class="brush: html notranslate"><!DOCTYPE html> +<html> + <head> + <meta charset="utf-8"> + <title>JavaScript console</title> + <style> + * { + box-sizing: border-box; + } + + html { + background-color: #0C323D; + color: #809089; + font-family: monospace; + } + + body { + max-width: 700px; + } + + p { + margin: 0; + width: 1%; + padding: 0 1%; + font-size: 16px; + line-height: 1.5; + float: left; + } + + .input p { + margin-right: 1%; + } + + .output p { + width: 100%; + } + + .input input { + width: 96%; + float: left; + border: none; + font-size: 16px; + line-height: 1.5; + font-family: monospace; + padding: 0; + background: #0C323D; + color: #809089; + } + + div { + clear: both; + } + + </style> + </head> + <body> + + + </body> + + <script> + var geval = eval; + function createInput() { + var inputDiv = document.createElement('div'); + var inputPara = document.createElement('p'); + var inputForm = document.createElement('input'); + + inputDiv.setAttribute('class', 'input'); + inputPara.textContent = '>'; + inputDiv.appendChild(inputPara); + inputDiv.appendChild(inputForm); + document.body.appendChild(inputDiv); + + inputForm.addEventListener('change', executeCode); + } + + function executeCode(e) { + try { + var result = geval(e.target.value); + } catch(e) { + var result = 'error — ' + e.message; + } + + var outputDiv = document.createElement('div'); + var outputPara = document.createElement('p'); + + outputDiv.setAttribute('class','output'); + outputPara.textContent = 'Result: ' + result; + outputDiv.appendChild(outputPara); + document.body.appendChild(outputDiv); + + e.target.disabled = true; + e.target.parentNode.style.opacity = '0.5'; + + createInput() + } + + createInput(); + + </script> +</html></pre> +</div> + +<p>{{ EmbedLiveSample('Hidden_code', '100%', 300) }}</p> + +<h3 id="문자열의_길이_찾기">문자열의 길이 찾기</h3> + +<p>간단합니다 — 간단하게 {{jsxref("String.prototype.length", "length")}} 프로퍼티를 사용할 수 있습니다. 다음 코드를 입력해 보세요.</p> + +<pre class="brush: js notranslate">var browserType = 'mozilla'; +browserType.length;</pre> + +<p>결과는 7을 리턴해야 합니다. 'mozilla'는 7글자이기 때문입니다. 이것은 여러 가지 이유로 유용합니다. 예를 들어 이름의 길이에 따라 이름의 순서를 정렬해야 하던가, 유저가 작성한 이름이 특정 길이 이상일 때 너무 길다는 것을 알려줘야 하는 경우에 사용할 수 있습니다.</p> + +<h3 id="특정_문자열_찾기">특정 문자열 찾기</h3> + +<p>관련하여, 대괄호 표기법을 이용해서 문자열 안의 문자를 구할 수 있습니다. 대괄호 표기법은 변수명 끝에 대괄호를 포함합니다. 대괄호 안에는 구하고 싶은 문자의 숫자를 포함시키면 되며, 예를 들어 아래의 경우 첫 번째 문자를 구할 수 있습니다:</p> + +<pre class="brush: js notranslate">browserType[0];</pre> + +<p>컴퓨터는 1이 아니라 0부터 숫자를 셉니다! 문자열의 마지막 문자를 구하기 위해서, 우리는 다음 코드를 사용할 수 있으며, 기술적인 <code>length</code> 프로퍼티과 같이 사용하면 아래와 같습니다:</p> + +<pre class="brush: js notranslate">browserType[browserType.length-1];</pre> + +<p>"mozilla"는 7글자이지만, 숫자는 0부터 시작하기 때문에 글자의 위치는 6입니다. 그렇기 때문에 <code>length-1</code>을 사용합니다. 예를 들어, 여러 문자열 중 첫 번째 문자를 찾아 알파벳순으로 정렬해야 할 경우에 사용할 수 있습니다.</p> + +<h3 id="문자열_내부의_하위_문자열_찾기_및_추출">문자열 내부의 하위 문자열 찾기 및 추출</h3> + +<ol> + <li>때때로 큰 문자열 안의 작은 문자열(우리는 이것을 하위 문자열이라고 이야기 한다.)을 찾고 싶을 것입니다. 이 작업은 {{jsxref("String.prototype.indexOf()", "indexOf()")}}를 사용하여 완료할 수 있습니다, which takes a single {{glossary("parameter")}} — 찾기 원하는 하위 문자열을 찾을 수 있습니다. 시도해 봅시다: + <pre class="brush: js notranslate">browserType.indexOf('zilla');</pre> + 결과는 2입니다. 하위 문자열인 "zilla"는 "mozilla'의 2번 위치(0, 1, 2— 그러므로 3번째 문자열)에서 시작합니다. 이러한 코드는 문자열을 필터링하는 데 사용될 수 있습니다. 예를 들어 웹 주소 목록에서 "mozilla"가 포함된 주소만 인쇄하고 싶은 경우입니다.</li> + <li>다른 방법으로도 할 수 있으며, 더욱 효율적일 수 있습니다. 다음 예제를 따라해 봅시다: + <pre class="brush: js notranslate">browserType.indexOf('vanilla');</pre> + 이렇게 하면 -1( 하위 문자열 (이 경우 'vanilla')이 기본 문자열에서 발견되지 않으면 반환한다.)의 결과를 얻을 수 있습니다.<br> + <br> + 하위 문자열 'mozilla'가 포함되지 않은 문자열의 모든 인스턴스를 찾으려면 이 연산자를 사용하고 아래에 표시된 것처럼 부정 연산자를 사용해서 작업을 수행할 수 있습니다. 다음과 같이 할 수 있습니다: + <pre class="brush: js notranslate">if(browserType.indexOf('mozilla') !== -1) { + // do stuff with the string +}</pre> + </li> + <li>문자열 내에서 부분 문자열이 어디에서 시작되고 어떤 문자로 끝나는지 알고 싶으면 {{jsxref("String.prototype.slice()", "slice()")}}를 사용하여 문자열을 추출할 수 있습니다. 다음을 시도해 봅시다: + <pre class="brush: js notranslate">browserType.slice(0,3);</pre> + "moz"를 반환합니다 - 첫 번째 파라메터는 추출을 시작할 문자 위치이고 두 번째 파라메터는 추출할 문자의 갯수입니다. 따라서 슬라이스는 첫 번째 위치에서부터 세 번째 위치까지 포함됩니다.</li> + <li>또한 특정 문자 뒤에 문자열의 나머지 문자를 모두 추출하려는 경우 두 번째 매개 변수를 포함하지 않고 문자열에서 나머지 문자를 추출할 위치의 문자 위치만 포함하면 됩니다. 다음을 시도해보십시오. + <pre class="brush: js notranslate">browserType.slice(2);</pre> + 이렇게 하면 "zilla"가 반환됩니다. 문자의 2번째 위치는 "z"이고 두 번째 매개 변수를 포함하지 않았기 때문에 반환된 하위 문자열은 문자열의 나머지 문자 모두입니다.</li> +</ol> + +<div class="note"> +<p><strong>Note</strong>: <code>slice()</code>의 두 번째 매개 변수는 선택사항입니다 : 이를 포함하지 않으면 <code>slice()</code>는 원래 문자열의 끝에 끝납니다. 게다가 다른 매개변수도 존재합니다.{{jsxref("String.prototype.slice()", "slice()")}} 페이지를 방문하여 더 자세하게 알 수 있습니다.</p> +</div> + +<h3 id="대소문자_변경">대/소문자 변경</h3> + +<p>문자열 메소드 {{jsxref("String.prototype.toLowerCase()", "toLowerCase()")}} 와{{jsxref("String.prototype.toUpperCase()", "toUpperCase()")}} 는 문자열을 가져와 그것을 모두 각각 대문자나 소문자로 바꿉니다. 이는 데이터베이스에 저장하기 전에 모든 사용자 입력 데이터를 표준화하려는 경우 유용합니다.</p> + +<p>다음 행을 입력하여 어떻게 되는지 살펴보겠습니다.</p> + +<pre class="brush: js notranslate">var radData = 'My NaMe Is MuD'; +radData.toLowerCase(); +radData.toUpperCase();</pre> + +<h3 id="문자열의_일부를_변경하기">문자열의 일부를 변경하기</h3> + +<p>문자열 내의 한 하위 문자열을 {{jsxref("String.prototype.replace()", "replace()")}} 를 통해 다른 하위 문자열로 바꿀 수 있습니다. 이 작업은 기본적인 수준에서 매우 간단하게 작동합니다. 하지만 아직 시도해보지 않은 고급 작업도 있습니다.</p> + +<p>그것은 2개의 매개변수를 가집니다. — 바뀜을 당하는 문자와 바꾸려는 문자입니다. 다음 예제를 따라해보세요.:</p> + +<pre class="brush: js notranslate">browserType.replace('moz','van');</pre> + +<h2 id="예제">예제</h2> + +<p>이 섹션에서는 문자열을 다루는 방법을 설명합니다. 아래의 각 실습에서는 문자열로 이루어진 배열을 루프문을 사용해 bullet list(불릿 리스트)로 표현하였습니다. 지금 배열이나 루프를 이해할 필요가 없습니다. - 이러한 내용은 추후에 설명합니다. 중요한것은 각각의 문자열이 우리가 원하는 형식으로 출력하는 코드를 작성하는 것입니다.</p> + +<p>각 예제에는 리셋 버튼이 있고, 리셋 버튼은 실수를 했거나 코드가 작동하지 않아서 재설정하는데 사용할 수 있습니다. 해결 방법을 모를 때, 해답 버튼(solution button)을 누르면 해답을 볼 수 있습니다.</p> + +<h3 id="인사말_필터링_하기">인사말 필터링 하기</h3> + +<p>첫 번째 예제는 간단히 시작해봅시다. 우리는 배열에 들어있는 크리스마스 인사말 메시지를 정렬하려고 합니다. if(...)을 사용해 각 문자열을 비교하고 크리스마스 메시지인 경우의 목록만 인쇄하려고 합니다.</p> + +<ol> + <li>먼저 각 메시지가 크리스마스 메시지인지 여부를 테스트할 수 있는 방법을 생각해봅시다. 메시지들은 어떤 문자열이 있고, 존재하는지 테스트하기 위해 어떤 방법을 사용할 수 있을까요?</li> + <li>연산자와 피연산자를 사용해 조건문을 만들어야 합니다. 연산자 왼쪽에 있는것과 연산자 오른쪽에 있는 것이 동등한가요? 또는 이 경우 왼쪽 메서드가 오른쪽으로 결과값을 전달합니까?</li> + <li>힌트 : 이 경우 메서드 호출이 결과값과 같지 않은지 테스트하는 것이 더 유용할 수 있습니다.</li> +</ol> + +<div class="hidden"> +<h6 id="Playable_code">Playable code</h6> + +<pre class="brush: html notranslate"><div class="output" style="min-height: 125px;"> + +<ul> + +</ul> + +</div> + +<textarea id="code" class="playable-code" style="height: 290px;"> +var list = document.querySelector('.output ul'); +list.innerHTML = ''; +var greetings = ['Happy Birthday!', + 'Merry Christmas my love', + 'A happy Christmas to all the family', + 'You\'re all I want for Christmas', + 'Get well soon']; + +for (var i = 0; i < greetings.length; i++) { + var input = greetings[i]; + // Your conditional test needs to go inside the parentheses + // in the line below, replacing what's currently there + if (greetings[i]) { + var result = input; + var listItem = document.createElement('li'); + listItem.textContent = result; + list.appendChild(listItem); + } +} +</textarea> + +<div class="playable-buttons"> + <input id="reset" type="button" value="Reset"> + <input id="solution" type="button" value="Show solution"> +</div> +</pre> + +<pre class="brush: js notranslate">var textarea = document.getElementById('code'); +var reset = document.getElementById('reset'); +var solution = document.getElementById('solution'); +var code = textarea.value; + +function updateCode() { + eval(textarea.value); +} + +reset.addEventListener('click', function() { + textarea.value = code; + updateCode(); +}); + +solution.addEventListener('click', function() { + textarea.value = jsSolution; + updateCode(); +}); + +var jsSolution = 'var list = document.querySelector(\'.output ul\');\nlist.innerHTML = \'\';\nvar greetings = [\'Happy Birthday!\',\n \'Merry Christmas my love\',\n \'A happy Christmas to all the family\',\n \'You\\\'re all I want for Christmas\',\n \'Get well soon\'];\n\nfor(var i = 0; i < greetings.length; i++) {\n var input = greetings[i];\n if(greetings[i].indexOf(\'Christmas\') !== -1) {\n var result = input;\n var listItem = document.createElement(\'li\');\n listItem.textContent = result;\n list.appendChild(listItem);\n }\n}'; + +textarea.addEventListener('input', updateCode); +window.addEventListener('load', updateCode); +</pre> +</div> + +<p>{{ EmbedLiveSample('Playable_code', '100%', 490) }}</p> + +<h3 id="대소문자_맞게_수정하기">대/소문자 맞게 수정하기</h3> + +<p>이 예제에는 영국 도시의 이름들을 모아놨습니다만 대/소문자가 잘못되어 있습니다. 우리는 이 문자들을 첫 번째 문자를 제외하고 모두 소문자로 변경해야 합니다. 이것은 다음과 같은 방식으로 할 수 있습니다:</p> + +<ol> + <li><code>input</code> 변수에 담긴 문자열 전체를 소문자로 변환한 후 새로운 변수에 저장하세요.</li> + <li>새로운 변수에 저장된 문자열의 첫 문자를 다른 변수에 저장하세요</li> + <li>Using this latest variable as a substring, replace the first letter of the lowercase string with the first letter of the lowercase string changed to upper case. Store the result of this replace procedure in another new variable.</li> + <li>Change the value of the <code>result</code> variable to equal to the final result, not the <code>input</code>.</li> +</ol> + +<div class="note"> +<p><strong>Note</strong>: A hint — the parameters of the string methods don't have to be string literals; they can also be variables, or even variables with a method being invoked on them.</p> +</div> + +<div class="hidden"> +<h6 id="Playable_code_2">Playable code 2</h6> + +<pre class="brush: html notranslate"><div class="output" style="min-height: 125px;"> + +<ul> + +</ul> + +</div> + +<textarea id="code" class="playable-code" style="height: 250px;"> +var list = document.querySelector('.output ul'); +list.innerHTML = ''; +var cities = ['lonDon', 'ManCHESTer', 'BiRmiNGHAM', 'liVERpoOL']; +for(var i = 0; i < cities.length; i++) { + var input = cities[i]; + // write your code just below here + + var result = input; + var listItem = document.createElement('li'); + listItem.textContent = result; + list.appendChild(listItem); +} +</textarea> + +<div class="playable-buttons"> + <input id="reset" type="button" value="Reset"> + <input id="solution" type="button" value="Show solution"> +</div> +</pre> + +<pre class="brush: js notranslate">var textarea = document.getElementById('code'); +var reset = document.getElementById('reset'); +var solution = document.getElementById('solution'); +var code = textarea.value; + +function updateCode() { + eval(textarea.value); +} + +reset.addEventListener('click', function() { + textarea.value = code; + updateCode(); +}); + +solution.addEventListener('click', function() { + textarea.value = jsSolution; + updateCode(); +}); + +var jsSolution = 'var list = document.querySelector(\'.output ul\');\nlist.innerHTML = \'\';\nvar cities = [\'lonDon\', \'ManCHESTer\', \'BiRmiNGHAM\', \'liVERpoOL\'];\n\nfor(var i = 0; i < cities.length; i++) {\n var input = cities[i];\n var lower = input.toLowerCase();\n var firstLetter = lower.slice(0,1);\n var capitalized = lower.replace(firstLetter,firstLetter.toUpperCase());\n var result = capitalized;\n var listItem = document.createElement(\'li\');\n listItem.textContent = result;\n list.appendChild(listItem);\n\n}'; + +textarea.addEventListener('input', updateCode); +window.addEventListener('load', updateCode); +</pre> +</div> + +<p>{{ EmbedLiveSample('Playable_code_2', '100%', 450) }}</p> + +<h3 id="Making_new_strings_from_old_parts">Making new strings from old parts</h3> + +<p>In this last exercise the array contains a bunch of strings containing information about train stations in the North of England. The strings are data items that contain the three letter station code, followed by some machine-readable data, followed by a semi-colon, followed by the human-readable station name. For example:</p> + +<pre class="notranslate">MAN675847583748sjt567654;Manchester Piccadilly</pre> + +<p>We want to extract the station code and name, and put them together in a string with the following structure:</p> + +<pre class="notranslate">MAN: Manchester Piccadilly</pre> + +<p>We'd recommend doing it like this:</p> + +<ol> + <li>Extract the three-letter station code and store it in a new variable.</li> + <li>Find the character index number of the semi-colon.</li> + <li>Extract the human-readable station name using the semi-colon character index number as a reference point, and store it in a new variable.</li> + <li>Concatenate the two new variables and a string literal to make the final string.</li> + <li>Change the value of the <code>result</code> variable to equal to the final string, not the <code>input</code>.</li> +</ol> + +<div class="hidden"> +<h6 id="Playable_code_3">Playable code 3</h6> + +<pre class="brush: html notranslate"><div class="output" style="min-height: 125px;"> + +<ul> + +</ul> + +</div> + +<textarea id="code" class="playable-code" style="height: 285px;"> +var list = document.querySelector('.output ul'); +list.innerHTML = ''; +var stations = ['MAN675847583748sjt567654;Manchester Piccadilly', + 'GNF576746573fhdg4737dh4;Greenfield', + 'LIV5hg65hd737456236dch46dg4;Liverpool Lime Street', + 'SYB4f65hf75f736463;Stalybridge', + 'HUD5767ghtyfyr4536dh45dg45dg3;Huddersfield']; + +for (var i = 0; i < stations.length; i++) { + var input = stations[i]; + // write your code just below here + + var result = input; + var listItem = document.createElement('li'); + listItem.textContent = result; + list.appendChild(listItem); +} +</textarea> + +<div class="playable-buttons"> + <input id="reset" type="button" value="Reset"> + <input id="solution" type="button" value="Show solution"> +</div> +</pre> + +<pre class="brush: js notranslate">var textarea = document.getElementById('code'); +var reset = document.getElementById('reset'); +var solution = document.getElementById('solution'); +var code = textarea.value; + +function updateCode() { + eval(textarea.value); +} + +reset.addEventListener('click', function() { + textarea.value = code; + updateCode(); +}); + +solution.addEventListener('click', function() { + textarea.value = jsSolution; + updateCode(); +}); + +var jsSolution = 'var list = document.querySelector(\'.output ul\');\nlist.innerHTML = \'\';\nvar stations = [\'MAN675847583748sjt567654;Manchester Piccadilly\',\n \'GNF576746573fhdg4737dh4;Greenfield\',\n \'LIV5hg65hd737456236dch46dg4;Liverpool Lime Street\',\n \'SYB4f65hf75f736463;Stalybridge\',\n \'HUD5767ghtyfyr4536dh45dg45dg3;Huddersfield\'];\n\nfor(var i = 0; i < stations.length; i++) {\n var input = stations[i];\n var code = input.slice(0,3);\n var semiC = input.indexOf(\';\');\n var name = input.slice(semiC + 1);\n var final = code + \': \' + name;\n var result = final;\n var listItem = document.createElement(\'li\');\n listItem.textContent = result;\n list.appendChild(listItem);\n}'; + + +textarea.addEventListener('input', updateCode); +window.addEventListener('load', updateCode); +</pre> +</div> + +<p>{{ EmbedLiveSample('Playable_code_3', '100%', 485) }}</p> + +<h2 id="결론">결론</h2> + +<p>자바스크립트에서 문장과 단어들을 다룰 수 있는 프로그래밍 능력이 매우 중요하다. 웹사이트는 사람들과 소통하는 공간이기 때문이다. 이 문서는 문자열을 다룰 수 있는 기초적인 내용에 대해 다루었다. 이 내용은 앞으로 배우게 될 심화 과정에 도움이 될 것이다. 다음으로 배열에 대해 알아보겠다.</p> + +<p>{{PreviousMenuNext("Learn/JavaScript/First_steps/Strings", "Learn/JavaScript/First_steps/Arrays", "Learn/JavaScript/First_steps")}}</p> diff --git a/files/ko/learn/javascript/first_steps/variables/index.html b/files/ko/learn/javascript/first_steps/variables/index.html new file mode 100644 index 0000000000..7d4b2adf4e --- /dev/null +++ b/files/ko/learn/javascript/first_steps/variables/index.html @@ -0,0 +1,360 @@ +--- +title: 필요한 정보를 저장하기-변수 +slug: Learn/JavaScript/First_steps/Variables +translation_of: Learn/JavaScript/First_steps/Variables +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/JavaScript/First_steps/What_went_wrong", "Learn/JavaScript/First_steps/Math", "Learn/JavaScript/First_steps")}}</div> + +<p class="summary">앞선 두 수업을 듣고, 자바스크립트에 대해(웹 기술에서 어떻게 사용되는지, 큰 범위에서의 특징) 알아보았다. 이번 수업에서는 기본중에 기본인 자바스크립트의 주된 구성중 하나인 변수가 어떻게 이루어져 있는지 알아볼 것이다.</p> + +<table class="learn-box"> + <tbody> + <tr> + <th scope="row">알아야 할 것</th> + <td>기본적인 컴퓨터 지식, 기본적인 HTML, CSS, JS의 이해</td> + </tr> + <tr> + <th scope="row">목표</th> + <td>자바스크립트 변수에 대해 익혀보기</td> + </tr> + </tbody> +</table> + +<h2 id="필요한_툴">필요한 툴</h2> + +<p>이번 수업에서 컨텐츠에 대한 이해도를 테스트하고자, 코드를 입력하라는 요청을 받게 될 것이다. 만약 데스크탑 브라우저를 사용한다면, 코드를 실행하기 가장 좋은 프로그램은 브라우저의 자바스크립트 콘솔창일 것이다.(도구의 사용법에 대해 알고자 한다면 <a href="/en-US/docs/Learn/Common_questions/What_are_browser_developer_tools">What are browser developer tools</a> 를 참고하자)</p> + +<h2 id="변수란">변수란?</h2> + +<p>변수란, 숫자(합계나 계산에 사용되는) 또는 문자열(문장의 일부로 사용되는)과 같은 값의 컨테이너입니다. 그러나 변수에 대한 한 가지 특별한 점은 포함된 값이 변경될 수 있다는 것입니다. 간단한 예를 살펴 보겠습니다:</p> + +<pre class="brush: html"><button>Press me</button></pre> + +<pre class="brush: js">const button = document.querySelector('button'); + +button.onclick = function() { + let name = prompt('What is your name?'); + alert('Hello ' + name + ', nice to see you!'); +}</pre> + +<p>{{ EmbedLiveSample('What_is_a_variable', '100%', 50, "", "", "hide-codepen-jsfiddle") }}</p> + +<p>이 예제에서 버튼을 누르면 몇 줄의 코드가 실행됩니다. 첫 번째 줄은 독자가 이름을 입력하도록 요청한 화면에 상자를 띄운 다음, 변수에 값을 저장합니다. 두 번째 줄은 변수 값에서 가져온, 이름이 포함된 환영 메시지가 표시됩니다. </p> + +<p>왜 변수가 유용한 지 이해하려면, 변수를 사용하지 않고 이 예제를 작성하는 방법에 대해 생각해 봅시다. 그러면 아마 이런 식으로 끝날 것입니다 :</p> + +<pre class="example-bad">let name = prompt('What is your name?'); + +if (name === 'Adam') { + alert('Hello Adam, nice to see you!'); +} else if (name === 'Alan') { + alert('Hello Alan, nice to see you!'); +} else if (name === 'Bella') { + alert('Hello Bella, nice to see you!'); +} else if (name === 'Bianca') { + alert('Hello Bianca, nice to see you!'); +} else if (name === 'Chris') { + alert('Hello Chris, nice to see you!'); +} + +// ... and so on ...</pre> + +<p>우리가 사용하고있는 구문을 완전히 이해하지는 못했지만, 아이디어를 얻을 수 있어야 합니다-변수를 사용할 수 없다면, 입력된 이름을 검사하는 거대한 코드 블록을 구현해야합니다. 그런 다음 해당 이름에 대한 각각의 메시지를 출력해야 합니다. 이것은 분명히 비효율적입니다 (코드는 네 가지 선택만으로도 훨씬 더 커집니다). 그리고 가능한 모든 선택 사항(모든 이름들)을 저장할 수 없어 작동하지 않을 수도 있습니다. </p> + +<p>변수는 이해하기 쉽습니다. 자바 스크립트에 대해 더 많이 배우면, 변수들은 자연스럽게 느껴질 것입니다. </p> + +<p>변수에 대한 또 다른 특별한 점은 문자열과 숫자뿐 아니라 무엇이든 포함 할 수 있다는 것입니다. 변수에는 복잡한 데이터와 놀랄만 한 기능을 수행하는 함수(Function)까지 포함될 수 있습니다. 당신은 이것에 대해 점점 더 많이 배울 것입니다. <br> + <br> + 변수는 값을 포함하고 있습니다. 이것은 중요한 차이점입니다. 변수는 값 자체가 아닙니다. 변수는 값을 위한 컨테이너입니다. 당신은 변수란 물건들을 저장할 수있는 작은 골판지 상자와 같다고 생각할 수 있습니다.</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/13506/boxes.png" style="display: block; height: 436px; margin: 0px auto; width: 1052px;"></p> + +<h2 id="변수의_선언">변수의 선언</h2> + +<p>변수를 사용하기 위해서, 먼저 변수를 선언해야 합니다 - 보다 정확히는, 변수를 선언한다고 부른다. 이를 위해 키워드 var를 입력하고, 당신이 원하는 변수 이름을 입력합니다.</p> + +<pre class="brush: js">var myName; +var myAge;</pre> + +<p>여기서 우리는 myName과 myAge라는 두 개의 변수를 생성합니다. 웹 브라우저의 콘솔 또는 아래 콘솔에서 두행을 입력해 보십시오 (원하는 경우, <a href="https://mdn.github.io/learning-area/javascript/introduction-to-js-1/variables/index.html">콘솔</a>을 별도의 탭이나 창에서 열 수 있음). 그 후, 자신이 명명한 변수를 만들어 보십시오.</p> + +<div class="hidden"> +<h6 id="Hidden_code">Hidden code</h6> + +<pre class="brush: html"><!DOCTYPE html> +<html> + <head> + <meta charset="utf-8"> + <title>JavaScript console</title> + <style> + * { + box-sizing: border-box; + } + + html { + background-color: #0C323D; + color: #809089; + font-family: monospace; + } + + body { + max-width: 700px; + } + + p { + margin: 0; + width: 1%; + padding: 0 1%; + font-size: 16px; + line-height: 1.5; + float: left; + } + + .input p { + margin-right: 1%; + } + + .output p { + width: 100%; + } + + .input input { + width: 96%; + float: left; + border: none; + font-size: 16px; + line-height: 1.5; + font-family: monospace; + padding: 0; + background: #0C323D; + color: #809089; + } + + div { + clear: both; + } + + </style> + </head> + <body> + + + </body> + + <script> + var geval = eval; + function createInput() { + var inputDiv = document.createElement('div'); + var inputPara = document.createElement('p'); + var inputForm = document.createElement('input'); + + inputDiv.setAttribute('class','input'); + inputPara.textContent = '>'; + inputDiv.appendChild(inputPara); + inputDiv.appendChild(inputForm); + document.body.appendChild(inputDiv); + + inputForm.addEventListener('change', executeCode); + } + + function executeCode(e) { + try { + var result = geval(e.target.value); + } catch(e) { + var result = 'error — ' + e.message; + } + + var outputDiv = document.createElement('div'); + var outputPara = document.createElement('p'); + + outputDiv.setAttribute('class','output'); + outputPara.textContent = 'Result: ' + result; + outputDiv.appendChild(outputPara); + document.body.appendChild(outputDiv); + + e.target.disabled = true; + e.target.parentNode.style.opacity = '0.5'; + + createInput() + } + + createInput(); + + </script> +</html></pre> +</div> + +<p>{{ EmbedLiveSample('Hidden_code', '100%', 300) }}</p> + +<div class="note"> +<p><strong>Note</strong>: JavaScript에서는 모든 코드 명령어가 세미콜론 (;)으로 끝나야합니다. 코드를 한 줄로 작성해도 올바르게 작동할 지라도, 여러 줄의 코드를 함께 작성하는 경우에는 그렇지 않습니다. 그것을 포함시키는 습관을 갖도록 노력하십시오.</p> +</div> + +<p>변수 이름을 입력하여 변수의 값이 실행 환경에 존재하는지 테스트 할 수 있습니다.</p> + +<pre class="brush: js">myName; +myAge;</pre> + +<p>이 변수들은 값을 포함하고 있지 않은 빈 컨테이너 입니다. 변수 이름만 입력 할 경우 <code>undefined</code> 값을 반환하며 변수는 이 값(<code>undefined)</code>을 포함하게 됩니다. 만약 존재하지 않는(선언되지 않은) 변수는, 오류 메시지가 표시됩니다. 아래 변수를 입력하여 확인해 보세요.</p> + +<pre class="brush: js">scoobyDoo;</pre> + +<div class="note"> +<p><strong>Note</strong>: 존재하지만 값을 포함하고 있지 않은 변수와, 존재하지 않은 변수를 혼돈하지 마십시오. 둘은 매우 다른 것들입니다.</p> +</div> + +<h2 id="변수의_초기화">변수의 초기화</h2> + +<p>변수를 선언한 후에는 값으로 초기화 할 수 있습니다. 변수 이름 다음에 등호(<code>=</code>)와 그 뒤에 부여 할 값을 입력하여 이 작업을 수행 할 수 있습니다.</p> + +<pre class="brush: js">myName = 'Chris'; +myAge = 37;</pre> + +<p>콘솔로 돌아가 코드들을 입력해 보세요. 각각의 경우 변수에 할당한 값은 콘솔을 통해 반환되어 확인 할 수 있습니다. 또한 단순히 변수 이름을 입력하여 변수 값을 반환 할 수 있습니다. 한번 해보세요.</p> + +<pre class="brush: js">myName; +myAge;</pre> + +<p>다음과 같이 변수를 선언하고 동시에 초기화 할 수 있습니다.</p> + +<pre class="brush: js">var myName = 'Chris';</pre> + +<p>아마도 변수의 선언과 초기화를 두줄로 나누어 하는것 보다 더 빠르기 때문에 대부분 이러한 방식을 자주 사용 하게 될 겁니다.</p> + +<div class="note"> +<p><strong>Note</strong>: 여러 줄 문자열로 JavaScript 프로그램을 작성할 때(write a multiline JavaScript), 변수를 선언하기 전에 해당 변수의 값을 초기화 할 수 있습니다. 이것이 가능한 이유는 JavaScript 에서 일반적으로 변수 선언문이 다른 코드 보다 먼저 실행되기 때문인데, 이 동작을 <strong>호이스팅</strong>이라고 합니다. 자세한 내용은 <a href="/ko/docs/Web/JavaScript/Reference/Statements/var#var_호이스팅(hoisting)">var 호이스팅</a> 문서를 참고하세요.</p> +</div> + +<h2 id="변수의_재지정">변수의 재지정</h2> + +<p>변수에 값이 할당되면 다른 값을 지정하여 해당 값을 업데이트 할 수 있습니다. 콘솔에 다음 행을 입력해 보세요.</p> + +<pre class="brush: js">myName = 'Bob'; +myAge = 40;</pre> + +<h3 id="변수_이름에_대한_규칙">변수 이름에 대한 규칙</h3> + +<p>변수를 원하는 대로 이름을 부여 할 수 있지만 제한이 있습니다. 일반적으로 라틴 문자(0-9, a-z, A-Z)와 밑줄 문자를 사용해야 합니다.</p> + +<ul> + <li>오류가 발생하거나 전 세계 타인이 이해하기 어려울 수 있으므로 다른 문자를 사용하면 안됩니다.</li> + <li>변수 이름의 시작부분에 밑줄(_)을 사용하지 마세요. JavaScript 구문에서 밑줄로 시작하는 것은 특별한 의미를 가지고 있으므로 혼란을 가져올수 있습니다.</li> + <li>변수 이름의 시작부분에 숫자를 사용하지 마세요. 허용되지 않으며 오류가 발생합니다.</li> + <li>안전한 명명법은 소위 <a href="https://en.wikipedia.org/wiki/CamelCase#Variations_and_synonyms">"lower camel case"</a>(소문자 낙타 문법) 입니다. 여러 단어를 하나로 묶고 첫 단어의 시작은 소문자를 사용하며 그다음 단어의 시작은 대문자로 사용합니다. 우리는 지금까지 이 문서에서 변수 이름에 이 방법을 사용해 왔습니다.</li> + <li>포함된 데이터를 쉽게 이해 할 수 있게 변수 이름을 직관적으로 부여 합니다. 단일 문자 / 숫자 또는 긴 구절을 사용하지 마세요.변수 이름을 직관적으로 만들어, 포함된 데이터를 표현 할 수 있습니다. </li> + <li>변수는 대소문자를 구분 합니다. - <code>myage</code> 와 <code>myAge</code> 는 다른 변수 입니다.</li> + <li>마지막으로 JavaScript 예약어를 변수 이름으로 사용하면 안됩니다. (예약어란 JavaScript의 실제 구문을 구성하는 단어를 의미 합니다.) 따라서 변수 이름으로 <code>var</code>, <code>function</code>, <code>let</code>, <code>for</code> 와 같은 단어를 사용 할 수 없습니다. 브라우저는 이러한 단어를 다른 코드 아이템(예약어)로 인식하므로 오류가 발생 합니다.</li> +</ul> + +<div class="note"> +<p><strong>Note</strong>: 다음 <a href="/en-US/docs/Web/JavaScript/Reference/Lexical_grammar#Keywords">Lexical grammar — keywords</a> 링크에서 예약어의 목록을 확인 할 수 있습니다.</p> +</div> + +<p>바람직한 변수 이름의 예:</p> + +<pre class="example-good">age +myAge +init +initialColor +finalOutputValue +audio1 +audio2</pre> + +<p>바람직하지 않은 변수 이름의 예:</p> + +<pre class="example-bad">1 +a +_12 +myage +MYAGE +var +Document +skjfndskjfnbdskjfb +thisisareallylongstupidvariablenameman</pre> + +<p>위의 지침을 염두에 두고 몇가지 변수를 추가로 작성해 보세요.</p> + +<h2 id="변수의_종류">변수의 종류</h2> + +<p>변수에 저장할 수 있는 몇가지 유형의 데이터(데이터 유형)가 있습니다. 이 섹션에서는 이를 간단히 설명하고 이후 자세히 살펴보겠습니다.</p> + +<p>지금까지 우린 두가지 형태의 데이터 유형을 살펴 봤지만 다른 유형들도 있습니다.</p> + +<h3 id="숫자">숫자</h3> + +<p>30과 같은 숫자 (정수라고도 함) 나 2.456(부동소수점 또는 부동 소수점 숫자라고도 함) 같은 십진수 숫자를 변수에 저장할 수 있습니다. JavaScript는 일부 프로그래밍 언어처럼 숫자 유형에 따른 다른 데이터 유형을 가지고 있지 않습니다. 변수에 숫자 값 대입할 때, 따옴표 사용하지 않습니다.</p> + +<pre class="brush: js">var myAge = 17;</pre> + +<h3 id="문자열">문자열</h3> + +<p>문자열은 텍스트의 조각입니다. 변수에 문자열 값을 대입할 때, 작은따옴표(')나 큰따옴표(")로 묶어야 합니다. 그렇지 않으면 JavaScript는 다른 변수 이름으로 해석하게 됩니다.</p> + +<pre class="brush: js">var dolphinGoodbye = 'So long and thanks for all the fish';</pre> + +<h3 id="불리언Booleans">불리언(Booleans)</h3> + +<p>불리언(Booleans)은 <code>true</code> 이나 <code>false</code> 라는 값을 가지는 참/거짓을 표현하는 데이터 유형입니다. 일반적으로 조건을 테스트하는 데 사용되며 그 다음 코드가 조건에 따라 실행됩니다. 예를 들어 다음과 같습니다.</p> + +<pre class="brush: js">var iAmAlive = true;</pre> + +<p>일반적으로 다음과 같은 방식으로 더 많이 사용됩니다.</p> + +<pre class="brush: js">var test = 6 < 3;</pre> + +<p>위의 코드는 "작다" 연산자(<code><</code>) 를 사용하여 6이 3보다 작은지를 확인 합니다. 예상 한대로 6이 3보다 작지 않으므로<code>false</code> 를 반환 합니다! 나중에 이러한 연산자에 대해 더 많이 배우게 됩니다.</p> + +<h3 id="배열">배열</h3> + +<p>배열은 대괄호로 묶이고 쉼표로 구분 된 여러 값을 포함하는 단일 객체입니다. 다음 코드를 콘솔에 입력해 보세요.</p> + +<pre class="brush: js">var myNameArray = ['Chris', 'Bob', 'Jim']; +var myNumberArray = [10,15,40];</pre> + +<p>이러한 배열이 정의되면 다음과 같은 구문을 사용하여 개별 값에 접근 할 수 있습니다. 다음 코드를 입력해 보세요.</p> + +<pre class="brush: js">myNameArray[0]; // should return 'Chris' +myNumberArray[2]; // should return 40</pre> + +<p>대괄호에는 반환할 값의 위치를 지정하는 인덱스 값이 들어 있습니다. 컴퓨터는 우리 사람처럼 1대신 0부터 숫자를 센다는 것을 알 수 있습니다.</p> + +<p>앞으로 배열에 대해 더 많이 배우게 됩니다.</p> + +<h3 id="객체">객체</h3> + +<p>프로그래밍에서 객체(Objects)는 실제 사물(real life object)을 모델링 하는 코드 구조입니다. 예를들어 주차장 객체는 주차장의 높이와 넓이 정보를 가지고 표현 할 수 있으며, 사람 객체는 이름, 키, 몸무게, 사용하는 언어등의 정보를 가지고 표현 할 수 있습니다.</p> + +<p>콘솔에 다음 코드를 입력해 보세요.</p> + +<pre class="brush: js">var dog = { name : 'Spot', breed : 'Dalmatian' };</pre> + +<p>객체에 저장된 정보를 검색하기 위해서는 아래 구문을 사용합니다.</p> + +<pre class="brush: js">dog.name</pre> + +<p>지금은 객체에 대해 더 자세하게 보지 않을 것입니다. - 앞으로 모듈에 있는 객체에 대해 더 많이 배울 수 있습니다.</p> + +<h2 id="지정되지_않은_타입">지정되지 않은 타입</h2> + +<p>JavaScript는 "느슨한 유형의 언어(loosely typed language)" 입니다. 즉, 다른 언어와 달리 변수에 포함 할 데이터의 유형을 지정할 필요가 없습니다.(예: 숫자? 문자열?)</p> + +<p>예를 들어, 변수를 선언하고 그 변수의 값을 따옴표로 묶은 값을 지정하면 브라우저는 변수의 값을 문자열로 인식합니다.</p> + +<pre class="brush: js">var myString = 'Hello';</pre> + +<p>따옴표 안에 숫자가 포함되어 있어도 여전히 문자열로 인식되므로 주의해야 합니다:</p> + +<pre class="brush: js">var myNumber = '500'; // oops, this is still a string +typeof(myNumber); +myNumber = 500; // much better — now this is a number +typeof(myNumber)</pre> + +<p>위의 네 줄의 코드를 하나씩 콘솔에 입력하여 결과가 무엇인지 확인해 보세요.(주석은 입력하지 마세요.) 여기에서 <code>typeof()</code> 라는 특수 함수를 사용하고 있음을 알 수 있습니다. - 이 함수는 입력한 변수의 데이터 유형을 반환합니다. 위의 코드에서 처음으로 호출될 때, <code>myNumber</code> 변수에는 <code>'500'</code> 라는 문자열이 포함되어 있으므로 <code>string</code> 을 반환해야 합니다. 두 번째는 어떤 값을 반환하는지 확인해 보세요.</p> + +<h2 id="요약">요약</h2> + +<p>지금까지 JavaScript의 변수란 무엇이며, 어떻게 생성하는지 알아보았습니다. 다음에는 JavaScript에서 숫자에 관해 자세히 살펴보고 기본 계산하는 방법을 알아보겠습니다.</p> + +<p>{{PreviousMenuNext("Learn/JavaScript/First_steps/What_went_wrong", "Learn/JavaScript/First_steps/Maths", "Learn/JavaScript/First_steps")}}</p> diff --git a/files/ko/learn/javascript/first_steps/what_is_javascript/index.html b/files/ko/learn/javascript/first_steps/what_is_javascript/index.html new file mode 100644 index 0000000000..e9198dd1d3 --- /dev/null +++ b/files/ko/learn/javascript/first_steps/what_is_javascript/index.html @@ -0,0 +1,423 @@ +--- +title: JavaScript가 뭔가요? +slug: Learn/JavaScript/First_steps/What_is_JavaScript +tags: + - Article + - Beginner + - CodingScripting + - Guide + - JavaScript + - Learn + - Script +translation_of: Learn/JavaScript/First_steps/What_is_JavaScript +--- +<div>{{LearnSidebar}}</div> + +<div>{{NextMenu("Learn/JavaScript/First_steps/A_first_splash", "Learn/JavaScript/First_steps")}}</div> + +<p class="summary">MDN의 JavaScript 초급자 과정에 오신 걸 환영합니다! 이 글은 JavaScript를 넓게 보면서 "뭔가요?", "뭘 하나요?"와 같은 질문을 답변하고, 여러분이 JavaScript에 친숙해지도록 도와드립니다.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">전제 조건:</th> + <td> + <p>기본적인 컴퓨터 능력, HTML과 CSS 기초.</p> + </td> + </tr> + <tr> + <th scope="row">목표:</th> + <td>JavaScript가 뭔지, 어떤 일을 할 수 있는 지, 웹사이트에 어떻게 적용하는지 알기.</td> + </tr> + </tbody> +</table> + +<h2 id="둘러보기">둘러보기</h2> + +<p>자바스크립트는 복잡한 무언가(주기적으로 내용이 갱신되는 기능이나 능동적인 지도, 변화하는 2D/3D 그래픽, 동영상 등)를 웹페이지에 적용할 수 있게 하는 스크립트 혹은 프로그래밍 언어입입니다. 자바스크립트는 표준 웹 기술이라는 레이어 케이크에서 세번째 층이라고 볼 수 있습니다. 다른 두 층(HTML과 CSS)에 대한 보다 자세한 정보는 학습 영역의 다른 부분에서 찾아 볼 수 있습니다.</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/13502/cake.png" style="display: block; margin: 0 auto;"></p> + +<ul> + <li>{{glossary("HTML")}}은 제공할 웹 컨텐츠의 구조와 의미를 문단, 제목, 표, 삽입 이미지, 동영상 등으로 정의하고 부여하는 마크업 언어입니다.</li> + <li>{{glossary("CSS")}}는 배경색, 폰트 등의 레이아웃등을 지정하여 HTML 컨텐츠를 꾸며주는 스타일 규칙 언어입니다.</li> + <li>{{glossary("JavaScript")}}는 동적으로 컨텐츠를 바꾸고, 멀티미디어를 다루고, 움직이는 이미지 그리고 꽤나 많은 다른 일(물론, 전부는 아니지만 몇 줄만의 자바스크립트 코드로 얻는 결과는 놀라울겁니다.)들을 할 수 있는 스크립트 언어입니다.</li> +</ul> + +<p>3개의 요소들은 각각 유기적으로 잘 구성되어 있습니다. 예제와 같이 간단한 폼을 만들어 봅시다. HTML을 사용하여 그 구조와 목적에 맞게 마크업 할 수 있습니다: </p> + +<pre class="brush: html notranslate"><p>Player 1: Chris</p></pre> + +<p><img alt="" src="https://mdn.mozillademos.org/files/13422/just-html.png" style="height: 28px; width: 108px;"></p> + +<p>그리고 CSS를 추가하여 이쁘게 꾸밀 수도 있습니다:</p> + +<pre class="brush: css notranslate">p { + font-family: 'helvetica neue', helvetica, sans-serif; + letter-spacing: 1px; + text-transform: uppercase; + text-align: center; + border: 2px solid rgba(0,0,200,0.6); + background: rgba(0,0,200,0.3); + color: rgba(0,0,200,0.6); + box-shadow: 1px 1px 2px rgba(0,0,200,0.4); + border-radius: 10px; + padding: 3px 10px; + display: inline-block; + cursor:pointer; +}</pre> + +<p><img alt="" src="https://mdn.mozillademos.org/files/13424/html-and-css.png" style="height: 48px; width: 187px;"></p> + +<p>그러고 마지막으로 약간의 자바스크립트로 동적인 기능을 추가할 수 있습니다:</p> + +<pre class="brush: js notranslate">const para = document.querySelector('p'); + +para.addEventListener('click', updateName); + +function updateName() { + let name = prompt('Enter a new name'); + para.textContent = 'Player 1: ' + name; +} +</pre> + +<p>{{ EmbedLiveSample('A_high-level_definition', '100%', 80, "", "", "hide-codepen-jsfiddle") }}</p> + +<p>마지막 버전의 텍스트 라벨을 클릭하여 어떻게 되는 지 확인해봅시다. (이 데모는 Github에서도 볼 수 있습니다. <a href="https://github.com/mdn/learning-area/blob/master/javascript/introduction-to-js-1/what-is-js/javascript-label.html">source code</a> 나 <a href="http://mdn.github.io/learning-area/javascript/introduction-to-js-1/what-is-js/javascript-label.html">run it live</a>를 참고해보세요!)</p> + +<p>자바스크립트는 보다 더 많은 일들을 할 수 있습니다. 이제 더 자세한 내용을 살펴봅시다!</p> + +<h2 id="그래서_진짜_어떤_일을_할_수_있나요">그래서, 진짜 어떤 일을 할 수 있나요?</h2> + +<p>자바스크립트 언어의 핵심은 다음과 같은 일들을 할 수 있게하는 프로그래밍 기능들로 구성되어 있습니다:</p> + +<ul> + <li>변수안에 값을 저장할 수 있습니다. 위의 예시를 보면, 작성된 새로운 이름을 <code>name</code>이라는 변수에 저장하였습니다.</li> + <li>프로그밍에서 '문자열(strings)'이라고 불리는 문자들도 조작 가능합니다. 위 예시에 보면 "Player 1:"이라는 문자열을 <code>name</code>이라고 만든 변수와 겹합하여 "Player 1: Chris"라는 글을 완성할 수 있었습니다.</li> + <li>웹 페이지상의 이벤트에 응답하는 코드를 작성할 수 있습니다. 예제에서 사용한 {{Event("click")}} 이벤트를 통해 요소가 언제 클릭되고, 텍스트 라벨을 업데이트 시킬지 정정의하였습니다.</li> + <li>그리고 더 많은 것들!</li> +</ul> + +<p>하지만 더욱 흥미진진한 것은 코어 자바스크립트 언어(<em>core JavaScript</em> language) 기반의 기능성입니다. 소위 <strong>Application Programming Interfaces</strong> (<strong>APIs</strong>) 라는 것은 여러분의 자바스크립트 코드에 사용할 수 있는 추가적인 강력한 마법들을 제공합니다. </p> + +<p>API는 이미 만들어진 코드의 집합체라고 볼 수 있으며, 개발자들이 만들기 어렵고 힘든 부분을 쉽게 구현하도록 하는 프로그램이라고 볼 수 있습니다. 마치 집에서 가구를 만들 때 직접 디자인하고, 재료를 구하고, 재단하고, 못을 박고 하는 등 혼자서 모든 것을 하는 대신 가구 만들기 키트를 사는 것과 같다고 보면 됩니다.</p> + +<p>일반적으로 두 종류로 구분됩니다.</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/13508/browser.png" style="display: block; height: 511px; margin: 0px auto; width: 815px;"></p> + +<p><strong>Browser API</strong>는 웹 브라우저에 설치된 API들로, 컴퓨터 환경구성으로 부터 데이터를 보이게 하고 복잡한 일들을 하게 합니다. 예를 들어:</p> + +<ul> + <li><a href="https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model">DOM (Document Object Model) API</a> 는 동적으로 페이지의 스타일을 정하는 등 HTML과 CSS를 알맞게 조정하는 역할을 합니다. 우리가 매일 보는 팝업창이나, 위의 사진과 같이 컨텐츠들이 보여지는 것들이 모두 DOM의 결과라고 볼 수 있습니다.</li> + <li><a href="https://developer.mozilla.org/en-US/docs/Web/API/Geolocation">Geolocation API</a>은 지리적인 정보를 검색하게 해줍니다. 이는 <a href="https://www.google.com/maps">Google Maps</a>이 어떻게 위치를 찾고 지도에 표시하는지 알 수 있게 합니다.</li> + <li><a href="https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API">Canvas</a> 와 <a href="https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API">WebGL</a> API는 2D와 3D 그래픽을 만들 수 있도록 합니다. 이러한 웹 기술을 사용하여 다양하고 재미있는 것들을 지원합니다. —<a href="https://www.chromeexperiments.com/webgl">Chrome Experiments</a> 와 <a href="http://webglsamples.org/">webglsamples</a>을 참조해보세요.</li> + <li>HTMLMediaElement 와 <a href="/en-US/docs/Web/API/WebRTC_API">WebRTC</a> 같은 <a href="https://developer.mozilla.org/en-US/Apps/Fundamentals/Audio_and_video_delivery">Audio and Video API</a>는 음악과 비디오를 웹 페이지 상에서 재생하고, 웹캠으로 캡처하고 다른 컴퓨터에 표시하는 등의 멀티미디어를 활용할 수 있는 재미있는 기술을 지원합니다. (<a href="http://chrisdavidmills.github.io/snapshot/">Snapshot demo</a>를 한번 참조해보세요.)</li> +</ul> + +<div class="note"> +<p><strong>Note</strong>: 대부분의 데모 코드들은 오래된 브라우저에서는 실행이 안될 수 있으니, FireFox, Chrome, Edge, Opera와 같은 최신의 브라우저를 사용하는 것을 추천합니다. 실제 배포가 되는 코드처럼 여러 사용자가 사용할 수 있음을 고려하여 <a href="/en-US/docs/Learn/Tools_and_testing/Cross_browser_testing">cross browser testing</a>(여러 브라우저를 이용하여 테스트)를 해보는 것이 좋습니다.</p> +</div> + +<p><strong>Third party API</strong> 는 브라우저에 기본적으로 설치된 API가 아닌 인터넷에서 개인적으로 정보와 코드를 얻어 프로그래밍한 것을 말합니다. 예를 들어:</p> + +<ul> + <li><a href="https://dev.twitter.com/overview/documentation">Twitter API</a>는 웹사이트에 가장 최근의 트윗을 보여주도록 합니다.</li> + <li><a href="https://developers.google.com/maps/">Google Maps API</a>와 <a href="https://wiki.openstreetmap.org/wiki/API">OpenStreetMap API</a>는 웹사이트에 원하는 지도를 넣어주고 추가기능을 지원합니다.</li> +</ul> + +<div class="note"> +<p><strong>Note</strong>: 이러한 API 들은 고급 과정이며, 이 과정에서는 다루지 않을 것입니다. 이 API들에 대한 보다 자세한 정보는 <a href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Client-side_web_APIs">Client-side web APIs module</a>에서 살펴보세요.</p> +</div> + +<p>물론 이것말고도 엄청나게 다양한 API들이 존재합니다! 하지만, 이 수업을 듣고 Facebook, Google Maps, Instagram등을 만들 수는 없으니 흥분하지는 말길 바랍니다. 이것보다 우리는 먼저 기본적인 것에 대해 배울 것이고 이것이 곧 이 수업을 진행하는 목적입니다. 자 시작해봅시다!</p> + +<h2 id="웹_페이지에서_JavaScript는_어떤_일을_하나요">웹 페이지에서 JavaScript는 어떤 일을 하나요?</h2> + +<p>여기서 몇가지 코드를 실제로 살펴보고, 페이지에서 자바스크립트가 언제 어떻게 작동하는지 알아 볼 것입니다.</p> + +<p>브라우저에서 웹페이지를 불러올 때 어떤 일이 발생하는지 생각해봅시다(먼저 <a href="/en-US/Learn/CSS/Introduction_to_CSS/How_CSS_works#How_does_CSS_actually_work">How CSS works</a>를 읽어 보세요.). 브라우저에서 웹페이지를 불러올 때, 실행 환경(브라우저 탭)안에서 HTML, CSS, Javascript 코드가 실행됩니다. 이는 마치 공장에서 원재료(코드)가 일련의 과정을 거쳐 제품(웹페이지)으로 탄생되는 것과 같습니다.</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/13504/execution.png" style="display: block; margin: 0 auto;"></p> + +<p>자바스크립트는 HTML과 CSS가 결합되고 웹페이지 상에서 올려진 후, 브라우저의 자바스크립트 엔진에 의해 실행됩니다. 이는 페이지의 구조와 스타일등을 정해놓고, 자바스크립트가 실행된다는 것과 같은 의미입니다.</p> + +<p>동적으로 사용자 인터페이스를 업데이트하는 자바스크립트의 사용은 Document Object Model API를 통해 HTML과 CSS를 수정하는 것으로 좋은 현상입니다. 만약 자바 스크립트가 HTML과 CSS 전에 실행되었다면 문제가 분명 발생할 것입니다.</p> + +<h3 id="브라우저_보안성">브라우저 보안성</h3> + +<p>각각의 브라우저 탭들은 코드가 실행되는 개별적인 구성(이러한 것은 "실행 환경"이라고 지칭한다)입니다. 이는 각 탭의 대부분의 경우는 완전히 독립적이고, 하나의 탭의 코드는 다른 탭이나 웹사이트에 직접적으로 영향을 줄 수 없다는 의미입니다 . 이는 보안성에 좋은 방법입니다. 만약 이러한 부분이 없다면, 해커들이 다른 웹사이트로 부터 정보를 가로채는 등 악랄한 짓들을 할 수 있습니다.</p> + +<div class="note"> +<p><strong>Note</strong>: 물론 코드나 정보를 동떨어진 웹사이트나 탭으로 전송할 수 있는 안전한 방식이 존재합니다. 하지만 지금 과정과는 거리가 멀기 때문에 여기서는 다루지 않도록 하겠습니다.</p> +</div> + +<h3 id="자바스크립트_실행_순서">자바스크립트 실행 순서</h3> + +<p>브라우저에서 자바스크립트를 만났을 때 일반적으로는 위에서 아래 순서대로 실행됩니다. 이는 순서에 주의해서 코드를 작성해야한다는 의미입니다. 예를 들어, 아래의 첫번째 예재를 통해 자바스크립트 블록을 반환해봅시다:</p> + +<pre class="brush: js notranslate">const para = document.querySelector('p'); +//HTML 요소 중 p태그를 선택 + +para.addEventListener('click', updateName); +//para에 저장된 객체가 클릭되었을 때 updateName 함수를 실행 + +function updateName() { + let name = prompt('Enter a new name'); + //'Enter a new name'과 입력란 출력하여 입력받은 값을 name에 저장 + para.textContent = 'Player 1: ' + name; + //papa(p태그)에 새로운 문자열 저장 +}</pre> + +<p>먼저 p태그의 요소를 para변수에 저장합니다(1번줄). 그리고 event listener를 붙여(3번줄) p태그가 클릭되었을 때 <code>updateName()</code>코드 블록(중괄호로 묶여있는 부분)이 (5-8번줄) 실행되도록 합니다. <code>updateName()</code> 코드 블록(이렇게 계속적으로 사용할 수 있는 코드 블럭을 함수라고 합니다.). 사용자로 하여금 새로운 이름을 입력받기를 요청하고, 사용자가 이름을 입력하면 화면에 출력하게 됩니다.</p> + +<p>만약 1번줄과 3번줄을 바꿨다면 코드는 실행되지 않을 것입니다. 대신 브라우저의 개발자 콘솔창에 다음과 같은 에러 알림이 뜰 것입니다. — <code>TypeError: para is undefined</code>. 이는 para라는 객체가 아직 존재하지 않는다는 뜻으로, para라는 변수에 event listener는 추가할 수 없습니다</p> + +<div class="note"> +<p><strong>Note</strong>: 이는 매우 일반적인 에러이기 때문에, 프로그램을 실행할 때 코드 상에서 사용되는 객체에 대해 주의할 필요가 있습니다.</p> +</div> + +<h3 id="해석형_언어와_컴파일러형_언어">해석형 언어와 컴파일러형 언어</h3> + +<p>프로그래밍을 하는 입장에서 인터프리트와 컴파일이라는 개념에 대해서는 들어보았을 것입니다. 자바스크립트는 해석형 언어입니다. 따라서 코드가 위에서 아래로 순차적으로 실행되고 그 즉시 결과가 반환됩니다. 브라우저에서 동작하기 전에 다른 방식으로 코드를 변환할 필요가 없습니다.</p> + +<p>반면에 컴파일러형 언어는 컴퓨터에 의해 동작되기전 다른 형식으로 변환하는 언어입니다. 예를 들면 C/C++과 같은 언어는 어셈블리어로 컴파일되어 동작됩니다.</p> + +<p>이 둘의 관점은 각각의 장점을 가지고 있으니 다음장 부터 한번 알아봅시다.</p> + +<h3 id="서버측_코드와_클라이언트측_코드">서버측 코드와 클라이언트측 코드</h3> + +<p>웹 개발 맥락에서 서버측과 클라이언트측 코드에 대해 들어보았을 것입니다. 클라이언트측 코드란 사용자의 컴퓨터에서 작동되는 코드입니다. 만약 웹페이지를 보고자 한다면, 클라이언트측 코드가 사용자의 컴퓨터로 다운로드되고 브라우저가 이를 표시합니다. 이러한 자바스크립트 모듈을 정확히는 클라이언트측 자바스크립트라고 합니다.</p> + +<p>반면 서버측 코드는 서버에서 작동되고, 그 결과가 사용자의 브라우저에 넘어가 표시됩니다. PHP, Python, Ruby, ASP.NET등이 서버측 웹 언어의 대표적 예라고 볼 수 있습니다. 물론 자바스크립트도 가능합니다! 유명한 Node.js란 환경을 통해 서버측에서도 자바스크립트가 사용 가능합니다. <a href="/en-US/docs/Learn/Server-side">Dynamic Websites – Server-side programming</a>에서 서버측 자바스크립트에 대해 더 알 수 있습니다.</p> + +<h3 id="동적_VS_정적_코드">동적 VS 정적 코드</h3> + +<p>"동적"이라는 말은 클라이언트측 서버측 언어 모두를 가르킵니다. 이는 각기 다른 상황에서 적절한 정보가 보이고, 컨텐츠를 웹페이지나 앱 상에 계속적으로 노출시키는 역할을 합니다. 서버측 코드는 데이터베이스로 부터 데이터를 던지는 등 동적으로 새로운 컨텐츠들을 만듭니다. 반면에, 클라이언트측 자바스크립트는 새로운 HTML 표를 만들어 서버에서 요청한 데이터를 뿌려 사용자에게 보이는 등 동적으로 브라우저 안에서 작동됩니다. 이 둘 사이는 서로 미묘한 차이가 있지만, 서로 연관되어 있고 서버측 클라이언트측의 관계와 접근에 대해 알 필요가 있습니다.</p> + +<p>동적으로 바뀌지 않는 페이지를 "정적"페이지라고 합니다. (항상 같은 콘텐츠를 보여줍니다.)</p> + +<h2 id="웹_페이지에_JavaScript를_어떻게_넣나요">웹 페이지에 JavaScript를 어떻게 넣나요?</h2> + +<p>자바스크립트는 CSS와 같은 방식으로 HTML 페이지에 적용됩니다. CSS는 외부의 스타일시트를 적용하기 위해 link 요소를 사용하거나 내부의 스타일시트를 적용하기 위해 style 요소를 사용하는 반면,자바스크립트는 HTML상에서 오직 script 태크만으로 사용이 가능합니다. 어떻게 작동되는지 한번 살펴봅시다.</p> + +<h3 id="HTML_내부의_자바스크립트">HTML 내부의 자바스크립트</h3> + +<ol> + <li>먼저, 예제로 주어진 <a href="https://github.com/mdn/learning-area/blob/master/javascript/introduction-to-js-1/what-is-js/apply-javascript.html">apply-javascript.html</a>파일을 저장합니다.</li> + <li>파일을 브라우저와 편집기 상에서 둘다 엽니다. HTML으로 만든 클릭 버튼이 있는 간단한 웹페이지를 볼 수 있습니다.</li> + <li>그런다음, 편집기로 가서 <code></body></code> 태그 직전에 다음의 코드를 추가하도록 합니다: + <pre class="brush: html notranslate"><script> + + // JavaScript goes here + +</script></pre> + </li> +</ol> + +<p>그러고 아래의 자바스크립트 코드를 <script></script>사이에 넣음으로서 페이지 상에서 동작이 가능하게끔 할 수 있습니다.( 위 코드에서 "// JavaScript goes here" 부분에 아래의 코드를 추가하면 됩니다.)</p> + +<pre class="brush: js notranslate" dir="rtl"><code>document.addEventListener("DOMContentLoaded", function() { + function createParagraph() { + let para = document.createElement('p'); + para.textContent = 'You clicked the button!'; + document.body.appendChild(para); + }</code> + + const buttons = document.querySelectorAll('button'); + + for(let i = 0; i < buttons.length ; i++) { + buttons[i].addEventListener('click', createParagraph); + } +});</pre> + +<ol> + <li>파일을 저장하고 새로고침을 눌러보세요. 이제 버튼을 클릭하면 새로운 문단이 아래쪽에 생기는 것을 볼 수 있습니다.</li> +</ol> + +<div class="blockIndicator note"> +<p>각각의 문법에 대해서는 이후 더 자세히 다루기 때문에, 동작여부만 확인하고 넘어가도 무방합니다.</p> +</div> + +<div class="note"> +<p><strong>Note</strong>: 만약 예제가 실행되지 않는다면, 돌아가서 올바른지 한 번 더 체크해보도록 하세요. 혹시 저장할 때 확장자를 .html 로 하지 않았나요? 혹시 {{htmlelement("script")}} 를<code></body></code> 태그 뒤에 붙인 건 아닌가요? 다음과 같이 자바스크립트를 작성했나요? <strong>자바스크립트는 까다로운 언어이기 때문에 정확하게 문법을 지킬 필요가 있습니다. 그렇지 않으면 제대로 동작하지 않을 수 도 있습니다.</strong></p> +</div> + +<div class="note"> +<p><strong>Note</strong>: 깃허브에서도 이 코드를 볼 수 있습니다. <a href="https://github.com/mdn/learning-area/blob/master/javascript/introduction-to-js-1/what-is-js/apply-javascript-internal.html">apply-javascript-internal.html</a> (<a href="http://mdn.github.io/learning-area/javascript/introduction-to-js-1/what-is-js/apply-javascript-internal.html">see it live too</a>).</p> +</div> + +<h3 id="외부의_자바스크립트">외부의 자바스크립트</h3> + +<p>만약에 외부 파일로 자바스크립트를 위치시키고 싶다면 어떻게 할까요? 이에 대해서 알아봅니다.</p> + +<ol> + <li>먼저, HTML 파일이 있는 디렉토리에 <code>script.js</code>라는 새로운 파일을 만듭니다. 파일의 확장자가 .js이면 그 파일이 자바스크립트로 이루어져 있음을 뜻합니다.</li> + <li>아래의 태그를 HTML 코드에 복사 후 저장합니다.</li> + <li> + <pre class="syntaxbox notranslate"><script src="script.js"></script></pre> + </li> + <li>script.js 의 내용을 다음과 같이 바꿉니다. + <pre class="notranslate"><code>function createParagraph() { + let para = document.createElement('p'); + para.textContent = 'You clicked the button!'; + document.body.appendChild(para); +} + +const buttons = document.querySelectorAll('button'); + +for(let i = 0; i < buttons.length ; i++) { + buttons[i].addEventListener('click', createParagraph); +}</code></pre> + </li> + <li>저장하고 브라우저를 새로고침하면 앞과 똑같은 결과가 나올것입니다. 똑같이 작동하기 때문에 이제 자바스크립트는 외부에서 만들 수 있음을 알 수 있습니다. 이는 코드를 만들고 구성하는 입장에서 좋으며, 여러 HTML파일로 부터 재사용이 가능합니다. 더군다나 HTML은 스크립트의 본문이 외부로 분리되어 간결해집니다.</li> +</ol> + +<div class="blockIndicator note"> +<p><strong>Note</strong>: 깃허브에서 이 버전을 볼 수 있습니다. <a href="https://github.com/mdn/learning-area/blob/master/javascript/introduction-to-js-1/what-is-js/apply-javascript-external.html">apply-javascript-external.html</a> 그리고 <a href="https://github.com/mdn/learning-area/blob/master/javascript/introduction-to-js-1/what-is-js/script.js">script.js</a> (<a href="http://mdn.github.io/learning-area/javascript/introduction-to-js-1/what-is-js/apply-javascript-external.html">see it live too</a>).</p> +</div> + +<h3 id="인라인_JavaScript_처리기">인라인 JavaScript 처리기</h3> + +<p>실제 HTML 속에 포함된 자바스크립트코드를 함께 쓸 수 있습니다. 이는 다음과 같으니 참고해보세요:</p> + +<pre class="brush: js example-bad notranslate">function createParagraph() { + let para = document.createElement('p'); + para.textContent = 'You clicked the button!'; + document.body.appendChild(para); +} +//HTML 내의 <scirpt>태그 내부에 작성 +</pre> + +<pre class="brush: html example-bad notranslate"><button onclick="createParagraph()">Click me!</button></pre> + +<p>이는 다음과 같은 예제로 볼 수 있습니다.</p> + +<p>이 데모 예제는 <button>태그에 onclick속성에 대한 값을 함수이름으로 넣어 버튼이 클릭될 때마다 함수가 실행되도록 작성하였습니다.</p> + +<p><strong>하지만, 이 방법은 효율적이지 않습니다. </strong>이는 자바스크립트와 함께 HTML 소스를 복잡하게 할 수 있습니다. 또한 함수를 만들기 위한 모든 버튼 마다 <code>onclick="createParagraph()"</code> 속성을 포함해야합니다.</p> + +<p>JavaScript 코드만으로도 모든 버튼에 함수를 연결할 수 있습니다. 위의 내용을 의도한대로 수정한다면 다음과 같습니다:</p> + +<pre class="notranslate">const buttons = document.querySelectorAll('button'); +//모든 <button>태그를 List 형태로 buttons 변수에 저장한다. + +for (let i = 0; i < buttons.length ; i++) { + buttons[i].addEventListener('click', createParagraph); +} +//복수이기 때문에 for를 사용해 루프를 돌린다. +</pre> + +<p>이 코드는 onclick 속성 코드 보다 조금 길어보이지만, 페이지가 많든, 버튼의 수가 많든 적든 상관없이 모든 버튼들이 같은 기능을 할 수 있도록 합니다. 물론 자바스크립트 코드를 변경할 필요가 없습니다.</p> + +<div class="note"> +<p><strong>Note</strong>: <code>apply-javascript.html 수정을 해보고 버튼을 한 번 추가해 보세요.</code> 실행해보면 버튼 하나하나 클릭할 때 마다 글이 보일 것입니다. 꽤 깔끔하지 않은가요?</p> +</div> + +<h3 id="스크립트의_로딩_방법">스크립트의 로딩 방법</h3> + +<p> 작성된 스크립트를 브라우저가 적절한 때에 로딩하는것에 대해 몇가지 이슈가 있습니다. 중요한 것은 모든 HTML 요소는 순서대로 페이지에 로드된다는 것입니다. 만약 당신이 자바스크립트를 이용해 HTML 요소를 조작할 경우(정확하게는 DOM), 자바스크립트 코드가 조작 대상인 HTML 요소보다 먼저 실행된다면 조작할 요소가 존재하지 않는 상태이기 때문에 제대로 동작하지 않을 것입니다.</p> + +<p>위의 코드 예제에서, 내부와 외부의 자바스크립트는 HTML Document의 <code>body</code>가 해석되기 전인 <code>head </code>부분에 로드되고 실행되었습니다. 이는 에러를 일으킬 수 있습니다. 그래서 여기에 사용되는 몇가지 해결방법들이 있습니다.</p> + +<p><strong>내부 자바스크립트 예제</strong>에서는 다음과 같이 구성하면 됩니다:</p> + +<pre class="notranslate"><code>document.addEventListener("DOMContentLoaded", function() { + ... +});</code></pre> + +<p>이 이벤트리스너는 <code>"DOMContentLoad" </code>이벤트가 발생되었을 때<code> function()</code>을 실행한다는 의미입니다. (<a href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Building_blocks/Events">이벤트 리스너</a>에 관해서는 이번 코스에서 다루게 됩니다.) <code>"DOMContentLoad"</code> 이벤트는 브라우저가 완전히 로드되고 해석될때 발생됩니다. <code>function(){}</code> 내부의 자바스크립트 구문은 이벤트가 발생되기 전까지는 실행되지 않습니다. 따라서 모든 <code>body</code>태그의 요소가 로드된 이후 자바스크립트 코드가 실행되도록 만들어 에러를 피할 수 있습니다.</p> + +<p><strong>외부 자바스크립트</strong> 예제에서는 좀더 최신의 자바스크립트 문법인 <code>async </code>속성을 사용하게 됩니다. 일반적으로 <code>HTML</code>요소를 로딩하는 중 <code><scirpt></code>태그를 만나면 JavaScript의 내용이 모두 다운될 때까지 <code>HTML</code>로딩은 멈추게 되는데, <code>async</code>요소는 비동기방식으로 <code><script></code>태그에 도달했을 때 브라우저에게 <code>HTML </code>요소를 멈추지 않고 다운받도록 유지시킵니다.</p> + +<pre class="notranslate"><code><script src="script.js" async></script></code></pre> + +<p>이 경우 <code>script</code>와 <code>HTML</code>은 모두 동시에 로드되고 작동할 것입니다.</p> + +<div class="blockIndicator note"> +<p><strong>Note</strong>: 외부 스크립트 경우 async 속성을 사용하면 되기 때문에 내부 스크립트처럼 DOMContentLoaded이벤트를 사용할 필요가 없습니다. 하지만 async속성은 외부 스크립트의 경우만 동작합니다.</p> +</div> + +<p>예전 방식은 <code>scirpt </code>요소를 <code>body</code>태그의 맨 끝에 넣는 방법이었습니다(<code></body></code> 바로 위에). 이 방식을 사용해도 <code>body</code>태그가 모두 로드된 이후 <code>scirpt</code>가 실행되게 만들 수 있습니다. 문제는 이 방법과 <code>DOMContentLoaded</code>를 이용한 방법 모두<code> HTML DOM</code>이 로드되기 전까지 <code>script</code>의 로딩과 파싱이 완전히 차단된다는 것입다. 이는 많은 자바스크립트 코드를 다루는 규모가 큰 사이트의 경우 사이트를 느리게 만드는 중요한 성능 문제를 야기할 수 있습니다. 이것이 <code>async </code>속성을 사용해야 하는 이유입니다!</p> + +<div class="blockIndicator note"> +<p><strong>Note</strong>: 자바스크립트의 비동기 개념은 이해하는데 시간이 오래 걸리기 때문에, 지금 이해되지 않는다면 현재 단계에선 외부 스크립트 방식만 사용하고 넘어가도 무방합니다.</p> +</div> + +<h4 id="async_defer">async & defer</h4> + +<p>더 깊게 들어가보면 이러한 코드문제를 해결하기 위한 방법은 실제로 두가지가 있습니다. — <code>async</code> 와<code>defer</code> 입니다. 두 가지의 차이를 봅시다.</p> + +<p>async 스크립트는 페이지 렌더링의 중단 없이 스크립트를 다운로드 하고, 또한 스크립트의 다운로드가 끝나자 마자 이를 실행시킵니다. async는 외부 스크립트끼리의 구체적인 실행 순서는 보장하지 않고, 단지 나머지 페이지가 나타나는 동안 스크립트가 비동기방식으로 다운로드 되어 중단되지 않는다는 것만 보장합니다. async는 각각의 스크립트가 독립적으로, 서로에게 의존하지 않는 관계일 때 적절합니다.</p> + +<p>아래의 예제를 보시죠:</p> + +<pre class="notranslate"><code><script async src="js/vendor/jquery.js"></script> + +<script async src="js/script2.js"></script> + +<script async src="js/script3.js"></script></code></pre> + +<p>3개의 스크립트를 로딩하지만 이들의 순서는 보장할 수 없습니다. 이는 <code>script2.js</code>나 <code>script3.js</code>에 있는 함수가<code> jquery.js</code>의 함수를 사용한다면 에러를 발생될 수 있다는 것을 의미합니다.</p> + +<p>Defer는 이와 다르게 순서대로 다운로드 한 후 모든 스크립트와 내용이 다운로드 되었을 때 실행됩니다:</p> + +<pre class="notranslate"><code><script defer src="js/vendor/jquery.js"></script> + +<script defer src="js/script2.js"></script> + +<script defer src="js/script3.js"></script></code></pre> + +<p>따라서 위의 예제의 경우에는 <code>jquery.js</code> -> <code>script2.js</code> -> <code>script3.js</code> 의 순서가 보장됩니다.</p> + +<p>요약 :</p> + +<ul> + <li>만약 scirpt들이 각각의 스크립트에 의존하지 않고 독립적으로 파싱되도 상관없다면, <code>async</code> 를 사용합니다.</li> + <li>먄약 sciprt들이 의존하고 하나의 스크립트가 파싱될때까지 기다려야 한다면, <code>defer</code> 를 사용하고 각각의 <code><script></code> 태그들을 실행되길 원하는 순서대로 작성합니다.</li> +</ul> + +<h2 id="주석">주석</h2> + +<p>HTML과 CSS와 같이, 자바스크립트에서도 주석문의 사용이 가능합니다. 주석문은 브라우저 실행때는 무시되어 넘어가고 다른 개발자로 하여금 어떻게 구성되고 작동되는지 설명해주는 역할을 합니다(물론 자신의 훗날 코드를 다시 보았을 때 빨리 기억하고, 이해할 수 있게끔 도와주기도 합니다.). 주석문은 매우 유용하고 코딩시 자주 사용됩니다(특히 큰 프로젝트에서). 주석문에는 두가지 종류가 있습니다:</p> + +<ul> + <li>두개의 슬래시(//)를 통해 한 줄의 주석이 가능합니다. + <pre class="brush: js notranslate">// I am a comment</pre> + </li> + <li> /* 와 */를 사용하여 그 사이에 여러 줄의 주석문의 구성이 가능합니다. + <pre class="brush: js notranslate">/* + I am also + a comment +*/</pre> + </li> +</ul> + +<p>예를 들자면, 앞의 데모예제에 주석문을 다음과 같이 달 수 있습니다.</p> + +<pre class="brush: js notranslate">// Function: creates a new paragraph and append it to the bottom of the HTML body. + +function createParagraph() { + let para = document.createElement('p'); + para.textContent = 'You clicked the button!'; + document.body.appendChild(para); +} + +/* + 1. Get references to all the buttons on the page and sort them in an array. + 2. Loop through all the buttons and add a click event listener to each one. + + When any button is pressed, the createParagraph() function will be run. +*/ + +const buttons = document.querySelectorAll('button'); + +for (let i = 0; i < buttons.length ; i++) { + buttons[i].addEventListener('click', createParagraph); +}</pre> + +<h2 id="정리">정리</h2> + +<p>지금까지 우리는 자바스크립트의 첫걸음을 떼었습니다. 여기서 자바스크립트를 왜 사용하고 어떻게 사용하는지에 대한 방법들에 대한 기초적인 부분을 배웠습니다. 여러 예제 코드를 봄으로써, 웹사이트와 다른 곳에서의 코드상 자바스크립트가 어떻게 구성되어있는지 배웠습니다.</p> + +<p>자바스크립트가 지금은 조금 어려울 수 있으나, 걱정하지 마세요. 이 수업은 첫 단계인만큼 앞으로 더 많은 것을 배우기 위해 감각을 키우기 위한 수업입니다. 다음 수업에서 우리는 <a href="/en-US/docs/Learn/JavaScript/Introduction_to_JavaScript_1/A_first_splash">plunge straight into the practical</a>를 통해 앞으로 더 나아가고 스스로 자바스크립트 예제를 실행해볼 것입니다.</p> diff --git a/files/ko/learn/javascript/first_steps/what_went_wrong/index.html b/files/ko/learn/javascript/first_steps/what_went_wrong/index.html new file mode 100644 index 0000000000..44030c4057 --- /dev/null +++ b/files/ko/learn/javascript/first_steps/what_went_wrong/index.html @@ -0,0 +1,237 @@ +--- +title: 자바스크립트 문제해결 +slug: Learn/JavaScript/First_steps/What_went_wrong +translation_of: Learn/JavaScript/First_steps/What_went_wrong +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/JavaScript/First_steps/A_first_splash", "Learn/JavaScript/First_steps/Variables", "Learn/JavaScript/First_steps")}}</div> + +<p class="summary">이전 수업에서 "숫자맞추기" 프로그램을 만들어봤을때, 프로그램이 돌아가지 않는다는 것을 볼 것이다. 하지만 여기서 자바스크립트의 에러를 찾고 고치는 방법에 대해 알려주니 겁먹지 말고 도전해보자!</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">알아야 할 것</th> + <td>기본적인 컴퓨터 이해. HTML, CSS, 자바스크립트의 이해</td> + </tr> + <tr> + <th scope="row">목표</th> + <td>코드상의 문제를 고치는 능력과 자신감 고취</td> + </tr> + </tbody> +</table> + +<h2 id="에러의_종류">에러의 종류</h2> + +<p>일반적으로, 코드가 잘못된 이유에는 2가지 종류가 있으니 살펴보자.</p> + +<ul> + <li><strong>구문 에러(Syntax errors)</strong>: 코드 상의 구문 에러로 대개 철자가 잘못되어 작동이 안되거나 중간에 프로그램이 중지된다. 물론 여기서 에러 메시지가 출력되므로 확인할 수 있다. 코드 편집기 툴을 사용하고 에러 메시지의 의미만 파악할 수 있다면, 충분히 고칠 수 있다.</li> + <li><strong>논리 에러(Logic errors)</strong>: 구문은 올바르지만, 코드의 의미자체가 잘못된 경우이다. 즉 프로그램은 정상적으로 돌아가지만, 원하는 결과를 얻지 못하는 경우이다. 에러 메시지가 직접적으로 표시되지 않기 때문에, 일반적으로 구문에러보다 에러 수정이 힘들다.</li> +</ul> + +<p>물론, 간단하지는 않지만 좀 더 세분화된 분류가 있다. 그렇지만, 위의 분류가 처음에는 이해하기 좋다. 우리는 앞으로 이 두가지 종류에 대해 알아볼 것이다.</p> + +<h2 id="잘못된_예">잘못된 예</h2> + +<p>시작하기 앞서, 이전에 볼 '숫자맞추기'게임을 살펴보자 (이번 시간을 제외하고는 앞으로 일부러 에러를 만든 코드를 볼 것입니다.) 깃허브에 가서 로컬 지역에 저장합니다. -> <a href="https://github.com/mdn/learning-area/blob/master/javascript/introduction-to-js-1/troubleshooting/number-game-errors.html">number-game-errors.html</a> (see it <a href="http://mdn.github.io/learning-area/javascript/introduction-to-js-1/troubleshooting/number-game-errors.html">running live here</a>).</p> + +<ol> + <li>시작하기에 앞서, 파일을 본인이 사용하는 텍스트 에디터와 브라우저를 통해 연다.</li> + <li>프로그램을 실행시켜본다.("Submit Button"을 눌렀을 때, 정상적으로 실행이 되면 안된다)</li> +</ol> + +<div class="note"> +<p><strong>Note</strong>: You might well have your own version of the game example that doesn't work, which you might want to fix! We'd still like you to work through the article with our version, so that you can learn the techniques we are teaching here. Then you can go back and try to fix your example.</p> +</div> + +<p>여기서 구문 에러가 발생했을때 볼 수 있는 개발자 콘솔에 대해 살펴보고, 이를 통해 수정해보자. 이제부터 시작이다!</p> + +<h2 id="구문Syntax_에러_고치기">구문(Syntax) 에러 고치기</h2> + +<p>수업 앞쪽에서 간단한 자바스크립트 명령어를 <a href="/en-US/docs/Learn/Common_questions/What_are_browser_developer_tools">developer tools JavaScript console</a> 에서 살펴보았다 (만약 모르겠다면 앞의 링크를 살펴보자). 좋은 것은, 브라우저의 자바스크립트 엔진이 구문에러가 발생할 대마다 에러메시지를 콘솔에게 던져준다. 자, 이제 시작해보자</p> + +<ol> + <li> 열려져 있는 <code>number-game-errors.html</code>이 있는 탭으로 가서 자바스크립트 콘솔창을 연다. 다음줄을 따라 에러메시지를 볼 수 있을 것이다.<img alt="" src="https://mdn.mozillademos.org/files/13496/not-a-function.png" style="display: block; margin: 0 auto;"></li> + <li>이는 쉬운 에러에 속하기 때문에, 브라우저가 해결하도록 팁등을 알려준다. (위의 캡처사진은 FireFox이지만, 아마 다른 브라우저에서도 비슷한 내용을 제공해준다). 왼쪽부터 살펴보면, + <ul> + <li>빨간색 "x"는 에러라는 것을 의미한다.</li> + <li>무엇이 잘못됬는지 알려준다. 여기서는 "TypeError: guessSubmit.addeventListener is not a function"</li> + <li>"Learn More" 링크는 다양한 내용이 있는 MDN 페이지와 연결해 에러의 의미를 설명해준다.</li> + <li>자바스크립트 파일의 이름으로 개발자툴의 디버거 탭을 연결한다. 이 링크를 따라가면, 에러가 발생한 정확한 위치를 찾을 수 있다.</li> + <li>에러가 발생한 줄번호와, 그 줄에서 몇번째 문자에 있는지 알려준다. 여기서는 86번줄, 앞에서 3번째 문자이다</li> + </ul> + </li> + <li>편집기에서 86번째 줄을 보자. + <pre class="brush: js">guessSubmit.addeventListener('click', checkGuess);</pre> + </li> + <li>"guessSubmit.addeventListener is not a function"라고 에러메시지가 뜨는걸로 보아, 아마 철자가 잘못되었을 것이다. 만약 철자가 애매하거나하면, MDN에서 찾아보는것이 좋을 것이다. 현재로 가장 좋은 방법은 검색엔진에서 "mdn <em>name-of-feature</em>" 를 검색하는 것이다. 예를들자면 다음을 살펴보자 -> <code><a href="/en-US/docs/Web/API/EventTarget/addEventListener">addEventListener()</a></code>.</li> + <li>여기서 살펴보며, 함수의 이름 철자가 틀려서 에러가 났음을 알수 있다. 자바스크립트와 같은 프로그래밍은 정확하기 때문에 한글자라도 틀리면 에러가 날 것이다. <code>addeventListener</code>를 <code>addEventListener</code>러 바꿈으로 에러는 해결된다. 고쳐보자.</li> +</ol> + +<div class="note"> +<p><strong>Note</strong>: See our <a href="/en-US/docs/Web/JavaScript/Reference/Errors/Not_a_function">TypeError: "x" is not a function</a> reference page for more details about this error.</p> +</div> + +<h3 id="반복되는_구문에러">반복되는 구문에러</h3> + +<ol> + <li>저장하고 새로고침해보자. 하지만 그래도 여전히 에러가 난다.</li> + <li>이제 숫자를 입력하고 "Submit guess" 버튼을 눌러보자. 그런데, 또 다른 에러가 나타났다!<img alt="" src="https://mdn.mozillademos.org/files/13498/variable-is-null.png" style="display: block; margin: 0 auto;"></li> + <li>이번에는 에러 메시지가 78번 줄에 "TypeError: lowOrHi is null" 라고 떳다. + <div class="note"><strong>Note</strong>: This error didn't come up as soon as the page was loaded because this error occurred inside a function (inside the <code>checkGuess() { ... }</code> block). As you'll learn in more detail in our later functions article, code inside functions runs in a separate scope to code outside functions. In this case, the code was not run and the error was not thrown until the <code>checkGuess()</code> function was run by line 86.</div> + <strong>Note</strong>: <code><a href="/en-US/docs/Glossary/Null">Null</a></code> is a special value that means "nothing", or "no value". So <code>lowOrHi</code> has been declared and initialised, but not with any meaningful value — it has no type or value.</li> + <li>78번줄은 다음 코드다. + <pre class="brush: js">lowOrHi.textContent = 'Last guess was too high!';</pre> + </li> + <li>이줄에서는 <code>lowOrHi</code>변수의<code> textContent</code>속성을 문자열로 지정하지만, <code>lowOrHi</code>가 어떤 역할을 하는지 포함하지 않았기 때문에 동작되지 않는다. 왜 그런지 살펴보면, 예제의 <code>lowOrHi</code>의 다른 예제를 보면 알 수 있다. 가장 가까이에 잇는 부분은 48번줄에서 찾을 수 있다. + <pre class="brush: js">var lowOrHi = document.querySelector('lowOrHi');</pre> + </li> + <li>여기서는 변수로 하여금 HTML안의 요소로 정보를 가지도록 하려고 한다. 이 줄이 실행되고 나서 값의 null인지도 확인해보자. 49번줄에 다음 코드를 추가해보자. + <pre class="brush: js">console.log(lowOrHi);</pre> + + <div class="note"> + <p><strong>Note</strong>: <code><a href="/en-US/docs/Web/API/Console/log">console.log()</a></code> is a really useful debugging function that prints a value to the console. So it will print the value of <code>lowOrHi</code> to the console as soon as we have tried to set it in line 48.</p> + </div> + </li> + <li>저장하고 새로고침해보면, 콘솔창에서 <code>console.log()</code> 의 결과를 볼 수 있을 것이다.<img alt="" src="https://mdn.mozillademos.org/files/13494/console-log-output.png" style="display: block; margin: 0 auto;"> 물론, <code>lowOrHi</code>'s값은 여전히 null이므로 48번줄은 문제가 있다고 볼 수 있다.</li> + <li>문제가 무엇인지 생각해보자. 49번줄 <code><a href="/en-US/docs/Web/API/Document/querySelector">document.querySelector()</a></code> 메소드는 CSS 선택자로금 선택되는 요소의 정보를 갖도록 만든다. 파일을 살펴보면, 다음과 같은 코드를 볼 수 있다. + <pre class="brush: js"><p class="lowOrHi"></p></pre> + </li> + <li>따라서 여기에 점(.) 으로 시작되는 클래스 선택자가 필요한 것이다 . 하지만 48번줄의 querySelector() 메소드에서는 바로 이 '점(.)' 이 없다. <code>lowOrHi</code>를 <code>.lowOrHi</code> 로 바꾸어 문제를 해결할 수 있다.</li> + <li>저장하고 새로고침하면, <code>console.log() </code>에서 우리가 원하는 <p> 요소를 반환할 것이다. 자, 이제 다른 에러가 해결되었다. <code>console.log()</code>를 지금 제거해도 되고 난중을 위해 나둬도 되니 알아서 하자.</li> +</ol> + +<div class="note"> +<p><strong>Note</strong>: See our <a href="/en-US/docs/Web/JavaScript/Reference/Errors/Unexpected_type">TypeError: "x" is (not) "y"</a> reference page for more details about this error.</p> +</div> + +<h3 id="세번씩_반복되는_구문에러">세번씩 반복되는 구문에러</h3> + +<ol> + <li>이제 프로그램을 계속 실행할수록, 성공횟수는 많아진다. 즉 프로그램이 종료될때까지 정확한 수를 추측하든, 횟수에 상관없이 완벽한 프로그램이 동작된다는 것이다.</li> + <li>여기서 프로그램에 처음에 보았던 똑같던 에러가 발생한다. "TypeError: resetButton.addeventListener is not a function"이라고! 하지만 이번에는 94번줄이라고 표시된다.</li> + <li>94번줄을 보면, 똑같은 실수를 하고 있다는 것을 쉽게 찾아볼 수 있다. 단지 <code>addeventListener</code> 를 <code>addEventListener</code> 로 철자만 주의해서 바꾸면 된다.</li> +</ol> + +<h2 id="논리Logic_에러">논리(Logic) 에러</h2> + +<p>이제, 프로그램은 잘 작동되지만, 몇 번 프로그램을 돌리면 추측해야 할 수가 항상 1이라는 것을 명백히 알 수 있다. 즉, 프로그램의 목표에 어긋난다는 것이다.</p> + +<p>이는 분명 어딘가에 프로그램 논리적으로 무슨 문제가 있다는 것이다.(물론, 에러가 검출되지도 않고, 잘 작동된다)</p> + +<ol> + <li><code>randomNumber</code> 변수를 찾고, 임의의 수를 처음으로 지정된 곳도 찾는다. 임의의 수가 저장된 부분은 아마 44번 줄 언저리일 것이다. + + <pre class="brush: js">var randomNumber = Math.floor(Math.random()) + 1;</pre> + 또한 한 게임이 끝나면 다시 임의의 수를 지정하는 부분은 아마 113번 줄 정도일 것이다.<br> + + <pre class="brush: js">randomNumber = Math.floor(Math.random()) + 1;</pre> + </li> + <li><code><font face="Open Sans, Arial, sans-serif">이 줄에서 문제가 발생되었는지 알기위해, </font>console.log()</code> 를 불러오자. 다음 코드를 앞선 두 코드 아래에 넣는 것도 잊지 말자. + <pre class="brush: js">console.log(randomNumber);</pre> + </li> + <li>저장하고, 새로고침하게되면 randomNumer 변수가 항상 1이 콘솔창에 표시되는 것을 알 수 있다.</li> +</ol> + +<h3 id="논리에_대한_고찰">논리에 대한 고찰</h3> + +<p>고치기 전에, 이 코드가 무슨 역할을 하는지 살펴보자. 먼저, 0과 1사이의 임의의 10진수를 생성하는 <code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/random">Math.random()</a> </code>을 살펴보자.</p> + +<pre class="brush: js">Math.random()</pre> + +<p>다음으로 가장 가까운 정수로 전달되는 <code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/floor">Math.floor()</a></code><font face="Open Sans, arial, sans-serif">안의</font><code> Math.random()</code>의 결과는 넘어간다<code>.</code> 그러고 결과값에 1을 더한다.</p> + +<pre>Math.floor(Math.random()) + 1</pre> + +<p>0과 1사이의 임의의 10진수와 가장 가까운 수 중에 작은 수는 항상 0이므로, 여기서 1을 더하면 항상 1이 된다. 따라서 가까운 수를 찾기전에 임의수에 100을 곱해야 한다. 다음 코드는 곧 0과 99사이의 수를 나타낸다.</p> + +<pre class="brush: js">Math.floor(Math.random()*100);</pre> + +<p>그러므로 여기서 1을 더하게 되면, 우리가 원하는 1과 100사이의 수가 될 것이다.</p> + +<pre class="brush: js">Math.floor(Math.random()*100) + 1;</pre> + +<p>코드를 위와 같이 고치고, 저장 후 새로고침해보자. 그러면 프로그램은 우리가 생각하는 대로 작동될 것이다.</p> + +<h2 id="다른_일반적인_에러">다른 일반적인 에러</h2> + +<p>코드상에서 맞딱드릴 수 있는 에러는 여러가지가 있다. 이번 섹션은 이러한 에러들에 대해 말해줄 것이다.</p> + +<h3 id="SyntaxError_missing_before_statement">SyntaxError: missing ; before statement</h3> + +<p>이번 에러는 일반적으로 코드의 끝부분에 세미콜론이 빠졌을 때 발생하지만, 때로는 헷갈릴 때도 있다. 예를 들어 <code>checkGuess()</code> 함수안의 코드를 고칠때를 살펴보자.</p> + +<pre class="brush: js">var userGuess = Number(guessField.value);</pre> + +<p>이 코드를 다음코드로 바꾼다.</p> + +<pre class="brush: js">var userGuess === Number(guessField.value);</pre> + +<p>당연히 이 둘의 코드가 다르기때문에 오류가 발생했을 것이다. 즉, 대입 연산자(=, 값을 변수에 지정하도록 함)와 비교연산자(===, 어떤 값과 다른값을 비교할때 쓰며, true와false중 하나가 반환됨)를 함께 혼동해서 쓰면 안된다.</p> + +<div class="note"> +<p><strong>Note</strong>: See our <a href="/en-US/docs/Web/JavaScript/Reference/Errors/Missing_semicolon_before_statement">SyntaxError: missing ; before statement</a> reference page for more details about this error.</p> +</div> + +<h3 id="어떤_값을_입력해도_항상_성공표시가_뜬다.">어떤 값을 입력해도, 항상 성공표시가 뜬다.</h3> + +<p>이 또한, 앞처럼 대입연산자와 비교연산자를 혼동해서 사용한 경우이다. 예를들어, <code>checkGuess()</code>함수 안의 다음코드</p> + +<pre class="brush: js">if (userGuess === randomNumber) {</pre> + +<p>를</p> + +<pre class="brush: js">if (userGuess = randomNumber) {</pre> + +<p>로 바꾼다면, 조건문은 항상 참이므로, 프로그램은 항상 성공했다고 뜰 것이니 주의하자!</p> + +<h3 id="SyntaxError_missing_after_argument_list">SyntaxError: missing ) after argument list</h3> + +<p>이는 보통 함수나 메소드 호출의 끝부분에 괄호 닫는것을 빼먹은 것을 의미한다.</p> + +<div class="note"> +<p><strong>Note</strong>: See our <a href="/en-US/docs/Web/JavaScript/Reference/Errors/Missing_parenthesis_after_argument_list">SyntaxError: missing ) after argument list</a> reference page for more details about this error.</p> +</div> + +<h3 id="SyntaxError_missing_after_property_id">SyntaxError: missing : after property id</h3> + +<p>이 오류는 자바스립트의 객체가 잘못되었을 때 발생하지만, 다음의 경우에는 변경할 수 있다.</p> + +<pre class="brush: js">function checkGuess() {</pre> + +<p>-></p> + +<pre class="brush: js">function checkGuess( {</pre> + +<p>이는 브라우저로 하여금 함수안의 컨텐츠를 인자로 함수에게 넘겨주는 역할을 한다. 괄호에 주의하도록 하자!</p> + +<h3 id="SyntaxError_missing_after_function_body">SyntaxError: missing } after function body</h3> + +<p>일반적으로 함수나 조건문에서 중괄호를 닫지 않아서 발생한다. <code>checkGuess()</code> 함수의 아래부분의 중괄호를 닫지않아서 에러가 발생한다.</p> + +<h3 id="SyntaxError_expected_expression_got_string_or_SyntaxError_unterminated_string_literal">SyntaxError: expected expression, got '<em>string</em>' or SyntaxError: unterminated string literal</h3> + +<p>이는 보통 문자열을 열거나 닫는 따옴표를 생략한 경우 에러가 발생한다.위의 첫번재 에러를 살펴보면, <em>string은</em> 문자열이 시작하는 부분에서 따옴표 대신 브라우저가 검색한 예상치 못한 문자열로 대체된다. 두번째 에러는 따옴표로 문자열이 끝나지 못했기 때문에 발생했다.</p> + +<p>모든 경우의 에러를 보았을 때, 지금까지 살펴본 예제에 어떻게 씨름했는지 생각해보자. 에러가 발생하면 , 발생된 줄 번호를 보고, 그 줄로 이동해 무엇이 잘못되었는지 살펴보는것이다. 이 오류가 반드시 해당 라인에 있는 것은 아니며, 위에서 언급되어진 문제로 인해 오류가 발생하지 않을 수도 있다는 점을 명심하자!</p> + +<div class="note"> +<p><strong>Note</strong>: See our <a href="/en-US/docs/Web/JavaScript/Reference/Errors/Unexpected_token">SyntaxError: Unexpected token</a> and <a href="/en-US/docs/Web/JavaScript/Reference/Errors/Unterminated_string_literal">SyntaxError: unterminated string literal</a> reference pages for more details about these errors.</p> +</div> + +<h2 id="요약">요약</h2> + +<p>자, 지끔까지 자바스크립트 프로그램에서의 에러의 특징에 대해 살펴보았다.물론, 코드상의 에러가 항상 간단한 것만은 아니다. 하지만 최소한 업무량은 줄어줄 것이며, 작업도 빠르게 마치도록 해줄 것이다.</p> + +<h2 id="더보기">더보기</h2> + +<div> +<ul> + <li>여기서 소개하지 못한 에러들도 많으니, 다음 링크에서 정보들을 찾아보며 그때그때 자세히 알아보자l — <a href="/en-US/docs/Web/JavaScript/Reference/Errors">JavaScript error reference</a>.</li> + <li>이것을 보고도 에러를 해결하지 힘들다면 <span class="short_text" id="result_box" lang="ko"><span>MDN 토론 포럼 </span></span>로 에러를 보내면 도와줄 것이다. 또한 다른 코드를 살펴보는 것도 좋다.</li> +</ul> +</div> + +<p>{{PreviousMenuNext("Learn/JavaScript/First_steps/A_first_splash", "Learn/JavaScript/First_steps/Variables", "Learn/JavaScript/First_steps")}}</p> diff --git a/files/ko/learn/javascript/howto/index.html b/files/ko/learn/javascript/howto/index.html new file mode 100644 index 0000000000..7af2a007be --- /dev/null +++ b/files/ko/learn/javascript/howto/index.html @@ -0,0 +1,294 @@ +--- +title: Solve common problems in your JavaScript code +slug: Learn/JavaScript/Howto +tags: + - 자바스크립트 + - 초보자 + - 학습 +translation_of: Learn/JavaScript/Howto +--- +<div>{{LearnSidebar}}</div> + +<div>다음의 링크들은 당신의 자바스크립트 코드가 정상적으로 작동할 수 있게 고쳐야되는 흔한 문제들의 해결책을 제시한다.</div> + +<h2 id="초보자들의_흔한_실수들">초보자들의 흔한 실수들</h2> + +<h3 id="스펠링과_대소문자를_제대로_해라">스펠링과 대소문자를 제대로 해라</h3> + +<p>코드가 작동하지 않거나 브라우저가 무언가가 undefined라고 불평하면 모든 변수 이름, 함수 이름 등을 정확하게 입력했는지 확인하십시오. </p> + +<p>문제를 일으키는 몇 가지 일반적인 내장 브라우저 함수는 다음과 같습니다.</p> + +<table class="standard-table"> + <thead> + <tr> + <th scope="col">올바른</th> + <th scope="col">잘못된</th> + </tr> + </thead> + <tbody> + <tr> + <td><code>getElementsByTagName()</code></td> + <td><code>getElementbyTagName()</code></td> + </tr> + <tr> + <td><code>getElementsByName()</code></td> + <td><code>getElementByName()</code></td> + </tr> + <tr> + <td><code>getElementsByClassName()</code></td> + <td><code>getElementByClassName()</code></td> + </tr> + <tr> + <td><code>getElementById()</code></td> + <td><code>getElementsById()</code></td> + </tr> + </tbody> +</table> + +<h3 id="세미콜론의_위치">세미콜론의 위치</h3> + +<p>세미콜론의 위치가 잘못 되지 않았는지 확인하세요. 예를들어:</p> + +<table class="standard-table"> + <thead> + <tr> + <th scope="col">올바른</th> + <th scope="col">잘못된</th> + </tr> + <tr> + <td><code>elem.style.color = 'red';</code></td> + <td><code>elem.style.color = 'red;'</code></td> + </tr> + </thead> +</table> + +<h3 id="함수">함수</h3> + +<p>함수와 관련하여 실수할 수 있는 것들이 많이 있습니다.</p> + +<p>가장 흔한 실수는 함수를 선언하고 어디서도 호출하지 않는 것입니다. 예를 들어:</p> + +<pre class="brush: js">function myFunction() { + alert('This is my function.'); +};</pre> + +<p>위 코드는 호출하지 않는 이상 아무것도 하지 않습니다.</p> + +<pre class="brush: js">myFunction();</pre> + +<h4 id="함수_스코프">함수 스코프</h4> + +<p><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Functions#Function_scope_and_conflicts">함수는 각자의 스코프가 있음</a>을 명심하세요 — 변수를 전역으로 선언하거나 함수에서 <a href="/en-US/docs/Learn/JavaScript/Building_blocks/Return_values">값을 리턴</a>하지 않는한 함수 밖에서 함수 내부에 설정된 변수 값에 접근 할 수 없습니다. (즉, 어떠한 함수 내에서도 접근 안됨)</p> + +<h4 id="리턴_문_이후_코드_실행">리턴 문 이후 코드 실행</h4> + +<p>함수 밖으로 값을 리턴할 때, 자바스크립트 인터프리터가 함수를 완전히 빠져나감을 명심하세요. — 리턴 문 이후에 선언된 코드는 절대로 실행되지 않습니다.</p> + +<p>사실, 몇몇 브라우저들은 (파이어폭스 처럼) 리턴 문 이후에 코드가 있다면 개발자 콘솔에 에러 메세지를 줍니다. 파이어폭스는 "unreachable code after return statement" 라고 알려줍니다.</p> + +<h3 id="오브젝트_표기_vs_일반적_할당">오브젝트 표기 vs 일반적 할당</h3> + +<p>보통 자바스크립테어서 무언가를 할당하려고 할때, 단일 등호기호를 사용합니다. 예:</p> + +<pre class="brush: js">const myNumber = 0;</pre> + +<p>하지만, 이 방법은 <a href="/en-US/docs/Learn/JavaScript/Objects">오브젝트</a>에선 동작하지 않습니다. — 오브젝트에선 멤버와 값 사이를 콜론으로 구분하고, 각 멤버들은 콤마로 구분합니다, 예를 들어:</p> + +<pre class="brush: js">const myObject = { + name: 'Chris', + age: 38 +}</pre> + +<h2 id="기본_정의">기본 정의</h2> + +<div class="column-container"> +<div class="column-half"> +<ul> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/What_is_JavaScript#A_high-level_definition">자바스크립트란 무엇인가?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Variables#What_is_a_variable">변수는 무엇인가?</a> </li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Strings">문자열은 무엇인가?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Arrays#What_is_an_Array">배열은 무엇인가?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Looping_code">루프는 무엇인가?</a></li> +</ul> +</div> + +<div class="column-half"> +<ul> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Functions">함수는 무엇인가?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Events">What is an event?</a> <a href="/en-US/docs/Learn/JavaScript/Building_blocks/Events">이벤트는 무엇인가?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Objects/Basics#Object_basics">오브젝트는 무엇인가?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Objects/JSON#No_really_what_is_JSON">JSON은 무엇인가?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Introduction#What_are_APIs">web API는 무엇인가?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Manipulating_documents#The_document_object_model">DOM은 무엇인가?</a></li> +</ul> +</div> +</div> + +<h2 id="Basic_use_cases">Basic use cases</h2> + +<div class="column-container"> +<div class="column-half"> +<h3 id="General">General</h3> + +<ul> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/What_is_JavaScript#How_do_you_add_JavaScript_to_your_page">How do you add JavaScript to your page?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/What_is_JavaScript#Comments">How do you add comments to JavaScript code?</a></li> +</ul> + +<h3 id="Variables">Variables</h3> + +<ul> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Variables#Declaring_a_variable">How do you declare a variable?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Variables#Initializing_a_variable">How do you initialize a variable with a value?</a></li> + <li><a href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/First_steps/Variables#Updating_a_variable">How do you update a variable's value?</a> (also see <a href="/en-US/docs/Learn/JavaScript/First_steps/Math#Assignment_operators">Assignment operators</a>)</li> + <li><a href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/First_steps/Variables#Variable_types">What data types can values have in JavaScript?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Variables#Loose_typing">What does 'loosely typed' mean?</a></li> +</ul> + +<h3 id="Math">Math</h3> + +<ul> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Math#Types_of_numbers">What types of number do you have to deal with in web development?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Math#Arithmetic_operators">How do you do basic math in JavaScript?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Math#Operator_precedence">What is operator precedence, and how is it handled in JavaScript?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Math#Increment_and_decrement_operators">How do you increment and decrement values in JavaScript?</a></li> + <li><a href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/First_steps/Math#Comparison_operators">How do you compare values in JavaScript?</a> (e.g. to see which one is bigger, or to see if one value is equal to another).</li> +</ul> + +<h3 id="Strings">Strings</h3> + +<ul> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Strings#Creating_a_string">How do you create a string in JavaScript?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Strings#Single_quotes_versus_double_quotes">Do you have to use single quotes or double quotes?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Strings#Escaping_characters_in_a_string">How do you escape characters in strings?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Strings#Concatenating_strings">How do you join strings together?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Strings#Numbers_versus_strings">Can you join strings and numbers together?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Useful_string_methods#Finding_the_length_of_a_string">How do you find the length of a string?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Useful_string_methods#Retrieving_a_specific_string_character">How you find what character is at a certain position in a string?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Useful_string_methods#Finding_a_substring_inside_a_string_and_extracting_it">How do you find and extract a specific substring from a string?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Useful_string_methods#Changing_case">How do you change the case of a string?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Useful_string_methods#Updating_parts_of_a_string">How do you replace one specific substring with another?</a></li> +</ul> +</div> + +<div class="column-half"> +<h3 id="Arrays">Arrays</h3> + +<ul> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Arrays#Creating_an_array">How do you create an array?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Arrays#Accessing_and_modifying_array_items">How do you access and modify the items in an array?</a> (this includes multidimensional arrays)</li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Arrays#Finding_the_length_of_an_array">How do you find the length of an array?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Arrays#Adding_and_removing_array_items">How you add and remove array items?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Arrays#Converting_between_strings_and_arrays">How do you split a string into array items, or join array items into a string?</a></li> +</ul> + +<h3 id="Debugging_JavaScript">Debugging JavaScript</h3> + +<ul> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/What_went_wrong#Types_of_error">What are the basic types of error?</a></li> + <li><a href="/en-US/docs/Learn/Common_questions/What_are_browser_developer_tools">What are browser developer tools, and how do you access them?</a></li> + <li><a href="/en-US/docs/Learn/Tools_and_testing/Cross_browser_testing/JavaScript#The_Console_API">How do you log a value to the JavaScript console?</a></li> + <li><a href="/en-US/docs/Learn/Tools_and_testing/Cross_browser_testing/JavaScript#Using_the_JavaScript_debugger">How do you use breakpoints, and other JavaScript debugging features?</a></li> +</ul> + +<p>For more information on JavaScript debugging, see <a href="/en-US/docs/Learn/Tools_and_testing/Cross_browser_testing/JavaScript">Handling common JavaScript problems</a>; also see <a href="/en-US/docs/Learn/JavaScript/First_steps/What_went_wrong#Other_common_errors">Other common errors</a> for a description of common errors.</p> + +<h3 id="Making_decisions_in_code">Making decisions in code</h3> + +<ul> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/conditionals">How do you execute different blocks of code, depending on a variable's value or other condition?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/conditionals#if_..._else_statements">How do you use if ...else statements?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/conditionals#Nesting_if_..._else">How do nest one decision block inside another?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/conditionals#Logical_operators_AND_OR_and_NOT">How do you use AND, OR, and NOT operators in JavaScript?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/conditionals#switch_statements">How do you conveniently handle a large number of choices for one condition?</a></li> + <li><a href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Building_blocks/conditionals#Ternary_operator">How do you use a ternary operator to make a quick choice between two options based on a true or false test?</a></li> +</ul> + +<h3 id="Loopingiteration">Looping/iteration</h3> + +<ul> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Looping_code">How do you run the same bit of code over and over again?</a></li> + <li><a href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Building_blocks/Looping_code#Exiting_loops_with_break">How do you exit a loop before the end if a certain condition is met?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Looping_code#Skipping_iterations_with_continue">How do you skip to the next iteration of a loop if a certain condition is met?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Looping_code#while_and_do_..._while">How do you use while and do ... while loops?</a></li> + <li>How to iterate over the elements in an array</li> + <li>How to iterate over the elements in a multidimensional array</li> + <li>How to iterate over the members in an object</li> + <li>How to iterate over the members of an object nested inside an array</li> +</ul> +</div> +</div> + +<h2 id="Intermediate_use_cases">Intermediate use cases</h2> + +<div class="column-container"> +<div class="column-half"> +<h3 id="Functions">Functions</h3> + +<ul> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Functions#Built-in_browser_functions">How do you find functions in the browser?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Functions#Functions_versus_methods">What is the difference between a function and a method?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Build_your_own_function">How do you create your own functions?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Functions#Invoking_functions">How do you run (call, or invoke) a function?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Functions#Anonymous_functions">What is an anonymous function?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Functions#Function_parameters">How do you specify parameters (or arguments) when invoking a function?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Functions#Function_scope_and_conflicts">What is function scope?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Return_values">What are return values, and how do you use them?</a></li> +</ul> + +<h3 id="Objects">Objects</h3> + +<ul> + <li><a href="/en-US/docs/Learn/JavaScript/Objects/Basics#Object_basics">How do you create an object?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Objects/Basics#Dot_notation">What is dot notation?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Objects/Basics#Bracket_notation">What is bracket notation?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Objects/Basics#Setting_object_members">How do you get and set the methods and properties of an object?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Objects/Basics#What_is_this">What is <code>this</code>, in the context of an object?</a></li> + <li><a href="/docs/Learn/JavaScript/Objects/Object-oriented_JS#Object-oriented_programming_from_10000_meters">What is object-oriented programming?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Objects/Object-oriented_JS#Constructors_and_object_instances">What are constructors and instances, and how do you create them?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Objects/Object-oriented_JS#Other_ways_to_create_object_instances">What different ways are there to create objects in JavaScript?</a></li> +</ul> + +<h3 id="JSON">JSON</h3> + +<ul> + <li><a href="/en-US/docs/Learn/JavaScript/Objects/JSON#JSON_structure">How do you structure JSON data, and read it from JavaScript?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Objects/JSON#Loading_our_JSON">How can you load a JSON file into a page?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Objects/JSON#Converting_between_objects_and_text">How do you convert a JSON object to a text string, and back again?</a></li> +</ul> +</div> + +<div class="column-half"> +<h3 id="Events">Events</h3> + +<ul> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Events#Event_handler_properties">What are event handlers and how do you use them?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Events#Inline_event_handlers_%E2%80%94_don%27t_use_these">What are inline event handlers?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Events#addEventListener()_and_removeEventListener()">What does the <code>addEventListener()</code> function do, and how do you use it?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Events#What_mechanism_should_I_use">Which mechanism should I use to add event code to my web pages?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Events#Event_objects">What are event objects, and how do you use them?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Events#Preventing_default_behaviour">How do you prevent default event behaviour?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Events#Event_bubbling_and_capture">How do events fire on nested elements? (event propagation, also related — event bubbling and capturing)</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Events#Event_delegation">What is event delegation, and how does it work?</a></li> +</ul> + +<h3 id="Object-oriented_JavaScript">Object-oriented JavaScript</h3> + +<ul> + <li><a href="/en-US/docs/Learn/JavaScript/Objects/Object_prototypes">What are object prototypes?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Objects/Object_prototypes#The_constructor_property">What is the constructor property, and how can you use it?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Objects/Object_prototypes#Modifying_prototypes">How do you add methods to the constructor?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Objects/Inheritance">How do you create a new constructor that inherits its members from a parent constructor?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Objects/Inheritance#Object_member_summary">When should you use inheritance in JavaScript?</a></li> +</ul> + +<h3 id="Web_APIs">Web APIs</h3> + +<ul> + <li><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Manipulating_documents#Active_learning_Basic_DOM_manipulation">How do you manipulate the DOM (e.g. adding or removing elements) using JavaScript?</a></li> +</ul> + +<p> </p> +</div> +</div> diff --git a/files/ko/learn/javascript/index.html b/files/ko/learn/javascript/index.html new file mode 100644 index 0000000000..b45501e751 --- /dev/null +++ b/files/ko/learn/javascript/index.html @@ -0,0 +1,70 @@ +--- +title: JavaScript - 동적인 클라이언트측 스크립트 언어 +slug: Learn/JavaScript +tags: + - Beginner + - JavaScript + - 입문 + - 입문자 + - 자바스크립트 + - 자바스크립트 입문자 +translation_of: Learn/JavaScript +--- +<div>{{LearnSidebar}}</div> + +<p class="summary">{{Glossary("JavaScript")}} 는 웹 페이지의 복잡한 것들을 구현할 수 있는 프로그래밍 언어입니다. 웹페이지는 단순히 변하지 않고 정적인 정보들만 보여주는 것 이상의 일을 합니다. 시간의 흐름에 따라 업데이트 되는 콘텐츠, 동적인 지도와 움직이는 2D/3D 그래픽, 또는 스크롤 가능한 비디오 쥬크박스들과 여러 가지들을 보여줍니다. 여러분은 '아마도 JavaScript 그 일들을 하고 있겠구나'라고 생각하실 수 있습니다.</p> + +<h2 id="학습_과정">학습 과정</h2> + +<p>JavaScript 는 HTML 이나 CSS 와 같은 관련 기술들보다 배우기가 더 어렵습니다. JavaScript 에 입문하기 전에, 적어도 아래의 두가지 기술을 먼저 배우고, 아마도 다른 것들도 배우는 것이 좋습니다. 다음 과정들을 통해 시작하세요.</p> + +<ul> + <li><a href="/ko/docs/Learn/Getting_started_with_the_web">Web과 함께 시작하기</a></li> + <li><a href="/ko/docs/Learn/HTML/Introduction_to_HTML">HTML 소개</a></li> + <li><a href="/ko/docs/Learn/CSS/Introduction_to_CSS">CSS 소개</a></li> +</ul> + +<p>다른 프로그래밍 언어를 배웠던 경험이 있다면 도움이 될 수도 있습니다.</p> + +<p>JavaScript 의 기본적인 것들이 익숙해진 이후에, 여러분은 더 고급 주제들을 배울 준비가 되어 있어야 합니다. 예를 들면 다음과 같습니다.</p> + +<ul> + <li>JavaScript 심화, <a href="/ko/docs/Web/JavaScript/Guide">자바스크립트 안내서</a></li> + <li><a href="/ko/docs/Web/API">웹 API 참조문서</a></li> +</ul> + +<h2 id="과정">과정</h2> + +<p>이 주제에는 다음 과정들이 제안된 순서대로 포함되어 있습니다.</p> + +<dl> + <dt><a href="/ko/docs/Learn/JavaScript/First_steps">자바스크립트 첫걸음</a></dt> + <dd>JavaScript 과정에서, JavaScript를 이용해 첫번째 경험을 쌓기 이전에 "JavaScript 는 무엇인가요?", "어떻게 생겼나요?", 그리고 "그것으로 무엇을 할 수 있죠?" 와 같은 질문에 대답 할 수 있어야 합니다. 그 이후에, 변수, 문자열, 숫자 그리고 배열과 같은 JavaScript 의 기능에 대해 살펴봅시다.</dd> + <dt><a href="/ko/docs/Learn/JavaScript/Building_blocks">JavaScript 구성 요소</a></dt> + <dd>이 과정에서는, 조건문, 반복문, 함수, 그리고 이벤트와 같이 일반적으로 쓰이며 괄호로 감싸여진 형태인 JavaScript 의 핵심적인 기본 기능들을 살펴볼 것입니다. 여러분은 이미 이것들에 대해 이미 보셨겟지만, 그저 지나쳤을 것이니, 우리는 이것에 대해 자세히 살펴볼 것입니다.</dd> + <dt><a href="/ko/docs/Learn/JavaScript/Objects">JavaScript 객체 소개</a></dt> + <dd>JavaScript 에서는 문자열과 배열같은 핵심적인 JavaScript 기능부터 JavaScript 보다 위에 작성된 브라우저의 API 까지 거의 대부분이 객체입니다. 심지어 관련 함수와 변수들을 효율적인 패키지로 캡슐화하기 위해 객체를 만들 수도 있습니다. 여러분이 언어에 대한 이해도를 높이고 효율적으로 코드를 작성하기 위해서라면 JavaScript 의 객체 지향적인 특성을 이해하는 것이 중요합니다. 따라서 우리는 이 과정을 통해 여러분을 도와드릴 것입니다. 여기에서는 객체 이론과 문법에 대해 설명하고 어떻게 객체를 만들고, JSON 데이터가 무엇이고 어떻게 작동하는지에 대해 설명합니다.</dd> + <dt><a href="/ko/docs/Learn/JavaScript/Asynchronous">비동기적 JavaScript</a> </dt> + <dd> + <p>이 부분에서 우리는 Javascript의 비동기적 실행이 왜 중요한지, 서버에서 리소스를 가져올때와 같은 시간지연을 유발하는 동작들을 어떻게 효과적으로 다룰지등에 대해 살펴봅니다.</p> + </dd> + <dt><a href="/ko/docs/Learn/JavaScript/Client-side_web_APIs">Client-side web APIs</a></dt> + <dd>클라이언트측의 웹사이트나 응용프로그램을 위해 JavaScript 를 작성하는 경우, 여러분은 브라우저와 운영체제 또는 다른 웹사이트의 데이터를 위한 API를 사용하기 전에 이상한 길에 빠지지 않을 겁니다. 이번 과정에서는 API 가 무엇인지, 그리고 개발 도중 자주 접하게 될 가장 보편적인 API들을 사용하는 방법에 대해 알아 볼 것입니다.</dd> +</dl> + +<h2 id="일반적인_JavaScript_문제_해결">일반적인 JavaScript 문제 해결</h2> + +<p><a href="/ko/docs/Learn/JavaScript/Howto">JavaScript 를 이용한 보편적인 문제 해결</a> 은 웹페이지를 만들 때 발생하는 일반적인 문제들을 JavaScript 로 해결하는 방법에 대한 링크들을 제공합니다.</p> + +<h2 id="관련_항목">관련 항목</h2> + +<dl> + <dt><a href="/ko/docs/Web/JavaScript">JavaScript on MDN</a></dt> + <dd>JavaScript 의 핵심적인 문서입니다. 여기서 JavaScript 언어의 모든 측면에 대해 넓은 참조 문서들과 JavaScript 경험자들을 위한 심화 튜토리얼들을 찾을 수 있습니다.</dd> + <dt><a href="https://learnjavascript.online/">JavaScript 배우기</a></dt> + <dd>Web 개발자 지망생을 위한 훌륭한 자료 — 짧은 강좌와 대화형 테스트, 자동화된 평가로 지도하는 인터랙티브 환경에서 JavaScript를 배웁니다. 처음 40개 강좌 는 무료이며, 한번의 작은 금액 지불로 전체코스를 수강할 수 있습니다.</dd> + <dt><a href="https://exlskills.com/learn-en/courses/javascript-fundamentals-basics_javascript">EXLskills의 JavaScript 기초</a></dt> + <dd>EXLskills의 오픈소스 코스로 JavaScript를 무료로 배우세요 JS로 어플리케이션 제작을 시작하는데 필요한 모든것을 배울수 있습니다.</dd> + <dt><a href="https://www.youtube.com/user/codingmath">Coding math</a></dt> + <dd>프로그래머가 되기 위해 이해해야 하는 수학을 가르치는 훌륭한 비디오 튜토리얼 시리즈 by <a href="https://twitter.com/bit101">Keith Peters</a>.</dd> +</dl> diff --git a/files/ko/learn/javascript/objects/basics/index.html b/files/ko/learn/javascript/objects/basics/index.html new file mode 100644 index 0000000000..4220f9bafc --- /dev/null +++ b/files/ko/learn/javascript/objects/basics/index.html @@ -0,0 +1,268 @@ +--- +title: JavaScript 객체 기본 +slug: Learn/JavaScript/Objects/Basics +tags: + - API + - this + - 객체 + - 객체 리터럴 + - 괄호 표기법 + - 구문 + - 배우기 + - 이론 + - 인스턴스 + - 입문자 + - 자바스크립트 + - 점 표기법 + - 코딩스크립트 +translation_of: Learn/JavaScript/Objects/Basics +--- +<div>{{LearnSidebar}}</div> + +<div>{{NextMenu("Learn/JavaScript/Objects/Object-oriented_JS", "Learn/JavaScript/Objects")}}</div> + +<p class="summary">이 글에서는 JavaScript 객체와 관련된 기본적인 문법을 살펴보고 이전 코스에서 학습해서 이미 알고 있는 JavaScript 의 특징들과 우리가 이미 사용하고 있는 기능들이 이미 객체와 관련되어 있다는 사실을 다시 한번 복습할 것입니다.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">사전 지식:</th> + <td>컴퓨터와 관련된 기본지식, HTML 과 CSS, 그리고 JavaScript 에 대한 기본 지식 (<a href="/ko/docs/Learn/JavaScript/First_steps">JavaScript 첫걸음</a> 및 <a href="/ko/docs/Learn/JavaScript/Building_blocks">JavaScript 구성요소</a> 참조).</td> + </tr> + <tr> + <th scope="row">목표:</th> + <td>객체지향 프로그래밍에 대한 기본 이론을 이해하고, JavaScript 에서 객체가 어떻게 처리되는지("대부분이 객체임") 학습 후, JavaScript 객체를 실제로 이용하는 방법에 대해 알게되는 것을 목표로 합니다.</td> + </tr> + </tbody> +</table> + +<h2 id="객체_기본">객체 기본</h2> + +<p>객체는 관련된 데이터와 함수(일반적으로 여러 데이터와 함수로 이루어지는데, 객체 안에 있을 때는 보통 프로퍼티와 메소드라고 부릅니다)의 집합입니다. 예제를 통해서 실제 객체가 무엇인지 알아보도록 합시다.</p> + +<p>시작하기에 앞서, <a href="https://github.com/mdn/learning-area/blob/master/javascript/oojs/introduction/oojs.html">oojs.html</a> 파일의 복사본을 로컬 환경에 만듭니다. 이 파일은 우리가 작성한 소스코드를 포함하는 작은 {{HTMLElement("script")}} 요소를 포함하고 있습니다. 우리는 기본 객체 문법을 탐구하기 위한 기반으로 이 파일을 사용할 것입니다. 예제를 제대로 따라하려면 반드시 <a href="/ko/docs/Learn/Common_questions/What_are_browser_developer_tools#The_JavaScript_console">개발자 도구 JavaScript 콘솔</a>을 열어두고, 몇몇 명령어를 직접 입력할 준비가 되어있어야 합니다.</p> + +<p>여타 JavaScript 의 요소들과 마찬가지로, 객체를 생성하는 것은 변수를 정의하고 초기화하는 것으로 시작합니다. 아래의 JavaScript 코드를 oojs.html 파일의 script tag 사이에 입력하고 저장 한 후, 리로드 해보세요.</p> + +<pre class="brush: js">var person = {};</pre> + +<p>이제 JS 콘솔에 <code>person</code> 을 입력하면 다음과 같은 결과를 보게됩니다.</p> + +<pre class="brush: js">[object Object]</pre> + +<p>축하합니다, 여러분은 벌써 첫 번째 객체를 생성하였습니다. 하지만 텅 빈 객체여서 우린 이걸로 뭘 할 수는 없습니다. 자, 이제 이 오브젝트를 다음과 같이 고쳐봅시다.</p> + +<pre class="brush: js">var person = { + name: ['Bob', 'Smith'], + age: 32, + gender: 'male', + interests: ['music', 'skiing'], + bio: function() { + alert(this.name[0] + ' ' + this.name[1] + ' is ' + this.age + ' years old. He likes ' + this.interests[0] + ' and ' + this.interests[1] + '.'); + }, + greeting: function() { + alert('Hi! I\'m ' + this.name[0] + '.'); + } +}; +</pre> + +<p>저장 후 리로드 한 다음에 아래의 내용을 브라우저 개발자 도구의 JavaScript 콘솔에 입력해보세요.</p> + +<pre class="brush: js">person.name +person.name[0] +person.age +person.interests[1] +person.bio() +person.greeting()</pre> + +<p>자, 이제 당신은 객체에 포함된 데이터와 함수를 갖게 되었으며, 이것들을 간단하고 멋진 문법을 통해 사용할 수 있게되었습니다!</p> + +<div class="note"> +<p><strong>Note</strong>: 만약 여기까지 진행하는데 어려움이 있다면, 제가 만들어놓은 파일과 비교해보세요 — <a href="https://github.com/mdn/learning-area/blob/master/javascript/oojs/introduction/oojs-finished.html">oojs-finished.html</a> (그리고 <a href="http://mdn.github.io/learning-area/javascript/oojs/introduction/oojs-finished.html">실행되는 예제도 보세요</a>). Live 버전에서는 텅빈 화면만 보이겠지만, 그게 정상입니다 — 다시, 개발자도구를 열고 객체 구조를 들여다보기 위해 위에 언급된 명령어를 입력해보세요.</p> +</div> + +<p>자, 이제 뭘 해볼까요? 객체는 각기 다른 이름(위의 예에서는 <code>name</code> 과 <code>age</code>)과 값(예제에서, <code>['Bob', 'Smith']</code> 과 <code>32</code>)을 갖는 복수개의 멤버로 구성됩니다. 한 쌍의 이름과 값은 ',' 로 구분되야 하고, 이름과 값은 ':' 으로 분리됩니다. 결국 문법은 아래와 같은 패턴이 됩니다.</p> + +<pre class="brush: js">var objectName = { + member1Name: member1Value, + member2Name: member2Value, + member3Name: member3Value +};</pre> + +<p>객체를 구성하는 멤버의 값은 어떤 것이라도 될 수 있습니다. 우리가 만든 person 객체는 문자열, 숫자, 배열 두개와 두개의 함수를 가지고 있습니다. 처음 4개의 아이템은 데이터 아이템인데, 이걸 객체의 <strong>프로퍼티(속성) </strong>라고 부릅니다. 끝에 두개의 아이템은 함수인데 이 함수를 통해 데이터를 가지고 뭔가 일을 할 수 있게 됩니다. 이걸 우리는 <strong>메소드</strong> 라고 부릅니다.</p> + +<p>이런 객체는 객체 리터럴(<strong>object literal)</strong> 이라고 부릅니다. 객체를 생성할 때 컨텐츠를 그대로 대입합니다. 객체 리터럴은 클래스로부터 생성하는 방식과는 다릅니다. 이 방식은 뒤에서 살펴보게 될겁니다.</p> + +<p>객체 리터럴을 사용해서 객체를 생성하는 것은 연속된 구조체나 연관된 데이터를 일정한 방법으로 변환하고자 할 때 많이 쓰이는 방법입니다. 예를 들면 서버에게 주소를 데이터베이스에 넣어달라고 요청하는 경우입니다. 각 아이템들을 하나 하나 개별 전송하는 것보다, 하나의 객체를 전송하는 것이 훨씬 효율적입니다. 또 각 아이템들을 이름으로 구분해서 사용하기 원할 때도 배열을 사용하는 것보다 훨씬 쉽습니다.</p> + +<h2 id="점_표기법">점 표기법</h2> + +<p>위에서, 우리는 객체의 프로퍼티와 메소드를 <strong>점 표기법</strong>을 통해 접근했습니다. 객체 이름(person)은 <strong>네임스페이스</strong>처럼 동작합니다. 객체내에 <strong>캡슐화되어있는</strong>것에 접근하려면 먼저 점을 입력해야합니다. 그 다음 점을 찍고 접근하고자 하는 항목을 적습니다. 간단한 프로퍼티의 이름일 수도 있을 것이고, 배열의 일부이거나 객체의 메소드를 호출할 수도 있습니다.</p> + +<pre class="brush: js">person.age +person.interests[1] +person.bio()</pre> + +<h3 id="하위_namespaces">하위 namespaces</h3> + +<p>다른 객체를 객체 멤버의 값으로 갖는 것도 가능합니다. 예를 들면, 다음과 같은 name 멤버를 </p> + +<pre class="brush: js">name: ['Bob', 'Smith'],</pre> + +<p>아래와 같이 바꿔봅시다.</p> + +<pre class="brush: js">name : { + first: 'Bob', + last: 'Smith' +},</pre> + +<p>자, 이제 우리는 성공적으로 <strong>하위 namespace</strong> 를 만들었습니다. 복잡해보이지만, 사실 그렇지도 않습니다. 이 속성을 사용하려면 그저 끝에 다른 점을 하나 찍어주기만 하면 됩니다. JS 콘솔에서 아래와 같이 입력해보세요.</p> + +<pre class="brush: js">person.name.first +person.name.last</pre> + +<p><strong>중요</strong>: 객체의 속성이 바뀌었으니까, 기존 메소드 코드를 바꿔 줘야 합니다. 기존 코드를</p> + +<pre class="brush: js">name[0] +name[1]</pre> + +<p>아래와 같이 바꿔줘야 합니다.</p> + +<pre class="brush: js">name.first +name.last</pre> + +<p>그렇지 않으면 기존 메소드는 더 이상 동작하지 않을 것입니다.</p> + +<h2 id="괄호_표기법">괄호 표기법</h2> + +<p>객체의 프로퍼티에 접근하는 다른 방법으로 괄호 표기법을 사용하는 것이 있습니다. 다음과 같이 사용하는 대신</p> + +<pre class="brush: js">person.age +person.name.first</pre> + +<p>이렇게 사용할 수 있습니다.</p> + +<pre class="brush: js">person['age'] +person['name']['first']</pre> + +<p>이런 방식은 배열 속에 있는 항목에 접근하는 방법과 매우 유사해 보이는데 실제로도 이는 기본적으로 동일한 것입니다. 한 항목을 선택하기 위해 인덱스 숫자를 이용하는 대신에 각 멤버의 값들과 연결된 이름을 이용합니다. 객체가 간혹 <strong>연관배열 (associative arrays</strong>)이라고 불리는 것이 당연합니다. 연관배열은 배열이 숫자를 값에 연결하는 것과 같은 방법으로 스트링을 값에 매핑합니다.</p> + +<h2 id="객체_멤버_설정하기">객체 멤버 설정하기</h2> + +<p>지금까지는 객체 멤버를 단순히 가져오기만(또는 <strong>반환</strong>) 했습니다. 설정할 멤버를 간단히 명시하여(점이나 대괄호 표기법을 사용) 객체 멤버의 값을 <strong>설정</strong>(갱신)하는 것도 물론 가능합니다.</p> + +<pre class="brush: js">person.age = 45; +person['name']['last'] = 'Cratchit';</pre> + +<p>위의 코드를 입력한 다음, 객체 멤버값을 아래와 같이 다시 확인해봅시다.</p> + +<pre class="brush: js">person.age +person['name']['last']</pre> + +<p>객체 멤버를 설정하는 것은 단순히 기존에 존재하는 프로퍼티나 메소드로 값을 설정하는 것 뿐 아니라, 완전히 새로운 멤버를 생성할 수도 있습니다. JS 콘솔에서 아래 내용을 입력해보세요.</p> + +<pre class="brush: js">person['eyes'] = 'hazel'; +person.farewell = function() { alert("Bye everybody!"); }</pre> + +<p>자, 이제 새로운 멤버를 테스트해보세요.</p> + +<pre class="brush: js">person['eyes'] +person.farewell()</pre> + +<p>대괄호 표현의 이점 중 하나는 멤버의 값을 동적으로 변경할 수 있을 뿐아니라, 멤버 이름까지도 동적으로 사용할 수 있다는 것입니다. 자, 만약 사용자가 두개의 텍스트 입력을 통해서 people 데이터에 커스텀 값을 넣고 싶어한다고 가정해봅시다. 그 값은 다음과 같이 얻어올 수 있을겁니다.</p> + +<pre class="brush: js">var myDataName = nameInput.value; +var myDataValue = nameValue.value;</pre> + +<p>이제 <code>person</code> 객체에 다음과 같이 새 멤버의 이름과 값을 추가할 수 있습니다.</p> + +<pre class="brush: js">person[myDataName] = myDataValue;</pre> + +<p>자, 제대로 동작하는지 보려면 아래와 같이 <code>person</code> 객체에 대괄호를 붙여서 확인해보면 됩니다.</p> + +<pre class="brush: js">var myDataName = 'height'; +var myDataValue = '1.75m'; +person[myDataName] = myDataValue;</pre> + +<p>이제 저장하고 리로드후 아래코드를 입력해보세요.</p> + +<pre class="brush: js">person.height</pre> + +<p>점 표기법으로는 위의 예제처럼 멤버의 이름을 동적으로 사용할 수 없고, 상수 값만을 사용해야 합니다.</p> + +<h2 id="this_는_무엇인가">"this" 는 무엇인가?</h2> + +<p>자, 우리가 이제 보게될 메소드가 좀 이상하게 보일 수도 있을겁니다. 예제를 한번 봐주세요</p> + +<pre class="brush: js">greeting: function() { + alert('Hi! I\'m ' + this.name.first + '.'); +}</pre> + +<p>아마도 "this" 가 뭔지 의아하실 것입니다. <code>this</code> 키워드는 지금 동작하고 있는 코드를 가지고 있는 객체를 가리킵니다. 위의 예제에서 <code>this</code> 는 <code>person</code> 객체와 동일합니다. 그럼 왜 직접 <code>person</code> 객체를 쓰지 않은걸까요? 앞으로 보게될 <a href="/ko/docs/Learn/JavaScript/Objects/Object-oriented_JS">입문자를 위한 객체 지향 JavaScript</a> 문서에서 우리가 생성자를 공부하게 될 때, 혹은 그것 말고도 기타 등등의 상황에서 <code>this</code> 는 매우 유용하게 사용됩니다. 이 this 라는 녀석은 객체 멤버의 컨텍스트가 바뀌는 경우에도 언제나 정확한 값을 사용하게 해줍니다(예를 들어, 두개의 다른 <code>person</code> 객체가 각각 다른 이름으로 인스턴스로 생성된 상태에서 인사말을 출력하기 위해 객체의 name 을 참조해야 한다고 생각해보세요).</p> + +<p>간략화된 person 객체를 가지고 설명을 좀 해보겠습니다.</p> + +<pre class="brush: js">var person1 = { + name: 'Chris', + greeting: function() { + alert('Hi! I\'m ' + this.name + '.'); + } +} + +var person2 = { + name: 'Brian', + greeting: function() { + alert('Hi! I\'m ' + this.name + '.'); + } +}</pre> + +<p>이 예제에서, 메소드의 실제 코드는 완전히 동일하지만 <code>person1.greeting()</code> 은 "Hi! I'm Chris." 를 출력합니다. 반면 <code>person2.greeting()</code> 은 "Hi! I'm Brian." 을 출력하게 됩니다. 앞서 이야기한 것처럼, <code>this</code> 은 실행중인 코드가 속해있는 객체입니다. 객체 리터럴을 직접 지정해서 사용하는 경우라면 그리 유용하지 않겠지만, 동적으로 객체를 생성하는 경우(예를 들면 생성자를 사용하는 경우)에는 매우 유용합니다. 이 부분은 추후에 더 명확하게 이해가 될 겁니다.</p> + +<h2 id="객체를_줄곧_사용해_왔습니다">객체를 줄곧 사용해 왔습니다</h2> + +<p>예제코드를 따라하다보니, 이쯤 되면 슬슬 "점" 표기법을 사용하는 것이 꽤 자연스럽게 느껴질 것입니다. 물론 이 코스 내내 사용했기 때문입니다! 샘플에서 사용하였던 브라우저 내장 API 나 JavaScript 객체들은 실제로 우리가 공부했던 구조와 완전히 동일한 방법으로 구현된 것들입니다. 물론 우리가 봤던 예제보다 복잡하기는 합니다.</p> + +<p>자, 다음과 같이 String의 메소드를 사용했다고 가정합시다.</p> + +<pre class="brush: js">myString.split(',');</pre> + +<p><code><a href="https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/String">String</a></code> 클래스의 인스턴스가 가진 메소드를 사용하고 있습니다. 코드에서 String 을 생성할 때 마다 <code>String</code> 의 인스턴스가 만들어지고, 그렇게 만들어진 인스턴스는 당연히 공통적으로 사용할 수 있는 메소드와 프러퍼티를 가집니다.</p> + +<p>아래와 같이 도큐먼트 오브젝트 모델(DOM)에 접근할때면,</p> + +<pre class="brush: js">var myDiv = document.createElement('div'); +var myVideo = document.querySelector('video');</pre> + +<p><code><a href="https://developer.mozilla.org/ko/docs/Web/API/Document">Document</a></code> 클래스의 인스턴스를 통해 메소드를 사용하고 있는 것입니다. 각 웹페이지가 로딩될 때, <code>Document</code> 인스턴스가 만들어지고, 전체 웹 페이지 구조와 컨텐츠 그리고 URL같은 기능들을 제공하는 <code>document</code> 가 호출됩니다. 다시 말하지만 이건 여러 공통 메소드와 프로퍼티들이 이 인스턴스를 통해 사용가능하게 됩니다.</p> + +<p>우리가 계속 사용해왔던 다른 내장 객체/API(<code><a href="/ko/docs/Web/JavaScript/Reference/Global_Objects/Array">Array</a></code>, <code><a href="/ko/docs/Web/JavaScript/Reference/Global_Objects/Math">Math</a></code> 등등)들도 마찬가지입니다</p> + +<p>모든 내장 객체/API가 자동으로 객체의 인스턴스를 생성하는 것은 아니라는 것에 주의 하세요. 예를 들어, <a href="/ko/docs/Web/API/Notifications_API">Notifications API</a> — 최근 브라우져들이 시스템 알림을 사용하게 하는 기능 — 는 사용자가 발생시시길 원하는 notification 만을 선택하게 하는 생성자를 사용해야 합니다. JavaScript 콘솔에 다음 내용을 입력해보세요</p> + +<pre class="brush: js">var myNotification = new Notification('Hello!');</pre> + +<p>다음 문서에서 생성자에 대해서 좀더 자세히 알아볼 것입니다.</p> + +<div class="note"> +<p><strong>Note</strong>: 객체간 통신은 <strong>message passing</strong> 방식을 사용한다고 생각하는게 좋습니다. 한 객체가 다른 객체에게 어떤 액션을 요청해야 하는 경우, 그 객체는 다른 객체가 가지고 있는 메소드를 통해서 메세지를 보내는 것이고, 응답을 기다리는 것입니다. 그 응답은 것이 우리가 알고 있는 return 값입니다.</p> +</div> + +<h2 id="요약">요약</h2> + +<p>축하합니다, 첫 번째 JavaScript 객체 설명 문서를 끝까지 읽으셨습니다. 이제 여러분은 JavaScript 객체를 어떻게 활용하는지 이해하게 되었습니다. 간단한 사용자 정의 객체를 만드는 방법을 포함해서요. 또 객체는 데이터와 연관된 함수를 저장하는데 매우 유용한 구조라는 것도 알게 되었습니다. 만약 <code>person</code> 객체가 가지고 있는 모든 프로퍼티와 메소드를 따로 따로 분리된 변수와 함수로 구현하려고 한다면 그것이야 말로 비효율적이고 끔찍한 일이 될 것입니다. 변수명과 함수명들이 중복된다거나 하는 일도 비일비재 할 것입니다. 객체는 고유의 패키지에 우리의 정보를 안전하게 정보를 보호해주는 역활을 합니다.</p> + +<p>다음 장에서는 객체지향(OOP) 이론을 배우고, JavaScript 에서는 객체지향이 어떻게 사용되었는지 알아볼 것입니다.</p> + +<p>{{NextMenu("Learn/JavaScript/Objects/Object-oriented_JS", "Learn/JavaScript/Objects")}}</p> + +<h2 id="이_모듈_에서는">이 모듈 에서는</h2> + +<ul> + <li><a href="https://developer.mozilla.org/ko/docs/Learn/JavaScript/Objects/Basics">객체 기본</a></li> + <li><a href="https://developer.mozilla.org/ko/docs/Learn/JavaScript/Objects/Object-oriented_JS">입문자를위한 객체 지향 JavaScript</a></li> + <li><a href="https://developer.mozilla.org/ko/docs/Learn/JavaScript/Objects/Object_prototypes">객체 프로토타입</a></li> + <li><a href="https://developer.mozilla.org/ko/docs/Learn/JavaScript/Objects/Inheritance">JavaScript 에서의 상속</a></li> + <li><a href="https://developer.mozilla.org/ko/docs/Learn/JavaScript/Objects/JSON">JSON 데이터와 작업</a></li> + <li><a href="https://developer.mozilla.org/ko/docs/Learn/JavaScript/Objects/Object_building_practice">객체 생성 실습</a></li> + <li><a href="https://developer.mozilla.org/ko/docs/Learn/JavaScript/Objects/Adding_bouncing_balls_features">bouncing balls demo 에 기능들 추가하기</a></li> +</ul> diff --git a/files/ko/learn/javascript/objects/index.html b/files/ko/learn/javascript/objects/index.html new file mode 100644 index 0000000000..9bdd5d8a66 --- /dev/null +++ b/files/ko/learn/javascript/objects/index.html @@ -0,0 +1,50 @@ +--- +title: JavaScript 객체 소개 +slug: Learn/JavaScript/Objects +tags: + - 객체 + - 배우기 + - 입문자 + - 자바스크립트 + - 지침 + - 코딩스크립트 + - 평가 +translation_of: Learn/JavaScript/Objects +--- +<div>{{LearnSidebar}}</div> + +<p class="summary"> 자바스크립트에서는 스트링과 배열과같은 기본적인 기능부터 가장 상단에 놓여진 브라우저 API에 이르기까지 대부분의 것들이 객체입니다. 사용자는 관련된 함수들과 변수들을 효율적인 패키지로 추상화하거나 편리한 데이터 컨테이너로 작동하는 객체를 만들 수 있습니다. 언어에 대한 지식을 가지고 더 멀리 나아고자 한다면 자바스크립트의 객체 기반의 본질을 이해하는 것이 중요하므로, 여러분을 돕기위해 이 모듈을 제공하였습니다. 여기에서는 객체 이론과 구문을 자세히 가르쳐드리며, 사용자 정의 객체를 만드는 방법도 알아볼 것입니다.</p> + +<h2 id="사전_지식">사전 지식</h2> + +<p>이 장을 읽기 전에, 여러분은 HTML 과 CSS 를 어느 정도 알고 있어야 합니다. 그렇지 않다면 <a href="/ko/docs/Web/Guide/HTML/Introduction">HTML 소개</a>와 <a href="/ko/docs/Learn/CSS/Introduction_to_CSS">CSS 소개</a>를 먼저 읽고 오시기 바랍니다.</p> + +<p>JavaScript 객체에 대해 자세히 알아보려면, 기본 문법에 대해 어느 정도 능숙해야 합니다. 이 장을 읽기 전에 <a href="/ko/docs/Learn/JavaScript/First_steps">JavaScript 첫걸음</a>과 <a href="/ko/docs/Learn/JavaScript/Building_blocks">JavaScript 구성 요소</a>를 먼저 읽어보시기를 바랍니다.</p> + +<div class="note"> +<p><strong>Note</strong>: 컴퓨터/태블릿/혹은 다른 디바이스 상에서 스스로 파일을 만들수 없는 환경이라면, <a href="http://jsbin.com/">JSBin</a> 또는 <a href="https://thimble.mozilla.org/">Thimble</a> 과 같은 온라인 코딩 프로그램을 이용하여 (거의 모든) 예제 코드를 테스트해 보실 수 있습니다.</p> +</div> + +<h2 id="가이드">가이드</h2> + +<dl> + <dt><a href="/ko/docs/Learn/JavaScript/Objects/Basics">객체 기본</a></dt> + <dd>JavaScript 객체 소개의 첫 장에서는, 기본적인 JavaScript 객체 문법을 볼 것이며, 이전 과정에서 이미 봐왔던 몇몇 JavaScript 특징들을 다시 들여다 볼 것입니다. 이를 통해 우리는 이전에 다루었던 많은 특징들이 사실상 객체였다는 사실을 알게 될 것입니다.</dd> + <dt><a href="/ko/docs/Learn/JavaScript/Objects/Object-oriented_JS">입문자를 위한 객체지향 자바스크립트</a></dt> + <dd>가장 기본적인 것으로, 우리는 객체 지향 JavaScript(OOJS) 에 초점을 둘 것입니다. 이 글에서는 객체 지향 프로그래밍(OOP) 이론의 기본 관점을 보여주고, JavaScript 가 생성자함수를 이용하여 객체 클래스를 에뮬레이트 하는 방법과 객체 인스턴스를 생성하는 방법에 대해 탐구합니다.</dd> + <dt><a href="/ko/docs/Learn/JavaScript/Objects/Object_prototypes">객체 프로토타입</a></dt> + <dd>프로토타입은 JavaScript 객체가 또다른 객체로 특성을 상속시키기 위한 메커니즘이고, 그것들은 고전적인 객체 지향 프로그래밍 언어들의 상속 메커니즘과 다르게 작동합니다. 이 글에서는 그 다름을 탐구하고, 프로토타입 체인이 동작하는 방식을 설명하며 프로토타입의 속성이 기본 생성자들로 메소드를 추가하기 위해 사용되는 방법을 보여줍니다.</dd> + <dt><a href="/ko/docs/Learn/JavaScript/Objects/Inheritance">자바스크립트에서의 상속</a></dt> + <dd>이제 OOJS 에 대한 대부분의 세부사항들에 대해서 설명이 되었으므로, 본 장에서는 "부모" 클래스로부터 특성을 상속받은 "자식" 오브젝트 클래스를 생성하는 방법을 보여줍니다. 뿐만 아니라, OOJS 를 언제 또는 어디서 사용하면 좋을 지에 대한 몇몇 조언도 기술되어있습니다.</dd> + <dt><a href="/ko/docs/Learn/JavaScript/Objects/JSON">JSON 데이터와 작업</a></dt> + <dd>JSON(JavaScript Object Notation) 은 JavaScript 객체 문법상의 구조화된 데이터를 표현하기 위한 표준 텍스트기반 포맷입니다. 그래서 주로 웹사이트 상에 데이터를 표현하고 전송하는 데 사용되고 있습니다(예를 들면, 웹페이지 상에 데이터를 디스플레이할 수 있도록 서버에서 클라이언트로의 데이터 전송). 이 글에서는 데이터에 접근하기 위해 JSON 을 파싱하고, 또 자신만의 JSON 을 작성하는 것처럼 자바스크립트를 사용하여 JSON 과 연동할 필요가 있는 모든 것들을 보여드릴 것입니다.</dd> + <dt><a href="/ko/docs/Learn/JavaScript/Objects/Object_building_practice">객체 생성 실습</a></dt> + <dd>이전 글들에서 우리는 JavaScript 객체 이론과 문법 세부사항의 중요한 것들을 보았습니다. 본 장에서는 커스텀 JavaScript 객체를 생성하는 다양한 연습을 하면서 실용적인 예들을 깊이 다룹니다.</dd> +</dl> + +<h2 id="평가">평가</h2> + +<dl> + <dt><a href="/en-US/docs/Learn/JavaScript/Objects/Adding_bouncing_balls_features">Bouncing balls demo 에 기능들 추가</a></dt> + <dd>이 평가에서는 여러분이 이전 글의 bouncing balls demo 를 시작점으로 하여, 몇 가지 새롭고 재미있는 기능들을 추가하길 기대합니다.</dd> +</dl> diff --git a/files/ko/learn/javascript/objects/inheritance/index.html b/files/ko/learn/javascript/objects/inheritance/index.html new file mode 100644 index 0000000000..72a2302d15 --- /dev/null +++ b/files/ko/learn/javascript/objects/inheritance/index.html @@ -0,0 +1,394 @@ +--- +title: Inheritance in JavaScript +slug: Learn/JavaScript/Objects/Inheritance +translation_of: Learn/JavaScript/Objects/Inheritance +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/JavaScript/Objects/Object_prototypes", "Learn/JavaScript/Objects/JSON", "Learn/JavaScript/Objects")}}</div> + +<p class="summary">OOJS에 대한 온갖 잡지식을 설명했으니, 이 글에서는 부모 클래스에서 자식 클래스를 상속하는 방법을 알아봅니다. 덤으로 OOJS를 구현하는데 몇 가지 참고사항도 있습니다.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">선수조건:</th> + <td>컴퓨터 기본지식, HTML과 CSS에 대한 기본적인 이해,자바스크립트에 어느 정도 익숙할 것 (see <a href="/ko/docs/Learn/JavaScript/First_steps">First steps</a> and <a href="/ko/docs/Learn/JavaScript/Building_blocks">Building blocks</a>). OOJS 기초 지식 (see <a href="/ko/docs/Learn/JavaScript/Objects/Basics">Introduction to objects</a>).</td> + </tr> + <tr> + <th scope="row">학습목표:</th> + <td>Javascript에서 상속을 구현하는 법을 이해합니다.</td> + </tr> + </tbody> +</table> + +<h2 id="프로토타입_상속">프로토타입 상속</h2> + +<p>지금까지 몇 가지 상속을 살펴보았습니다 — 프로토타입 체인이 어떻게 동작하는지, 체인을 통해 멤버들을 탐색하는 것도 보았죠. 하지만 이는 대부분 브라우저가 알아서 처리하는 로직이었습니다. 그러면 우리가 직접 객체를 생성하고 상속하려면 어떻게 해야 할까요?</p> + +<p>실질적인 예제를 통해 알아보도록 합시다.</p> + +<h2 id="시작하기">시작하기</h2> + +<p>먼저 <a href="https://github.com/mdn/learning-area/blob/master/javascript/oojs/advanced/oojs-class-inheritance-start.html">oojs-class-inheritance-start.html</a>를 다운 받으시고 (<a href="http://mdn.github.io/learning-area/javascript/oojs/advanced/oojs-class-inheritance-start.html">running live</a> 페이지도 보시구요). 파일 내에서 이전 예제에서 계속 봐 왔던 <code>Person()</code> 생성자를 보실 수 있습니다 — 생성자에 속성 몇 개를 정의했기에 조금 다릅니다:</p> + +<pre class="brush: js">function Person(first, last, age, gender, interests) { + this.name = { + first, + last + }; + this.age = age; + this.gender = gender; + this.interests = interests; +};</pre> + +<p>메소드는 <em>전부</em> 아래처럼 prototype에 정의되어 있습니다:</p> + +<pre class="brush: js">Person.prototype.greeting = function() { + alert('Hi! I\'m ' + this.name.first + '.'); +};</pre> + +<div class="note"> +<p><strong>Note</strong>: 소스 코드에는 <code>bio()와</code> <code>farewell()</code>메소드가 정의되어 있습니다. 잠시 후에 다른 생성자로 어떻게 상속하는지 알아보도록 합시다.</p> +</div> + +<p>객체 지향에 대해 처음 정의할 때 언급했었던 <code>Teacher</code> 클래스를 만들어 봅시다. <code>Person</code>을 상속받고 아래 몇 가지를 추가해서요:</p> + +<ol> + <li><code>subject</code> 속성 — 교사가 가르치는 과목을 나타냅니다.</li> + <li>기존의 <code>greeting()</code> 보다 조금 더 공손한 인사를 하는 메소드 — 교사가 학생들에게 건넬 만한 표현으로 하죠.</li> +</ol> + +<h2 id="Teacher()_생성자_함수_정의">Teacher() 생성자 함수 정의</h2> + +<p>제일 처음 단계에서는 <code>Teacher()</code> 생성자를 만들어야 합니다 — 기존 코드 밑에 아래 코드를 추가하세요:</p> + +<pre class="brush: js">function Teacher(first, last, age, gender, interests, subject) { + Person.call(this, first, last, age, gender, interests); + + this.subject = subject; +}</pre> + +<p>Person() 생성자와 여러모로 비슷해 보이지만 여지껏 보지 못했던 한가지 차이점이 있습니다 — <code><a href="/ko/docs/Web/JavaScript/Reference/Global_Objects/Function/call">call()</a></code> 함수죠. call() 함수의 첫번째 매개변수는 다른 곳에서 정의된 함수를 현재 컨텍스트에서 실행할 수 있도록 합니다. 실행하고자 하는 함수의 첫 번째 매개변수로 this를 전달하고 나머지는 실제 함수 실행에 필요한 인자들을 전달하면 됩니다.</p> + +<p>Teacher()의 생성자는 <code>Person()</code>을 상속받았으므로 같은 매개변수들이 필요합니다. 따라서 동일한 매개변수들을 <code>call()</code>의 인자로 전달하여 실행합니다.</p> + +<p>마지막 줄에서는 새 속성인 <code>subject</code>를 정의하여 Person이 아닌 Teacher만이 갖는 속성을 만들어 줍니다.</p> + +<p>참고로 아래와 같이 할 수도 있습니다:</p> + +<pre class="brush: js">function Teacher(first, last, age, gender, interests, subject) { + this.name = { + first, + last + }; + this.age = age; + this.gender = gender; + this.interests = interests; + this.subject = subject; +}</pre> + +<p>다만 이는 <code>Person()</code>을 상속받은게 아니라 단지 동일한 인자를 정의했을 뿐이죠. 이건 원하는 방법이 아닐 뿐더러 코드의 길이만 더 늘어났습니다.</p> + +<h3 id="매개변수가_없는_생성자_상속하기">매개변수가 없는 생성자 상속하기</h3> + +<p>상속하려는 생성자가 속성을 매개변수로 받지 않는다면 <code>call()</code>의 매개변수에도 아무것도 전달할 필요가 없습니다. 아래처럼 간단한 생성자가 있다면:</p> + +<pre class="brush: js">function Brick() { + this.width = 10; + this.height = 20; +}</pre> + +<p><code>width</code>와 <code>height</code> 속성을 상속받기 위해 아래처럼만 하면 됩니다(물론 이후 설명할 방법을 써도 되구요):</p> + +<pre class="brush: js">function BlueGlassBrick() { + Brick.call(this); + + this.opacity = 0.5; + this.color = 'blue'; +}</pre> + +<p><code>call() </code>함수에 this만 넘긴 것을 보세요. — <code>Brick()</code> 생성자에서 매개변수를 통해 초기화 하는 속성들이 없으므로 <code>call()</code>에도 넘길 필요가 없습니다.</p> + +<h2 id="Teacher()의_프로토타입과_생성자_참조_설정하기">Teacher()의 프로토타입과 생성자 참조 설정하기</h2> + +<p>다 좋은데 문제가 있습니다. 방금 정의한 새 생성자에는 생성자 함수 자신에 대한 참조만 가지고 있는 프로토타입 속성이 할당되어 있습니다. 정작 상속 받은 Person() 생성자의 prototype 속성은 없죠. Javascript 콘솔에서 <code>Object.getOwnPropertyNames(Teacher.prototype)</code>을 쳐서 확인해 보세요. 다음엔 <code>Teacher</code>를 <code>Person</code>으로 바꿔서 확인해 보세요. Teacher()생성자는 Person()의 메소드를 상속받지 못하였습니다. <code>Person.prototype.greeting</code>과 <code>Teacher.prototype.greeting</code> 구문을 실행하여 비교해 보세요. <code>Teacher()</code>가 메소드도 상속 받으려면 어떻게 해야 할까요?</p> + +<ol> + <li>기존 코드에 아래 코드를 추가하세요: + <pre class="brush: js">Teacher.prototype = Object.create(Person.prototype);</pre> + 구원 투수 <code><a href="/ko/docs/Web/JavaScript/Reference/Global_Objects/Object/create">create()</a></code>의 등판입니다. 새 객체를 생성하여 <code>Teacher.prototype</code>으로 할당했죠. 새 객체는 <code>Person.prototype</code> 객체를 자신의 프로토타입으로 가지고 있으므로 <code>Person.prototype</code>에 정의된 모든 메소드를 사용할 수 있습니다.</li> + <li>넘어가기 전에 한가지 더 해야 합니다. 마지막 줄을 추가하고 나면 <code>Teacher.prototype</code>의 <code>constructor</code> 속성이 Person()으로 되어 있습니다. <code>Teacher.prototype</code>에 <code>Person.prototype</code>을 상속받은 객체를 할당했기 때문이죠. 코드를 저장한 뒤 브라우저로 불러와서 Teacher.prototype.constructor 구문의 반환 값을 확인해 보세요.</li> + <li>문제의 소지가 있으므로 고쳐야 됩니다. 소스에 아래 코드를 추가하세요: + <pre class="brush: js">Teacher.prototype.constructor = Teacher;</pre> + </li> + <li>저장하고 다시 브라우저에서 불러오면 의도한대로 <code>Teacher.prototype.constructor</code>가 <code>Teacher()</code>를 반환합니다. 게다가 <code>Person()</code>도 상속받았죠!</li> +</ol> + +<h2 id="Teacher()에_새_greeting()_함수_부여하기">Teacher()에 새 greeting() 함수 부여하기</h2> + +<p><code>Teacher()</code>에 새로운 <code>greeting()</code> 함수를 정의하여 코드를 완성합시다.</p> + +<p>가장 간단한 방법은 Teacher()의 프로토타입에 정의합니다. — 아래 코드를 추가하세요:</p> + +<pre class="brush: js">Teacher.prototype.greeting = function() { + var prefix; + + if (this.gender === 'male' || this.gender === 'Male' || this.gender === 'm' || this.gender === 'M') { + prefix = 'Mr.'; + } else if (this.gender === 'female' || this.gender === 'Female' || this.gender === 'f' || this.gender === 'F') { + prefix = 'Mrs.'; + } else { + prefix = 'Mx.'; + } + + alert('Hello. My name is ' + prefix + ' ' + this.name.last + ', and I teach ' + this.subject + '.'); +};</pre> + +<p>조건문을 이용해서 성별에 따라 적절한 호칭이 붙은 교사의 인삿말을 alert 창으로 띄웁니다.</p> + +<h2 id="예제_사용해_보기">예제 사용해 보기</h2> + +<p>소스를 환성했으니 아래 코드를 통해 새 <code>Teacher()</code> 인스턴스를 생성해 봅시다(아니면 인자를 원하는 값으로 변경하시거나요):</p> + +<pre class="brush: js">var teacher1 = new Teacher('Dave', 'Griffiths', 31, 'male', ['football', 'cookery'], 'mathematics');</pre> + +<p>저장한 코드를 다시 불러와서 아래처럼 <code>teacher1</code>의 속성과 메소드를 확인해 봅시다:</p> + +<pre class="brush: js">teacher1.name.first; +teacher1.interests[0]; +teacher1.bio(); +teacher1.subject; +teacher1.greeting(); +teacher1.farewell();</pre> + +<p>아주 잘 실행될 겁니다. 1, 2, 3, 6 줄은 Person() 생성자(클래스)에서 상속 받은 멤버에 접근합니다. 4번째 줄은 Teacher() 생성자(클래스)만 가지고 있는 멤버에 접근합니다. 5번째 줄은 Person()에서 상속 받은 멤버도 있지만 Teacher()가 이미 자신만의 새 메소드를 정의했으므로 Teacher()의 메소드에 접근합니다.</p> + +<div class="note"> +<p><strong>Note</strong>: 코드가 잘 동작하지 않으면 <a href="https://github.com/mdn/learning-area/blob/master/javascript/oojs/advanced/oojs-class-inheritance-finished.html">완성된 버전</a>을 확인해 보세요. (<a href="http://mdn.github.io/learning-area/javascript/oojs/advanced/oojs-class-inheritance-finished.html">실행 페이지</a>도 보시구요).</p> +</div> + +<p>이 테크닉이 Javascript에서 상속 받는 클래스를 만드는 유일한 방법은 아니지만 잘 동작하며 상속을 구현하는 방법을 잘 설명하고 있습니다.</p> + +<p>조금 더 명확한 방식으로 Javascript에서 상속을 구현하는 새 {{glossary("ECMAScript")}} 기능도 관심 가질만한 주제입니다(<a href="/ko/docs/Web/JavaScript/Reference/Classes">Classes</a> 참조). 아직까지 많은 브라우저에서 지원하지 못하고 있기 때문에 여기서 다를 주제는 아닙니다. 여러 문서에서 제시한 코드들은 IE9보다 더 오래된 구형 브라우저에서도 사용 가능하며 더 이전 버전을 지원하기 위한 방법들도 있습니다. </p> + +<p>JavaScript 라이브러리를 쓰면 간단합니다 — 상속 기능을 사용하기 위한 보편적인 방법이죠. 예를들어 <a href="http://coffeescript.org/#classes">CoffeeScript</a>는 <code>class</code>와 <code>extends</code>등의 기능을 제공합니다.</p> + +<h2 id="더_연습하기">더 연습하기</h2> + +<p><a href="/ko/docs/Learn/JavaScript/Objects/Object-oriented_JS#Object-oriented_programming_from_10000_meters">OOP theory section</a>, 에서는 개념적으로 Person을 상속받고 Teacher보다 덜 공손한 <code>greeting()</code> 메소드를 재정의한 <code>Student</code> 클래스를 정의했었습니다. 해당 절에서 <code>Student</code>의 인삿말이 어땠는지 확인해 보시고 <code>Person()</code>을 상속받는 <code>Student()</code> 생성자를 구현해 보세요. <code>greeting()</code> 함수도 재정의 해 보시구요.</p> + +<div class="note"> +<p><strong>Note</strong>: 코드가 잘 동작하지 않으면 <a href="https://github.com/mdn/learning-area/blob/master/javascript/oojs/advanced/oojs-class-inheritance-student.html">완성된 버전</a> 을 확인해 보세요.(<a href="http://mdn.github.io/learning-area/javascript/oojs/advanced/oojs-class-inheritance-student.html">실행 페이지</a>도 보시구요).</p> +</div> + +<h2 id="객체_멤버_요약">객체 멤버 요약</h2> + +<p>요약하면, 상속에 있어 고려해야 할 세 가지 유형의 속성/메소드가 있습니다:</p> + +<ol> + <li>생성자 함수 내에서 인스턴스에 정의하는 유형. 직접 작성한 코드에서는 생성자 함수 내에 <code>this.x = x</code> 구문과 유사하게 정의되어 있으므로 발견하기 쉽습니다. 브라우저 내장 코드에서는 객체 인스턴스(보통 <code>new</code> 키워드를 통해 생성, ex) <code>var myInstance = new myConstructor()</code>)에서만 접근할 수 있는 멤버입니다.</li> + <li>생성자에 직접 정의하는 유형, 생성자에서만 사용 가능합니다. 브라우저 내장 객체에서 흔히 사용하는 방식인데, 인스턴스가 아니라 생성자 함수에서 바로 호출되는 유형입니다. <code>Object.key()</code> 같은 함수들이죠.</li> + <li>인스턴스와 자식 클래스에 상속하기 위해 생성자의 프로토타입에 정의하는 유형. 생성자의 프로토타이비 속성에 정의되는 모든 멤버를 의미합니다. ex) <code>myConstructor.prototype.x()</code>.</li> +</ol> + +<p>뭐가 뭔지 헷갈려도 걱정하지 마세요 — 배우는 중이니 차츰 익숙해질겁니다.</p> + +<h2 id="ECMAScript_2015_클래스">ECMAScript 2015 클래스</h2> + +<p>ECMAScript 2015에서는 C++나 Java와 유사한 <a href="/ko/docs/Web/JavaScript/Reference/Classes">클래스 문법</a>을 공개하여 클래스를 조금 더 쉽고 명확하게 재활용 할 수 있게 되었습니다. 이 절에서는 프로토타입 상속으로 작성한 Person과 Teacher 예제를 클래스 문법으로 변경하고 어떻게 동작하는지 설명하겠습니다.</p> + +<div class="note"> +<p><strong>Note</strong>: 대부분의 최신 브라우저에서 새로운 클래스 작성 방식을 지원합니다만 일부 구형 브라우저(Internet Explorer가 대표적)에서는 동작하지 않으므로 하위호환성을 위해 프로토타입 상속을 배워둘 필요가 있습니다.</p> +</div> + +<p>Class-스타일로 재작성한 Person 예제를 보시죠:</p> + +<pre><code>class Person { + constructor(first, last, age, gender, interests) { + this.name = { + first, + last + }; + this.age = age; + this.gender = gender; + this.interests = interests; + } + + greeting() { + console.log(`Hi! I'm ${this.name.first}`); + }; + + farewell() { + console.log(`${this.name.first} has left the building. Bye for now!`); + }; +}</code></pre> + +<p><a href="/ko/docs/Web/JavaScript/Reference/Statements/class">class</a> 구문은 새로운 클래스를 작성함을 의미합니다. Class 블록 내에서 모든 기능을 정의할 수 있습니다.</p> + + + +<ul> + <li><code><a href="/ko/docs/Web/JavaScript/Reference/Classes/constructor">constructor()</a></code> 메소드는 <code>Person</code> 클래스의 생성자를 의미합니다.</li> + <li><code>greeting()</code> and <code>farewell()</code>는 멤버 메소드입니다. 클래스의 메소드는 생성자 다음에 아무 메소드나 추가할 수 있습니다. 여기서는 읽기 쉬우라고 string 결합이 아닌 <a href="/ko/docs/Web/JavaScript/Reference/Template_literals">template literals</a>을 사용했습니다.</li> +</ul> + +<p>이제 위에서 했듯이 <a href="/ko/docs/Web/JavaScript/Reference/Operators/new"><code>new</code> 연산자</a>로 객체 인스턴스를 생성할 수 있습니다:</p> + +<pre><code>let han = new Person('Han', 'Solo', 25, 'male', ['Smuggling']); +han.greeting(); +// Hi! I'm Han + +let leia = new Person('Leia', 'Organa', 19, 'female' ['Government']); +leia.farewell(); +// Leia has left the building. Bye for now</code></pre> + +<div class="note"> +<p><strong>Note</strong>: 코드를 까보면 class 부분은 프로토타입 상속으로 변환이 됩니다. — 문법 설탕(syntactic sugar)의 일종인거죠. 하지만 읽기 쉽다는데 대부분 동의하실 겁니다.</p> +</div> + +<h3 id="class_문법으로_상속">class 문법으로 상속</h3> + +<p>위에서 사람을 나타내는 클래스를 만들었습니다. Person 클래스는 일반적인 사람이 가질 만한 특성들을 나열하고 있죠; 이 절에서는 <code>Person</code>을 class 문법으로 상속받아 <code>Teacher</code> 클래스를 만들 예정입니다. 이 작업을 하위 클래스 생성이라 부릅니다.</p> + +<p>하위 클래스를 만드려면 Javascript에서 <a href="/ko/docs/Web/JavaScript/Reference/Classes/extends">extends 키워드</a>를 통해 상속 받을 클래스를 명시합니다.</p> + +<pre><code>class Teacher extends Person { + constructor(first, last, age, gender, interests, subject, grade) { + this.name = { + first, + last + }; + + this.age = age; + this.gender = gender; + this.interests = interests; + // subject and grade are specific to Teacher + this.subject = subject; + this.grade = grade; + } +}</code></pre> + +<p><code>constructor()</code>에서 첫번쨰로 <a href="/ko/docs/Web/JavaScript/Reference/Operators/super"><code>super()</code> 연산자</a>를 정의하면 코드를 조금 더 읽기 쉬워집니다. 이는 상위 클래스의 생성자를 호출하며 super()의 매개변수를 통해 상위 클래스의 멤버를 상속받을 수 있는 코드입니다.</p> + +<pre><code>class Teacher extends Person { + constructor(first, last, age, gender, interests, subject, grade) { + super(first, last, age, gender, interests); + + // subject and grade are specific to Teacher + this.subject = subject; + this.grade = grade; + } +}</code></pre> + +<p><code>Teacher</code>의 인스턴스를 생성하면 의도한대로 이제 <code>Teacher</code>와 <code>Person</code> 양 쪽의 메소드와 속성을 사용할 수 있습니다.</p> + +<pre><code>let snape = new Teacher('Severus', 'Snape', 58, 'male', ['Potions'], 'Dark arts', 5); +snape.greeting(); // Hi! I'm Severus. +snape.farewell(); // Severus has left the building. Bye for now. +snape.age // 58 +snape.subject; // Dark arts</code></pre> + +<p>Person을 수정하지 않고 Teacher를 생성한 것처럼 또 다른 하위클래스도 생성할 수 있습니다.</p> + +<div class="note"> +<p><strong>Note</strong>: GitHub에서 <a href="https://github.com/mdn/learning-area/blob/master/javascript/oojs/advanced/es2015-class-inheritance.html">es2015-class-inheritance.html</a> 예제를 참조하세요(<a href="https://mdn.github.io/learning-area/javascript/oojs/advanced/es2015-class-inheritance.html">실행 페이지</a>).</p> +</div> + +<h2 id="Getters와_Setters">Getters와 Setters</h2> + +<p>생성한 클래스 인스턴스의 속성 값을 변경하거나 최종 값을 예측할 수 없는 경우가 있을 겁니다. Teacher 예제를 보면 인스턴스를 생성하기 전에는 어떤 과목을 가르칠지 아직 모릅니다. 학기 도중에 가르치는 과목이 변경될 수도 있구요.</p> + +<p>이런 상황에 getter/setter가 필요합니다.</p> + +<p>Teacher 클래스에 getter/setter를 추가해 봅시다. 마지막에 작성했던 예제를 그대로 사용해보죠.</p> + +<p>Getter와 setter는 쌍으로 동작합니다. Getter가 현재 값을 반환한다면 그에 대응하는 setter는 해당하는 값을 변경합니다.</p> + +<p>수정된 <code>Teacher</code> 클래스는 아래와 같습니다:</p> + +<pre><code>class Teacher extends Person { + constructor(first, last, age, gender, interests, subject, grade) { + super(first, last, age, gender, interests); + // subject and grade are specific to Teacher + this._subject = subject; + this.grade = grade; + } + + get subject() { + return this._subject; + } + + set subject(newSubject) { + this._subject = newSubject; + } +}</code></pre> + +<p>위 클래스를 보시면 <code>subject</code> 속성에 대해 getter와 setter가 생겼습니다. 멤버 변수에는 _를 붙여 getter/setter와 구분을 하였습니다. 이렇게 하지 않으면 get/set을 호출할때마다 에러가 발생합니다:</p> + +<ul> + <li><code>snape</code> 객체의 <code>_subject</code> 속성 값을 보려면 <code>snape._subject</code>를 실행합니다.</li> + <li>To show the current value of the <code>_subject</code> property of the <code>snape</code> object we can use <code>snape._subject</code>.</li> + <li><code>_subject</code>에 새 값을 할당하려면 <code>snape._subject="new value"</code>를 실행합니다.</li> +</ul> + +<p>두 기능이 실제로 어떻게 작동하는지 아래를 참조하세요:</p> + +<pre><code>// Check the default value +console.log(snape._subject) // Returns "Dark arts" + +// Change the value +snape._subject="Balloon animals" // Sets subject to "Balloon animals" + +// Check it again and see if it matches the new value +console.log(snape._subject) // Returns "Balloon animals"</code></pre> + +<div class="note"> +<p><strong>Note</strong>: GitHub에서 <a href="https://github.com/mdn/learning-area/blob/master/javascript/oojs/advanced/es2015-getters-setters.html">es2015-getters-setters.html</a> 예제를 참조하세요(<a href="https://mdn.github.io/learning-area/javascript/oojs/advanced/es2015-getters-setters.html">실행 페이지</a>).</p> +</div> + +<h2 id="JavaScript에서_언제_상속을_사용해야_할까">JavaScript에서 언제 상속을 사용해야 할까?</h2> + +<p>이 마지막 문서를 읽고 나면 "뭐가 이리 어렵냐"고 생각하실지도 모르겠습니다. 어렵긴 합니다 프로토타입과 상속은 Javascript에서 가장 난해한 부분이거든요. 하지만 이 부분은 Javascript가 강력하고 유연한 언어로써 작용할 수 있는 원동력이기에 충분한 시간을 들여 배울 가치가 있습니다.</p> + +<p>어찌보면 여러분은 항상 상속하고 있었습니다. Web API나 브라우저 내장 객체인 string, array 등의 메소드/속성을 사용하면서 암묵적으로 상속을 사용하고 있었던거죠.</p> + +<p>처음 시작하거나 작은 프로젝트에서 직접 상속을 구현하는 코드를 작성하는 경우는 그리 많지 않습니다. 필요하지도 않는데 상속을 위한 코드를 구현하는 건 시간 낭비에 불과하죠. 하지만 코드량이 많아질수록 상속이 필요한 경우가 생깁니다. 동일한 기능을 가진 클래스가 많아졌음을 발견했다면 기능들을 한데 묶어 공유할 수 있도록 일반 객체를 만들고 특이 객체들에게 상속하는 방식이 훨씬 편하고 유용하다는 점을 알 수 있습니다.</p> + +<div class="note"> +<p><strong>Note</strong>: Javascript에서는 프로토타입을 통해 상속이 구현되어 있어 이 방식을 흔히 <strong>위임</strong>이라고 표현합니다. 특이 객체들이 일반 객체에게 일부 기능의 실행을 위임하는 것이죠.</p> +</div> + +<p>상속을 구현할때 상속 레벨을 너무 깊게 하지 말고, 메소드와 속성들이 정확히 어디에 구현되어 있는지 항상 인지해야 합니다. 브라우저 내장 객체의 prototype 역시 일시적으로 수정이 가능하지만 정말로 필요한 경우를 제외하고는 건드리지 말아야 합니다. 너무 깊은 상속은 디버그 할 때 끝없는 혼돈과 고통만을 줄 겁니다.</p> + +<p>궁극적으로 객체는 함수나 반복문과 같이 고유한 역할과 장점을 지닌 채 코드를 재사용하는 또 다른 방법입니다. 서로 연관된 변수와 함수들을 하나로 묶어 다룰 필요가 있을때 객체가 좋은 아이디어입니다. 한 곳에서 다른 곳으로 데이터 집합을 전달할 때에도 객체가 유용합니다. 두가지 모두 생성자나 상속 없이도 가능한 일입니다. 딱 하나의 인스턴스만 필요할 경우 객체를 선언하지 않고 객체 리터럴만으로도 충분합니다. 당연히 상속은 필요없구요.</p> + +<h2 id="요약">요약</h2> + +<p>이 글에서는 여러분들이 반드시 알아야 할 OOJS 이론과 문법의 나머지 부분에 대해 다루고 있습니다. 이 시점에서 여러분은 javascript 객체와 OOP 기초, 프로토타입과 프로토타입 상속, 클래스(생성자)를 만들고 인스턴스를 생성하며 기능을 추가하고, 다른 클래스를 상속 받아 하위 클래스를 만드는 방법을 배웠습니다.</p> + +<p>다음 글에서는 Javascript 객체로 데이터를 교환하는 방식인 Javascript Object Notation(JSON)에 대해 알아봅시다.</p> + +<h2 id="See_also">See also</h2> + +<ul> + <li><a href="http://www.objectplayground.com/">ObjectPlayground.com</a> — A really useful interactive learning site for learning about objects.</li> + <li><a href="https://www.amazon.com/gp/product/193398869X/">Secrets of the JavaScript Ninja</a>, Chapter 6 — A good book on advanced JavaScript concepts and techniques, by John Resig and Bear Bibeault. Chapter 6 covers aspects of prototypes and inheritance really well; you can probably track down a print or online copy fairly easily.</li> + <li><a href="https://github.com/getify/You-Dont-Know-JS/blob/master/this%20&%20object%20prototypes/README.md#you-dont-know-js-this--object-prototypes">You Don't Know JS: this & Object Prototypes</a> — Part of Kyle Simpson's excellent series of JavaScript manuals, Chapter 5 in particular looks at prototypes in much more detail than we do here. We've presented a simplified view in this series of articles aimed at beginners, whereas Kyle goes into great depth and provides a more complex but more accurate picture.</li> +</ul> + +<p>{{PreviousMenuNext("Learn/JavaScript/Objects/Object_prototypes", "Learn/JavaScript/Objects/JSON", "Learn/JavaScript/Objects")}}</p> + + + +<h2 id="In_this_module">In this module</h2> + +<ul> + <li><a href="/en-US/docs/Learn/JavaScript/Objects/Basics">Object basics</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Objects/Object-oriented_JS">Object-oriented JavaScript for beginners</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Objects/Object_prototypes">Object prototypes</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Objects/Inheritance">Inheritance in JavaScript</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Objects/JSON">Working with JSON data</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Objects/Object_building_practice">Object building practice</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Objects/Adding_bouncing_balls_features">Adding features to our bouncing balls demo</a></li> +</ul> diff --git a/files/ko/learn/javascript/objects/json/index.html b/files/ko/learn/javascript/objects/json/index.html new file mode 100644 index 0000000000..a9d5751319 --- /dev/null +++ b/files/ko/learn/javascript/objects/json/index.html @@ -0,0 +1,351 @@ +--- +title: JSON으로 작업하기 +slug: Learn/JavaScript/Objects/JSON +tags: + - JSON + - JSON 객체 + - JSON 문자열로 변환 + - 입문자 + - 초보자 +translation_of: Learn/JavaScript/Objects/JSON +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/JavaScript/Objects/Inheritance", "Learn/JavaScript/Objects/Object_building_practice", "Learn/JavaScript/Objects")}}</div> + +<p class="summary">JavaScript Object Notation (JSON)은 Javascript 객체 문법으로 구조화된 데이터를 표현하기 위한 문자 기반의 표준 포맷입니다. 웹 어플리케이션에서 데이터를 전송할 때 일반적으로 사용합니다(서버에서 클라이언트로 데이터를 전송하여 표현하려거나 반대의 경우). 여기저기서 자주 보았을테니 여기선 JSON을 파싱, 데이터에 접근하고 JSON을 생성하는 등 Javascript로 JSON을 다루는 법에 대해 알아봅시다.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">사전지식:</th> + <td>컴퓨터 기초, HTML과 CSS에 대한 기본 지식, Javascript 기초 (<a href="/en-US/docs/Learn/JavaScript/First_steps">First steps</a>과 <a href="/en-US/docs/Learn/JavaScript/Building_blocks">Building blocks</a> 참조), OOJS 기초 (<a href="/en-US/docs/Learn/JavaScript/Object-oriented/Introduction">Introduction to objects</a> 참조).</td> + </tr> + <tr> + <th scope="row">목표:</th> + <td>JSON에 담긴 데이터를 이용하는 법과 JSON 객체 생성하는 법에 대해 알아보기.</td> + </tr> + </tbody> +</table> + +<h2 id="아니_대체_JSON이_뭐죠">아니, 대체 JSON이 뭐죠?</h2> + +<p>{{glossary("JSON")}} 는 <a href="https://en.wikipedia.org/wiki/Douglas_Crockford">Douglas Crockford</a>가 널리 퍼뜨린 Javascript 객체 문법을 따르는 문자 기반의 데이터 포맷입니다. JSON이 Javascript 객체 문법과 매우 유사하지만 딱히 Javascript가 아니더라도 JSON을 읽고 쓸 수 있는 기능이 다수의 프로그래밍 환경에서 제공됩니다.</p> + +<p>JSON은 문자열 형태로 존재합니다 — 네트워크를 통해 전송할 때 아주 유용하죠. 데이터에 억세스하기 위해서는 네이티브 JSON 객체로 변환될 필요가 있습니다. 별로 큰 문제는 아닌 것이 Javascript는 <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON">JSON</a> 전역 객체를 통해 문자열과 JSON 객체의 상호변환을 지원합니다.</p> + +<div class="note"> +<p><strong>Note</strong>: 문자열에서 네이티브 객체로 변환하는 것은 파싱(Parsing)이라고 합니다. 네트워크를 통해 전달할 수 있게 객체를 문자열로 변환하는 과정은 문자열화(Stringification)이라고 합니다.</p> +</div> + +<p>개별 JSON 객체를 <code>.json</code> 확장자를 가진 단순 텍스트 파일에 저장할 수 있습니다. {{glossary("MIME 타입")}}은 <code>application/json</code> 입니다.</p> + +<h3 id="JSON_구조">JSON 구조</h3> + +<p>위에서 설명했듯이 JSON은 Javascript 객체 리터럴 문법을 따르는 문자열입니다. JSON 안에는 마찬가지로 Javascript의 기본 데이터 타입인 문자열, 숫자, 배열, 불리언 그리고 다른 객체를 포함할 수 있습니다. 이런 방식으로 여러분은 데이터 계층을 구축할 수 있습니다, 아래 처럼요.</p> + +<pre class="brush: json notranslate">{ + "squadName": "Super hero squad", + "homeTown": "Metro City", + "formed": 2016, + "secretBase": "Super tower", + "active": true, + "members": [ + { + "name": "Molecule Man", + "age": 29, + "secretIdentity": "Dan Jukes", + "powers": [ + "Radiation resistance", + "Turning tiny", + "Radiation blast" + ] + }, + { + "name": "Madame Uppercut", + "age": 39, + "secretIdentity": "Jane Wilson", + "powers": [ + "Million tonne punch", + "Damage resistance", + "Superhuman reflexes" + ] + }, + { + "name": "Eternal Flame", + "age": 1000000, + "secretIdentity": "Unknown", + "powers": [ + "Immortality", + "Heat Immunity", + "Inferno", + "Teleportation", + "Interdimensional travel" + ] + } + ] +}</pre> + +<p>이 객체를 Javascript 프로그램에서 로드하고, 예를 들어 <code>superHeroes</code>라는 이름의 변수에 파싱하면 <a href="/en-US/docs/Learn/JavaScript/Objects/Basics">JavaScript object basics</a> 문서에서 보았던 것처럼 점/브라켓 표현법을 통해 객체 내 데이터에 접근할 수 있게 됩니다. 아래와 같이요:</p> + +<pre class="brush: js notranslate">superHeroes.homeTown +superHeroes['active']</pre> + +<p>하위 계층의 데이터에 접근하려면, 간단하게 프로퍼티 이름과 배열 인덱스의 체인을 통해 접근하면 됩니다. 예를 들어 superHeroes의 두 번째 member의 세 번째 power에 접근하려면 아래와 같이 하면 됩니다.</p> + +<pre class="brush: js notranslate">superHeroes['members'][1]['powers'][2]</pre> + +<ol> + <li>우선 변수 이름은 — <code>superHeroes</code>입니다.</li> + <li><code>members</code> 프로퍼티에 접근하려면, <code>["members"]</code>를 입력합니다.</li> + <li><code>members</code>는 객체로 구성된 배열입니다. 두 번째 객체에 접근할 것이므로 <code>[1]</code>를 입력합니다.</li> + <li>이 객체에서 <code>powers</code> 프로퍼티에 접근하려면 <code>["powers"]</code>를 입력합니다.</li> + <li><code>powers</code> 프로퍼티 안에는 위에서 선택한 hero의 superpower들이 있습니다. 세 번째 것을 선택해야 하므로 <code>[2]</code>.</li> +</ol> + +<div class="note"> +<p><strong>Note</strong>: 위에서 볼 수 있듯 <a href="http://mdn.github.io/learning-area/javascript/oojs/json/JSONTest.html">JSONTest.html</a> 예제에서 JSON 내 변수(<a href="https://github.com/mdn/learning-area/blob/master/javascript/oojs/json/JSONTest.html">source code</a> 참고)를 만들었다. 당신 브라우저의 Javascript 콘솔을 통하여 이 코드를 로드하고 그 변수 안에 얻을 수 있는 데이터에 접근해보자.</p> +</div> + +<h3 id="JSON에서의_배열">JSON에서의 배열</h3> + +<p>앞서 JSON 텍스트는 기본적으로 자바스크립트의 오브젝트와 비슷하게 생겼다고 언급하였습니다. 그리고 그것은 대부분 맞습니다. "대부분 맞다"라고 말한 이유는 자바스크립트의 배열 또한 JSON에서 유효하기 때문입니다.</p> + +<pre class="brush: json notranslate">[ + { + "name": "Molecule Man", + "age": 29, + "secretIdentity": "Dan Jukes", + "powers": [ + "Radiation resistance", + "Turning tiny", + "Radiation blast" + ] + }, + { + "name": "Madame Uppercut", + "age": 39, + "secretIdentity": "Jane Wilson", + "powers": [ + "Million tonne punch", + "Damage resistance", + "Superhuman reflexes" + ] + } +]</pre> + +<p>위 예제는 완벽히 올바른 형태의 JSON입니다. 배열의 요소(파싱된 버전)에 접근하기 위해서는 배열의 인덱스를 사용하면 됩니다. <code>[0]["powers"][0]</code> 와 같이 말이죠.</p> + +<h3 id="Other_notes">Other notes</h3> + +<ul> + <li>JSON은 순수히 데이터 포맷입니다. 오직 프로퍼티만 담을 수 있습니다. 메서드는 담을 수 없습니다.</li> + <li>JSON은 문자열과 프로퍼티의 이름 작성시 큰 따옴표만을 사용해야 합니다. 작은 따옴표는 사용불가합니다.</li> + <li>콤마나 콜론을 잘못 배치하는 사소한 실수로 인해 JSON파일이 잘못되어 작동하지 않을 수 있습니다. <a href="http://jsonlint.com/">JSONLint</a>같은 어플리케이션을 사용해 JSON 유효성 검사를 할 수 있습니다.</li> + <li>JSON은 JSON내부에 포함할 수 있는 모든 형태의 데이터 타입을 취할 수 있습니다. 즉, 배열이나 오브젝트 외에도 단일 문자열이나 숫자또한 유효한 JSON 오브젝트가 됩니다.</li> + <li>자바스크립트에서 오브젝트 프로퍼티가 따옴표로 묶이지 않을 수도 있는 것과는 달리, JSON에서는 따옴표로 묶인 문자열만이 프로퍼티로 사용될 수 있습니다.</li> +</ul> + +<h2 id="해보면서_배우기_JSON을_다뤄_보자">해보면서 배우기: JSON을 다뤄 보자</h2> + +<p>웹사이트에서 JSON 데이터를 어떻게 사용할 수 있는지 예제를 통해 살펴봅시다.</p> + +<h3 id="시작하기">시작하기</h3> + +<p>우선 로컬 저장소에 <a href="https://github.com/mdn/learning-area/blob/master/javascript/oojs/json/heroes.html">heroes.html</a> 와 <a href="https://github.com/mdn/learning-area/blob/master/javascript/oojs/json/style.css">style.css</a> 파일을 복사해주세요. style.css 파일은 페이지에 적용할 간단한 CSS를 담고 있으며, heros.html 파일은 간단한 body HTML을 담고 있습니다.</p> + +<pre class="brush: html notranslate"><header> +</header> + +<section> +</section></pre> + +<p>자바스크립트 코드를 담기 위한{{HTMLElement("script")}} 요소를 추가해 주세요. 현재는 두 줄의 코드만 작성되어 있습니다. {{HTMLElement("header")}} 와 {{HTMLElement("section")}} 요소를 참조하여 변수에 담는 코드입니다. :</p> + +<pre class="brush: js notranslate">var header = document.querySelector('header'); +var section = document.querySelector('section');</pre> + +<p>JSON 데이터를 다음 깃허브 링크에서 가져올수 있습니다. <a href="https://mdn.github.io/learning-area/javascript/oojs/json/superheroes.json">https://mdn.github.io/learning-area/javascript/oojs/json/superheroes.json</a>.</p> + +<p>페이지에 JSON 데이터를 로딩하고 DOM 조작을 통해 아래와 같이 만들어 봅시다. :</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/13857/json-superheroes.png" style="display: block; margin: 0 auto;"></p> + +<h3 id="JSON_가져오기">JSON 가져오기</h3> + +<p>JSON을 가져오기 위해서는, {{domxref("XMLHttpRequest")}} (때론 <strong>XHR</strong>)로 불리는 API를 사용하면 된다. 이것은 매우 유용한 JavaScript 오브젝트로 JavaScript (e.g. images, text, JSON, even HTML snippets)를 통해 우리가 서버로 부터 다양한 리소스를 가져오는 요청을 만들어 준다. 즉, 전체 페이지를 불러오지 않고도 필요한 부분만을 업데이트 할 수 있다. 이 기능은 좀 더 효과적으로 반응형 웹페이지을 다루는데 흥미로울 수 있으나, 아쉽게도 이 내용에 대한 자세한 부분은 여기서 다루지 않는다.</p> + +<ol> + <li>일단, 변수로 둘 JSON의 URL을 가져와야 합니다. 아래의 코드를 당신의 JavaScript 코드 내에 추가해 주세요. + <pre class="brush: js notranslate">var requestURL = 'https://mdn.github.io/learning-area/javascript/oojs/json/superheroes.json';</pre> + </li> + <li>요청을 만들기 위해, 우리는 <code>new</code> 키워드를 이용하여 <code>XMLHttpRequest</code> 생성자로부터 새로운 request 인스턴스를 생성해야 합니다. 아래의 코드를 추가해 주세요. + <pre class="brush: js notranslate">var request = new XMLHttpRequest();</pre> + </li> + <li>이제 <code><a href="/en-US/docs/Web/API/XMLHttpRequest/open">open()</a></code> 메소드를 사용해 새로운 요청을 만듭니다. 아래의 코드를 추가해 주세요. + <pre class="brush: js notranslate">request.open('GET', requestURL);</pre> + + <p>이것은 최소 두 개의 매개변수를 가집니다. 다른 선택적 매개변수도 가능해요. 이건 단순 예제니깐 두 가지 필수 매개변수만 취할게요.</p> + + <ul> + <li>HTTP 메서드는 네트워크 요청을 만들 때 사용됩니다. 이 경우 <code><a href="/en-US/docs/Web/HTTP/Methods/GET">GET</a></code> 을 사용하는게 좋겠어요. 우린 그저 데이터를 가져오면 되니깐요.</li> + <li>URL은 요청을 보낼 곳을 지정합니다. 우리가 저장해 둔 JSON 파일의 URL로 지정할게요.</li> + </ul> + </li> + <li>다음으로, 아래의 두 줄을 추가해 주세요. <code><a href="/en-US/docs/Web/API/XMLHttpRequest/responseType">responseType</a></code> 을 JSON으로 설정했어요. XHR로 하여금 서버가 JSON 데이터를 반환할 것이며, 자바스크립트 객체로서 변환될 것이라는 걸 알게 하기 위해서죠. 이제 <code><a href="/en-US/docs/Web/API/XMLHttpRequest/send">send()</a></code> 메서드를 이용해 요청을 보냅시다. + <pre class="brush: js notranslate">request.responseType = 'json'; +request.send();</pre> + </li> + <li>마지막 부분은 서버의 응답을 기다리고, 그것의 처리까지와 관련된 섹션입니다. 코드 아래에 다음의 코드를 추가해 주세요. + <pre class="brush: js notranslate">request.onload = function() { + var superHeroes = request.response; + populateHeader(superHeroes); + showHeroes(superHeroes); +}</pre> + </li> +</ol> + +<p>우리는 요청에 대한 응답을 <code>superHeroes</code>라는 변수에 저장할 겁니다.(<code><a href="/en-US/docs/Web/API/XMLHttpRequest/response">response</a></code> 프로퍼티로 가능) 이 변수는 이제 JSON 데이터에 기반한 자바스크립트 객체를 포함하게 됩니다! 두 개의 함수를 호출해 이 객체를 전달합시다. 하나는 <<code>header></code> 를 적절한 데이터로 채울 것이고, 다른 하나는 팀의 각 히어로에 대한 정보 카드를 생성하여 <code><section></code>내에 집어넣을 겁니다.</p> + +<p>우리는 로드 이벤트가 request 객체에 발생할 때에 작동하는 이벤트 핸들러 내에 코드를 넣었습니다. (<code><a href="/en-US/docs/Web/API/XMLHttpRequestEventTarget/onload">onload</a></code> 참고) 왜냐하면 응답이 성공적으로 돌아왔을 때만 로드 이벤트가 작동하기 때문입니다. 이러한 방식은 우리가 무언가를 시도하려고 할 때 <code>request.response</code> 가 확실히 가능하다는 것을 보장해 줍니다.</p> + +<h3 id="헤더_조작하기">헤더 조작하기</h3> + +<p>우린 JSON 데이터를 가져왔고, 그것을 자바스크립트 객체로 변환했어요. 이제 우리가 위에서 언급한 두 개의 함수를 사용함으로써 이것을 활용해 봅시다. 우선, 이전 코드 아래에 다음 함수 정의를 추가해 주세요.</p> + +<pre class="brush: js notranslate">function populateHeader(jsonObj) { + var myH1 = document.createElement('h1'); + myH1.textContent = jsonObj['squadName']; + header.appendChild(myH1); + + var myPara = document.createElement('p'); + myPara.textContent = 'Hometown: ' + jsonObj['homeTown'] + ' // Formed: ' + jsonObj['formed']; + header.appendChild(myPara); +}</pre> + +<p>우리는 이 매개변수를 <code>jsonObj</code>라고 이름 붙였습니다. 여러분으로 하여금 이 자바스크립트 객체가 JSON으로 부터 생겨났다는 걸 상기시켜 주기 위해서죠. 첫번째로 <code><a href="/en-US/docs/Web/API/Document/createElement">createElement()</a></code>로 {HTMLElement("h1")}} 요소를 생성하고, 이것의 <code><a href="/en-US/docs/Web/API/Node/textContent">textContent</a></code>를 객체의 <code>squadName</code> 프로퍼티와 같도록 만들어 준 뒤, <code><a href="/en-US/docs/Web/API/Node/appendChild">appendChild()</a></code>를 사용해서 헤더에 붙이도록 했습니다. We then do a very similar 이와 비슷한 과정을 paragraph에도 적용했죠. 생성하고,그것의 text content를 설정하고 헤더에 붙이도록요. 차이점이라면 그것의 텍스트가 객체의 <code>homeTown</code> 과 <code>formed</code> 프로퍼티를 포함한 문자열로 설정된 거예요.</p> + +<h3 id="히어로_정보_카드_만들기">히어로 정보 카드 만들기</h3> + +<p>자, 다음으로 슈퍼히어로 카드를 생성하고 보여줄 함수를 코드의 마지막에 추가해 주세요.</p> + +<pre class="brush: js notranslate">function showHeroes(jsonObj) { + var heroes = jsonObj['members']; + + for (var i = 0; i < heroes.length; i++) { + var myArticle = document.createElement('article'); + var myH2 = document.createElement('h2'); + var myPara1 = document.createElement('p'); + var myPara2 = document.createElement('p'); + var myPara3 = document.createElement('p'); + var myList = document.createElement('ul'); + + myH2.textContent = heroes[i].name; + myPara1.textContent = 'Secret identity: ' + heroes[i].secretIdentity; + myPara2.textContent = 'Age: ' + heroes[i].age; + myPara3.textContent = 'Superpowers:'; + + var superPowers = heroes[i].powers; + for (var j = 0; j < superPowers.length; j++) { + var listItem = document.createElement('li'); + listItem.textContent = superPowers[j]; + myList.appendChild(listItem); + } + + myArticle.appendChild(myH2); + myArticle.appendChild(myPara1); + myArticle.appendChild(myPara2); + myArticle.appendChild(myPara3); + myArticle.appendChild(myList); + + section.appendChild(myArticle); + } +}</pre> + +<p>우선, 새로운 변수 내의 자바스크립트 객체에 <code>members</code> 프로퍼티를 저장해 주세요. 이 배열은 각 히어로에 대한 정보를 가진 여러 개의 객체를 포함합니다.</p> + +<p>다음으로, 우리는 <a href="/en-US/docs/Learn/JavaScript/Building_blocks/Looping_code#The_standard_for_loop">for loop</a>를 사용하여 배열 내의 각 객체에 반복 실행을 걸겁니다.</p> + +<ol> + <li>몇 개의 새로운 요소를 생성해 주세요: <code><article></code>, <code><h2></code>, 3개의 <code><p></code>, 그리고 <code><ul></code>.</li> + <li><h2>가 히어로의 <code>name</code>을 가지도록 설정해 주세요.</li> + <li>목록 내의 정보를 소개하기 위해 세 개의 paragraph 안에 그들의 <code>secretIdentity</code>, <code>age</code>, 그리고 "Superpowers:" 라는 문장을 넣어 주세요.</li> + <li><code>superPowers</code> 라는 새로운 변수 안에 <code>powers</code>프로퍼티를 저장해 주세요. 이것은 현재 히어로의 초능력(superpower)을 열거한 배열을 포함합니다.</li> + <li>현재 히어로의 초능력을 반복 실행할 또다른 <code>for</code> 반복문을 사용합니다. 하나의 객체씩 <code><li></code> 를 생성하고, 그 안에 초능력을 집어 넣고, <code>appendChild()</code>를 사용하여 '<code>myList'</code> 라는 <code><ul></code> 안에 <code>listItem</code> 을 집어 넣습니다.</li> + <li>마지막으로 <code><article></code> (<code>myArticle</code>) 안에 <code><h2></code>, <code><p></code>, 그리고 <code><ul></code> 넣은 뒤, <code><section></code> 안에 <code><article></code>을 넣어 줍니다. 요소가 추가되어 지는 순서가 중요해요.왜냐하면 HTML 내에 보여질 거거든요.</li> +</ol> + +<div class="note"> +<p><strong>Note</strong>: 만약 실습에 문제를 겪고 있다면, <a href="https://github.com/mdn/learning-area/blob/master/javascript/oojs/json/heroes-finished.html">heroes-finished.html</a> 코드를 참조하세요. (<a href="http://mdn.github.io/learning-area/javascript/oojs/json/heroes-finished.html">running live</a> 또한 보세요.)</p> +</div> + +<div class="note"> +<p><strong>Note</strong>: 만약 우리가 주로 사용하는 JavaScript 객체에 접근하기 위한 점/괄호 표기법을 따르는데 문제를 겪고 있다면, 다른 탭이나 당신의 선호하는 텍스트 에디터에 <a href="http://mdn.github.io/learning-area/javascript/oojs/json/superheroes.json">superheroes.json</a> 파일을 여는 것이 도움이 될 것이다. 또한 당신은 점/괄호 표기법에 대한 다른 정보를 위해 <a href="/en-US/docs/Learn/JavaScript/Objects/Basics">JavaScript object basics</a> 글을 다시 확인하는 것을 권합니다.</p> +</div> + +<h2 id="객체와_문자_사이의_변환">객체와 문자 사이의 변환</h2> + +<p>위의 예제는 자바스크립트 객체에 접근한다는 관점에서 단순한 편이었죠. 왜냐하면 자바스크립트 객체를 사용해 우리는 XHR 요청을 곧장 JSON 응답으로 변환했으니깐요.</p> + +<pre class="brush: js notranslate">request.responseType = 'json';</pre> + +<p>하지만 우리는 이따금 재수 없어요. 때때로 우리는 날것의 JSON 문자열을 받기도 하고, 그것을 우리 스스로가 객체로 변환시켜야 할 때도 생기거든요. 그리고 네트워크를 통해 자바스크립트 객체를 보내고 싶을 때도 우리는 전송 전에 그걸 JSON(문자열)로 변환시켜야 해요. 다행히도, 이 두가지 문제가 웹 개발에 있어서 매우 흔한 덕에 다음과 같은 두가지 방법을 포함한 JSON 내장 객체가 브라우저 내에서 이용 가능합니다. </p> + +<ul> + <li><code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse">parse()</a></code>: JSON 문자열을 매개변수로서 수용하고, 일치하는 자바스크립트 객체로서 변환합니다.</li> + <li><code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify">stringify()</a></code>: 객체를 매개변수로서 수용하고, JSON 문자열 형태로 변환합니다. </li> +</ul> + +<p> 당신은 예제인 <a href="http://mdn.github.io/learning-area/javascript/oojs/json/heroes-finished-json-parse.html">heroes-finished-json-parse.html</a>에서 첫번째 동작을 확인할 수 있습니다.(아래 코드 참고-<a href="https://github.com/mdn/learning-area/blob/master/javascript/oojs/json/heroes-finished-json-parse.html">source code</a>) — JSON 텍스트를 반환하기 위한 추가한 XHR와 JavaScript 객체로 전환하기 위해 사용된 <code>parse()</code>제외하면 이 코드는 이전에 우리가 빌드한 것과 완전히 같은 코드입니다. 다음은중요한 코드의 일부입니다.:</p> + +<pre class="brush: js notranslate">request.open('GET', requestURL); +request.responseType = 'text'; // now we're getting a string! +request.send(); + +request.onload = function() { + var superHeroesText = request.response; // get the string from the response + var superHeroes = JSON.parse(superHeroesText); // convert it to an object + populateHeader(superHeroes); + showHeroes(superHeroes); +}</pre> + +<p>예상했겠지만, <code>stringify()</code> 는 반대의 방식으로 작용됩니다. 다음 나오는 코드 라인들을 당신의 브라우저 JavaScript 콘솔에 동작을 확인하면서 한 줄씩 입력해봅시다.:</p> + +<pre class="brush: js notranslate">var myJSON = { "name": "Chris", "age": "38" }; +myJSON +var myString = JSON.stringify(myJSON); +myString</pre> + +<p>이 페이지에서는 우리는 JavaScript 객체를 생성하고 있으며 이 객체가 무엇을 포함하고 있는지 확인하고 <code>stringify()</code> —반환된 값을 새로운 변수에 저장합니다—를 사용해서 JSON 문자열로 변환시켰습니다. 다시 한 번 더 확인해 봅시다.</p> + +<h2 id="실력을_시험해보자!">실력을 시험해보자!</h2> + +<p> 당신은 이 글의 끝에 도달했지만 가장 중요한 정보들을 기억하고 있습니까? 다음 단계를 가기 전 당신이 얼마나 이 정보를 습득하고 있는지 확인할 수 있는 테스트를 할 수 있습니다. — <a href="https://wiki.developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/Test_your_skills:_JSON">Test your skills: JSON</a></p> + +<h2 id="요약">요약</h2> + +<p> 이 글에서, 당신의 프로그램에서 JSON을 어떻게 생성하고 구성 요소를 파악할 수 있는지, 그리고 JSON 안에 묶여 있는 자료들에 어떻게 접근하는 방법을 포함한 JSON을 사용하기 위한 간단한 가이드를 제공했습니다. 다음 글에서는, 객체 지향적인 JavaScript에 대해 시작해 볼 것입니다.</p> + +<h2 id="참고">참고</h2> + +<ul> + <li><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON">JSON object reference page</a></li> + <li><a href="/en-US/docs/Web/API/XMLHttpRequest">XMLHttpRequest object reference page</a></li> + <li><a href="/en-US/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest">Using XMLHttpRequest</a></li> + <li><a href="/en-US/docs/Web/HTTP/Methods">HTTP request methods</a></li> + <li><a href="http://json.org">Official JSON web site with link to ECMA standard</a></li> +</ul> + +<p>{{PreviousMenuNext("Learn/JavaScript/Objects/Inheritance", "Learn/JavaScript/Objects/Object_building_practice", "Learn/JavaScript/Objects")}}</p> + +<h2 id="다음_단계">다음 단계</h2> + +<ul> + <li><a href="/en-US/docs/Learn/JavaScript/Objects/Basics">Object basics</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Objects/Object-oriented_JS">Object-oriented JavaScript for beginners</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Objects/Object_prototypes">Object prototypes</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Objects/Inheritance">Inheritance in JavaScript</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Objects/JSON">Working with JSON data</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Objects/Object_building_practice">Object building practice</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Objects/Adding_bouncing_balls_features">Adding features to our bouncing balls demo</a></li> +</ul> diff --git a/files/ko/learn/javascript/objects/object-oriented_js/index.html b/files/ko/learn/javascript/objects/object-oriented_js/index.html new file mode 100644 index 0000000000..df1bf59c17 --- /dev/null +++ b/files/ko/learn/javascript/objects/object-oriented_js/index.html @@ -0,0 +1,287 @@ +--- +title: Object-oriented JavaScript for beginners +slug: Learn/JavaScript/Objects/Object-oriented_JS +tags: + - Article + - Beginner + - CodingScripting + - JavaScript + - Learn + - 'l10n:priority' +translation_of: Learn/JavaScript/Objects/Object-oriented_JS +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/JavaScript/Objects/Basics", "Learn/JavaScript/Objects/Object_prototypes", "Learn/JavaScript/Objects")}}</div> + +<p class="summary">자, 이제 기초 단계를 벗어나서,객체지향 JavaScript (OOJS) 을 보도록 하죠 — 이 문서에서 객체지향 (OOP) 이론에 대한 기초를 훑어본 후, 자바스크립트가 생성자와 함수를 통해 객체 클래스 개념을 따라했는지, 그리고 어떻게 객체를 만드는지 알아볼겁니다.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">선수조건:</th> + <td>컴퓨터 기본지식, HTML과 CSS에 대한 기본적인 이해,자바스크립트에 어느 정도 익숙할 것 (see <a href="/ko/docs/Learn/JavaScript/First_steps">First steps</a> and <a href="/ko/docs/Learn/JavaScript/Building_blocks">Building blocks</a>). OOJS 기초 지식 (see <a href="/ko/docs/Learn/JavaScript/Object-oriented/Introduction">Introduction to objects</a>).</td> + </tr> + <tr> + <th scope="row">학습목표:</th> + <td>객체지향에 대한 기본 지식을 습득 하고, 객체 지향이 자바스크립트에 어떻게 적용되었는지 ( "모든 것은 객체다") 와 어떻게 생성자와 객체 인스턴스를 만드는지에 대해 이해한다.</td> + </tr> + </tbody> +</table> + +<h2 id="객체지향_프로그래밍_—_기초">객체지향 프로그래밍 — 기초</h2> + +<p>객체지향 프로그래밍(OOP)의 개요를 설명하는 것으로 시작하겠습니다. 지금 단계에서 OOP의 모든 것을 설명면 너무 복잡해서 혼란만을 가중시킬 것이기 때문에 최대한 간단히 설명하겠습니다. OOP의 기본 컨셉은 프로그램 내에서 표현하고자 하는 실 세계(real world)의 일들을 객체를 사용해서 모델링 하고, 객체를 사용하지 않으면 불가능 혹은 무지 어려웠을 일들을 쉽게 처리하는 방법을 제공한다는 것입니다.</p> + +<p>객체는 당신이 모델링하고자 하고자 하는 일이나 기능 혹은 필요한 행동들을 표현하는 프로그램 코드와 그와 연관된 데이터로 구성됩니다. 객체는 데이터(그리고, 함수 역시)를 감싸서 ,(공식적인 표현으로는 <strong>encapsulate</strong>) 객체 패키지(해당 객체를 참조하기 위한 이름. <strong>namespace </strong>라고도 불리죠)안에 보관합니다. 이는 계층 구조를 만드는데 용이하고 사용하기에도 쉽게 하기 위해서죠; 또한, 객체는 네트워크를 통해 쉽게 전송될 수 있도록 데이터를 저장하는 용도로도 많이 사용됩니다.</p> + +<h3 id="객체_템플릿_정의">객체 템플릿 정의</h3> + +<p>자, 학교의 선생님과 학생들의 정보를 보여주는 간단한 프로그램이 있다고 칩시다. 여기서는 OOP의 일반적인 개념만을 살펴볼 뿐이지, 특정 언어에 국한된 내용을 이야기하지는 않을겁니다.</p> + +<p>시작해보자면, <a href="/ko/docs/Learn/JavaScript/Objects/Basics">first objects article</a> 에서 배웠던 Person 객체로 돌아가봅시다. 거기서 "사람"에 대한 기초적인 데이터와 기능을 정의했었죠. "사람"을 구별할 수 있는 특징은 많습니다 (그들의 주소, 키,신발사이즈, DNA 프로필, 여권번호, 중요한 개인적 자실 등 ...) ,하지만 이 예제에서는 오직 이름, 나이, 성별 그리고 취미만을 다룰겁니다. 여기에 더불어 이 데이터를 기반으로 각 개인에 대한 간단한 소개말과 인사말을 표시할 수 있도록 할 겁니다 . 이런 과정을 <strong>추상화</strong> — 프로그래머의 의도에 맞추어 가장 중요한 것들만을 뽑아서 복잡한 것들을 보다 단순한 모델로 변환하는 작업 - 라고 합니다.<img alt="" src="https://mdn.mozillademos.org/files/13889/person-diagram.png" style="display: block; height: 219px; margin: 0px auto; width: 610px;"></p> + +<h3 id="실제_객체_생성">실제 객체 생성</h3> + +<p><strong>객체 인스턴스</strong>는 클래스를 통해서 만들 수 있습니다.— 객체는 클래스에 정의된 데이터와 함수를 갖습니다. Person클래스를 통해서, 실제 '사람' 객체를 생성할 수 있습니다.:</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/15163/MDN-Graphics-instantiation-2-fixed.png" style="display: block; height: 702px; margin: 0px auto; width: 695px;"></p> + +<p>클래스로부터 객체의 인스턴스가 생성될 때는 클래스의 <strong>생성자 함수</strong> 가 호출됩니다.클래스에서 객체 인스턴스가 생성되는 일련의 과정을 인스턴스화(<strong>instantiation</strong>)라고 합니다 — 객체의 인스턴스는 클래스를 통해 만들어집니다.</p> + +<h3 id="특별한_클래스">특별한 클래스</h3> + +<p>자, 이번에는 일반적인 사람이 아니라 — 일반적인 사람보다 세분화된 선생님과 학생들이 필요합니다. OOP 에서는,특정 클래스를 기반으로 새로운 클래스를 만들 수 있습니다 — <strong>child 클래스</strong> 는 <strong>부모 클래스</strong>를<strong> </strong><strong>상속</strong> 받아서 만들어집니다. child 클래스는 상속을 통해 부모 클래스에 정의된 데이터와 함수를 고스란히 사용할 수 있습니다. 클래스마다 기능이 달라지는 부분이 있다면, 직접 해당 클래스에 원하는 기능을 정의할 수 있습니다.</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/13881/MDN-Graphics-inherited-3.png" style="display: block; height: 743px; margin: 0px auto; width: 700px;"></p> + +<p>이것은 매우 유용합니다. 이름,성별,나이 등과 같이 선생님과 학생이 공유하는 많은 공통적인 특징들을 한번만 정의해도 되기 때문이죠. 또한 서로 다른 클래스에 같은 기능을 따로 정의할 수도 있습니다. 정의된 각각의 기능은 서로 다른 namespace에 존재하기 때문입니다. 예를 들어, 학생의 인사는 "안녕, 난 [이름]이야." 와 같은 형식이 될 것입니다. (ex) 안녕, 난 샘이야.) 반면 선생님은 "안녕하세요, 제 이름은 [성] [이름]이고 [과목명]을 담당하고 있습니다." 와 같이 좀 더 격식있는 형식을 사용할 것입니다. (ex) 안녕하세요, 제 이름은 데이브 그리피스이고 화학을 담당하고 있습니다.)</p> + +<div class="note"> +<p><strong>노트</strong>: 혹시 궁금해 하실까봐 말씀드리면, 여러 객체 타입에 같은 기능을 정의할 수 있는 능력을 멋진 용어로 <strong>"다형성(polymorphism)"</strong> 이라고 합니다.</p> +</div> + +<p>이제 자식 클래스들로부터 객체 인스턴스를 만들 수 있습니다. 예를 들면 :</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/13885/MDN-Graphics-instantiation-teacher-3.png" style="display: block; height: 743px; margin: 0px auto; width: 700px;"></p> + +<p>다음 부분에선, 어떻게 객체지향 프로그래밍 이론이 자바스크립트에 실제로 적용될 수 있는지 살펴보겠습니다.</p> + +<h2 id="생성자와_객체_인스턴스">생성자와 객체 인스턴스</h2> + +<p>자바스크립트는 객체와 그 기능을 정의하기 위해 <strong>생성자 함수</strong>라고 불리는 특별한 함수를 사용합니다. 이는 보통 우리가 얼마나 많은 객체들을 생성해야 할지 모르기 때문에 유용합니다. 생성자는 효율적으로 필요한 만큼 객체를 생성하고, 데이터와 함수들을 설정하는 방법을 제공합니다.</p> + +<p>생성자로부터 새로운 객체 인스턴스가 생성되면, 객체의 핵심 기능 (프로토타입에 의해 정의됩니다. <a href="/ko/docs/Learn/JavaScript/Objects/Object_prototypes">Object prototypes</a> 글에서 자세히 다룰 것입니다.)이 <strong>프로토타입 체인</strong>에 의해 연결됩니다.</p> + +<p>자바스크립트에서 생성자를 이용해 클래스를 만들고, 클래스에서 객체 인스턴스를 만드는 방법을 알아봅시다. 가장 먼저, 첫 객체 글에서 보았던 <a href="https://github.com/mdn/learning-area/blob/master/javascript/oojs/introduction/oojs.html">oojs.html</a> 파일을 로컬에 새로 복사하십시오.</p> + +<h3 id="간단한_예제">간단한 예제</h3> + +<ol> + <li>어떻게 일반적인 함수를 이용해 한 사람을 정의할 수 있는지부터 보겠습니다. 이 함수를 <code>script</code> 태그 안에 추가하세요: + + <pre class="brush: js">function createNewPerson(name) { + var obj = {}; + obj.name = name; + obj.greeting = function() { + alert('Hi! I\'m ' + this.name + '.'); + }; + return obj; +}</pre> + </li> + <li>이제 이 함수를 호출하여 새로운 사람을 만들 수 있습니다. 브라우저의 자바스크립트 콘솔을 열어 다음 코드를 입력해보세요: + <pre class="brush: js">var salva = createNewPerson('Salva'); +salva.name; +salva.greeting();</pre> + 이것은 잘 작동하지만, 썩 깔끔하진 않습니다. 객체를 만들기를 원하는데, 왜 굳이 빈 객체를 만들고 내용을 채워 리턴해야 할까요? 다행스럽게도 자바스크립트는 생성자 함수의 형태로 간단한 단축 명령을 제공합니다. 하나 만들어 보도록 하죠!</li> + <li>이전의 createNewPerson 함수를 다음의 코드로 교체하세요: + <pre class="brush: js">function Person(name) { + this.name = name; + this.greeting = function() { + alert('Hi! I\'m ' + this.name + '.'); + }; +}</pre> + </li> +</ol> + +<p>생성자 함수는 클래스의 자바스크립트 버전입니다. 이 함수가 함수가 가질 것 같은 모든 특징을 가지고 있지만, 아무것도 리턴하지 않고 객체를 만들지도 않는다는 것을 깨달으셨나요? 생성자 함수는 단순히 프로퍼티와 메소드를 정의합니다. 또 이를 정의할 때 this 라는 키워드가 사용되고 있는 것을 보실 수 있습니다. 이것은 객체 인스턴스가 생성될 때마다, 객체의 <code>name</code> 프로퍼티가 생성자 함수 호출에서 전달된 name 값과 같아질 것이라고 말하고 있습니다. 그리고 <code>greeting()</code> 메소드 역시 생성자에서 전달된 name 값을 사용할 것입니다.</p> + +<div class="note"> +<p><strong>노트</strong>: 관습적으로, 생성자 함수명은 대문자로 시작하게 합니다. 이 규칙은 생성자 함수가 코드 안에서 잘 구별되도록 해줍니다.</p> +</div> + +<p>그래서 어떻게 생성자 함수를 호출하여 객체들을 만들까요?</p> + +<ol> + <li>이전 코드 아래에 다음 코드들을 추가하세요: + <pre class="brush: js">var person1 = new Person('Bob'); +var person2 = new Person('Sarah');</pre> + </li> + <li> + <p>코드를 저장하고 브라우저를 새로고침합니다. 자바스크립트 콘솔에 다음 코드를 입력해보세요:</p> + </li> + <li> + <pre class="brush: js">person1.name +person1.greeting() +person2.name +person2.greeting()</pre> + </li> +</ol> + +<p>멋지군요! 이제 두 객체가 페이지에 생성된 것이 보입니다. 각각은 서로 다른 namespace에 저장되어있습니다. 객체의 프로퍼티와 메소드들을 사용하려면, <code>person1</code> 또는 <code>person2</code>로부터 호출하여야 합니다. 두 객체의 기능은 따로 패키징되어 서로 충돌하지 않을 것입니다. 그리고 두 Person 객체는 각각 고유의 <code>name</code> 프로퍼티와 <code>greeting()</code> 메소드를 사용할 수 있습니다. 이 둘이 생성될 때 부여받은 자신의 <code>name</code> 값을 사용한다는 것에 주목하십시오. 이것이 <code>this</code>를 사용하는 매우 중요한 이유 중 하나입니다. 객체들은 다른 값이 아니라, 그들이 가진 고유의 값을 사용합니다.</p> + +<p>생성자 호출을 다시 봅시다:</p> + +<pre class="brush: js">var person1 = new Person('Bob'); +var person2 = new Person('Sarah');</pre> + +<p>각각의 경우, <code>new</code> 키워드가 브라우저에게 우리가 새로운 객체 인스턴스를 만들고 싶어한다는 것을 알려줍니다. 괄호로 감싸진 매개변수들과 함께 생성자 이름을 호출하고, 결과는 변수에 담겨집니다. 일반적인 함수가 호출되는 방식과 매우 유사하죠. 각각의 인스턴스는 다음 정의에 따라 생성됩니다.</p> + +<pre class="brush: js">function Person(name) { + this.name = name; + this.greeting = function() { + alert('Hi! I\'m ' + this.name + '.'); + }; +}</pre> + +<p>새 객체가 생성된 이후, <code>person1</code>과 <code>person2</code> 변수는 다음 객체들을 가지게 됩니다.</p> + +<pre class="brush: js">{ + name: 'Bob', + greeting: function() { + alert('Hi! I\'m ' + this.name + '.'); + } +} + +{ + name: 'Sarah', + greeting: function() { + alert('Hi! I\'m ' + this.name + '.'); + } +}</pre> + +<p>우리가 생성자 함수를 호출할 때마다 매번 <code>greeting()</code> 함수를 다시 정의하는 것이 보입니다. 최선의 방법은 아니죠. 이를 피하기 위해, 우리는 prototype에 함수를 정의합니다. 이를 차후에 다시 살펴보겠습니다.</p> + +<h3 id="생성자_완성시키기">생성자 완성시키기</h3> + +<p>위에서 살펴본 예제는 시작에 불과합니다. 최종적인 <code>Person()</code> 생성자를 만들어봅시다.</p> + +<ol> + <li>여태 작성한 코드를 지우고 아래의 생성자로 대체하세요. 원리는 이전의 예제와 똑같으며, 약간 더 복잡할 뿐입니다: + <pre class="brush: js">function Person(first, last, age, gender, interests) { + this.name = { + 'first': first, + 'last' : last + }; + this.age = age; + this.gender = gender; + this.interests = interests; + this.bio = function() { + alert(this.name.first + ' ' + this.name.last + ' is ' + this.age + ' years old. He likes ' + this.interests[0] + ' and ' + this.interests[1] + '.'); + }; + this.greeting = function() { + alert('Hi! I\'m ' + this.name.first + '.'); + }; +}</pre> + </li> + <li>이제 생성자로 객체 인스턴스를 만들기 위해, 아래에 이 코드를 추가하세요: + <pre class="brush: js">var person1 = new Person('Bob', 'Smith', 32, 'male', ['music', 'skiing']);</pre> + </li> +</ol> + +<p>이제 이전에 해보았듯이, 브라우저의 자바스크립트 콘솔에서 프로퍼티와 메소드를 사용할 수 있습니다:</p> + +<pre class="brush: js">person1['age'] +person1.interests[1] +person1.bio() +// etc.</pre> + +<div class="note"> +<p><strong>노트</strong>: 만약 실행에 문제가 생긴다면, 저희가 준비한 코드와 비교해보세요. <a href="https://github.com/mdn/learning-area/blob/master/javascript/oojs/introduction/oojs-class-finished.html">oojs-class-finished.html</a> (<a href="http://mdn.github.io/learning-area/javascript/oojs/introduction/oojs-class-finished.html">또한 실제로 실행되는 모습을 보세요</a>).</p> +</div> + +<h3 id="추가_예제">추가 예제</h3> + +<p>이를 시작하기 위해서, 몇 개의 객체를 더 생성하는 코드를 추가해보세요. 그리고 생성된 객체 인스턴스의 멤버들을 사용하거나 바꿔보세요.</p> + +<p>더 나아가, 우리의 <code>bio()</code> 메소드엔 몇 가지 문제점이 있습니다. 먼저 결과가 항상 대명사 "He"를 포함한다는 점입니다. 생성된 사람이 여성이거나 다른 성별 분류를 가질지라도 말이죠. 그리고 <code>interests</code> 배열에 몇 개가 포함되어 있더라도 bio는 2개의 취미만을 출력합니다. 클래스 정의 (생성자)에서 이를 해결할 방법이 있을까요? 자유롭게 생성자를 수정해보세요. (약간의 조건문과 반복문이 필요할지도 모르겠습니다). 어떻게 성별에 따라, 혹은 취미의 개수에 따라 문장이 다르게 구성되어야할지 생각해보세요 .</p> + +<div class="note"> +<p><strong>노트</strong>: 하다가 막힌다면, 저희가 제공하는 <a href="https://github.com/mdn/learning-area/blob/master/javascript/oojs/introduction/oojs-class-further-exercises.html">GitHub 저장소의 모법 답안</a> (<a href="http://mdn.github.io/learning-area/javascript/oojs/introduction/oojs-class-further-exercises.html">그리고 실행 버전</a>)을 참고하세요. 하지만 일단 직접 해보시죠!</p> +</div> + +<h2 id="객체_인스턴스를_생성하는_다른_방법들">객체 인스턴스를 생성하는 다른 방법들</h2> + +<p>여태까지 객체 인스턴스를 만드는 두 가지 방법을 살펴보았습니다. <a href="/ko/docs/Learn/JavaScript/Objects/Basics#Object_basics">객체 리터럴을 선언하는 방법</a>과, 생성자 함수를 사용하는 방법(위를 보세요)이죠.</p> + +<p>이것들은 잘 동작하지만, 다른 방법들도 있습니다. 웹에서 정보를 찾다가 마주칠 경우를 대비해 익숙해져보는 것도 좋을 것 같습니다.</p> + +<h3 id="Object()_생성자">Object() 생성자</h3> + +<p>첫번째로, 새 객체를 만들기 위해 <code><a href="/ko/docs/Web/JavaScript/Reference/Global_Objects/Object">Object()</a></code> 생성자를 사용할 수 있습니다. 네, 최초의 object 역시 생성자를 가지고 있습니다. 빈 객체를 생성하는 함수이죠.</p> + +<ol> + <li>브라우저의 자바스크립트 콘솔에 아래 코드를 입력해보세요: + <pre class="brush: js">var person1 = new Object();</pre> + </li> + <li>이는 빈 객체를 <code>person1</code> 변수에 담습니다. 이제 이 객체에 점 표기법이나 괄호 표기법을 이용해 프로퍼티와 메소드들을 추가할 수 있습니다. 이 예제 코드를 콘솔 창에 입력해보세요. + <pre class="brush: js">person1.name = 'Chris'; +person1['age'] = 38; +person1.greeting = function() { + alert('Hi! I\'m ' + this.name + '.'); +};</pre> + </li> + <li>사전에 프로퍼티와 메소드를 정의하기 위해, <code>Object()</code> 생성자의 파라미터로 객체 리터럴을 전달할 수도 있습니다. 이 예제 코드를 콘솔 창에 입력해보세요. + <pre class="brush: js">var person1 = new Object({ + name: 'Chris', + age: 38, + greeting: function() { + alert('Hi! I\'m ' + this.name + '.'); + } +});</pre> + </li> +</ol> + +<h3 id="create()_함수_사용">create() 함수 사용</h3> + +<p>생성자는 여러분의 코드에 규칙을 부여해줍니다. 일단 생성자를 만들어두면, 이를 이용해 원하는대로 인스턴스를 생성할 수 있고, 이 인스턴스가 어디서 유래했는지 명백합니다.</p> + +<p>하지만 몇몇 사람들은 객체 인스턴스들을 생성할 때 먼저 생성자를 만들기를 원하지 않습니다. 특히 그들이 적은 수의 객체만을 생성할 때 말이죠. 자바스크립트는 <code><a href="/ko/docs/Web/JavaScript/Reference/Global_Objects/Object/create">create()</a></code>라는 내장함수를 가지고 있어 이를 가능하게 해줍니다. 이를 이용하면, 이미 존재하는 객체를 이용해 새로운 객체를 만들 수 있습니다.</p> + +<ol> + <li>이전 섹션에서 완료한 예제를 브라우저에서 열어, 아래 코드를 콘솔창에 입력해보세요. + <pre class="brush: js">var person2 = Object.create(person1);</pre> + </li> + <li>이제 이 코드를 입력해보세요. + <pre class="brush: js">person2.name +person2.greeting()</pre> + </li> +</ol> + +<p><code>person2</code>가 <code>person1</code>을 기반으로 만들어졌습니다. 새 객체는 원 객체와 같은 프로퍼티와 메소드들을 가집니다. </p> + +<p><code>create()</code> 함수의 한 가지 단점은 익스플로러 8에서는 지원하지 않는다는 점입니다. 따라서 오래된 브라우저들까지 지원하고 싶다면 생성자를 사용하는 것이 효과적입니다.</p> + +<p>다음에 <code>create()</code> 함수의 효과에 대해 더 살펴보겠습니다.</p> + +<h2 id="요약">요약</h2> + +<p>이 글은 객체지향 이론을 요약하여 설명해줍니다. 모든 부분을 다루지는 않지만, 지금 어떤 것들을 다루고 있는지에 대한 아이디어 정도는 얻을 수 있습니다. 게다가 객체 인스턴스를 생성하는 여러가지 방법에 대해서도 알아보기 시작했습니다.</p> + +<p>다음 글에서는 자바스크립트 객체 프로토타입에 대해 탐험해보겠습니다.</p> + +<p>{{PreviousMenuNext("Learn/JavaScript/Objects/Basics", "Learn/JavaScript/Objects/Object_prototypes", "Learn/JavaScript/Objects")}}</p> + +<h2 id="In_this_module">In this module</h2> + +<ul> + <li><a href="/en-US/docs/Learn/JavaScript/Objects/Basics">Object basics</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Objects/Object-oriented_JS">Object-oriented JavaScript for beginners</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Objects/Object_prototypes">Object prototypes</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Objects/Inheritance">Inheritance in JavaScript</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Objects/JSON">Working with JSON data</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Objects/Object_building_practice">Object building practice</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Objects/Adding_bouncing_balls_features">Adding features to our bouncing balls demo</a></li> +</ul> + +<p> </p> diff --git a/files/ko/learn/javascript/objects/object_prototypes/index.html b/files/ko/learn/javascript/objects/object_prototypes/index.html new file mode 100644 index 0000000000..f2eaf03498 --- /dev/null +++ b/files/ko/learn/javascript/objects/object_prototypes/index.html @@ -0,0 +1,274 @@ +--- +title: Object prototypes +slug: Learn/JavaScript/Objects/Object_prototypes +tags: + - 객체 지향 + - 상속 + - 자바스크립트 + - 프로토타입 +translation_of: Learn/JavaScript/Objects/Object_prototypes +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/JavaScript/Objects/Object-oriented_JS", "Learn/JavaScript/Objects/Inheritance", "Learn/JavaScript/Objects")}}</div> + +<p class="summary">Javascript에서는 객체를 상속하기 위하여 프로토타입이라는 방식을 사용합니다. 본 문서에서는 프로토타입 체인이 동작하는 방식을 설명하고 이미 존재하는 생성자에 메소드를 추가하기 위해 프로토타입 속성을 사용하는 법을 알아봅니다.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">선수조건:</th> + <td>컴퓨터 기본지식, HTML과 CSS에 대한 기본적인 이해,자바스크립트에 어느 정도 익숙할 것 (see <a href="/ko/docs/Learn/JavaScript/First_steps">First steps</a> and <a href="/ko/docs/Learn/JavaScript/Building_blocks">Building blocks</a>). OOJS 기초 지식 (see <a href="/ko/docs/Learn/JavaScript/Objects/Basics">Introduction to objects</a>).</td> + </tr> + <tr> + <th scope="row">학습목표:</th> + <td>Javascript 객체 프로토타입을 이해하고 프로토타입 체인이 어떻게 동작하는지, 또 프로토타입 속성에 새 메소드를 추가하는 방법을 배웁니다.</td> + </tr> + </tbody> +</table> + +<h2 id="프로토타입_기반_언어"> 프로토타입 기반 언어?</h2> + +<p>JavaScript는 흔히 <strong>프로토타입 기반 언어(prototype-based language)</strong>라 불립니다.— 모든 객체들이 메소드와 속성들을 상속 받기 위한 템플릿으로써 <strong>프로토타입 객체(prototype object)</strong>를 가진다는 의미입니다. 프로토타입 객체도 또 다시 상위 프로토타입 객체로부터 메소드와 속성을 상속 받을 수도 있고 그 상위 프로토타입 객체도 마찬가지입니다. 이를 <strong>프로토타입 체인(prototype chain)</strong>이라 부르며 다른 객체에 정의된 메소드와 속성을 한 객체에서 사용할 수 있도록 하는 근간입니다.</p> + +<p>정확히 말하자면 상속되는 속성과 메소드들은 각 객체가 아니라 객체의 생성자의 <code>prototype</code>이라는 속성에 정의되어 있습니다.</p> + +<p>JavaScript에서는 객체 인스턴스와 프로토타입 간에 연결(많은 브라우저들이 생성자의 <code>prototype</code> 속성에서 파생된 <code>__proto__</code> 속성으로 객체 인스턴스에 구현하고 있습니다.)이 구성되며 이 연결을 따라 프로토타입 체인을 타고 올라가며 속성과 메소드를 탐색합니다.</p> + +<div class="note"> +<p><strong>Note:</strong> 객체의 prototype(<code><a href="/ko/docs/Web/JavaScript/Reference/Global_Objects/Object/getPrototypeOf">Object.getPrototypeOf(obj)</a></code>함수 또는 deprecated 된 <code><a href="/ko/docs/Web/JavaScript/Reference/Global_Objects/Object/proto">__proto__</a></code>속성으로 접근 가능한)과 생성자의 <code>prototype</code> 속성의 차이를 인지하는 것이 중요합니다. 전자는 개별 객체의 속성이며 후자는 생성자의 속성입니다. 이 말은 <code>Object.getPrototypeOf(new Foobar())</code>의 반환값이 <code>Foobar.prototype</code>과 동일한 객체라는 의미입니다.</p> +</div> + +<p>자세히 알기 위해 예제를 하나 봅시다.</p> + +<h2 id="프로토타입_객체_이해하기">프로토타입 객체 이해하기</h2> + +<p><code>Person()</code> 생성자를 작성했던 예제 코드로 되돌아가 봅시다. — 브라우저로 예제 코드를 불러 오시구요. 이전 페이지에서 작업했던 예제 코드를 날려버렸다면 <a href="http://mdn.github.io/learning-area/javascript/oojs/introduction/oojs-class-further-exercises.html">oojs-class-further-exercises.html</a> 페이지를 방문해 주세요. (<a href="https://github.com/mdn/learning-area/blob/master/javascript/oojs/introduction/oojs-class-further-exercises.html">source code</a>도 보시구요).</p> + +<p>이 예제에서 생성자 함수를 정의했었습니다:</p> + +<pre class="brush: js">function Person(first, last, age, gender, interests) { + + // 속성과 메소드 정의 + this.first = first; + this.last = last; +//... +}</pre> + +<p>그리고 인스턴스도 하나 만들었구요:</p> + +<pre class="brush: js">var person1 = new Person('Bob', 'Smith', 32, 'male', ['music', 'skiing']);</pre> + +<p>Javascript 콘솔에서 "person1."을 치게 되면 브라우저는 아래처럼 해당 객체의 멤버 이름을 자동 완성 팝업으로 보여줄 것입니다:</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/13853/object-available-members.png" style="display: block; margin: 0 auto;"></p> + +<p>위에서 <code>person1</code>의 프로토타입 객체인 <code>Person()</code>에 정의된 멤버들 — <code>name</code>, <code>age</code>, <code>gender</code>, <code>interests</code>, <code>bio</code>, <code>greeting</code>을 볼 수 있습니다. 또한 — <code>watch</code>, <code>valueOf</code>처럼 <code>Person()</code>의 프로토타입 객체인 <code><a href="/ko/docs/Web/JavaScript/Reference/Global_Objects/Object">Object</a></code>에 정의된 다른 멤버들도 보실 수 있습니다. 이는 프로토타입 체인이 동작한다는 증거입니다.</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/13891/MDN-Graphics-person-person-object-2.png" style="display: block; height: 150px; margin: 0px auto; width: 700px;"></p> + +<p>그럼 실제로는 <code>Object</code>에 정의되어 있는 메소드를 <code>person1</code>에서 호출하면 어떻게 될까요?<br> + 아래 처럼 말이죠:</p> + +<pre class="brush: js">person1.valueOf()</pre> + +<p>이 메소드는 호출된 객체의 값을 단순 반환합니다. — 직접 실행해 보세요! 이때 일어나는 일은 아래와 같습니다:</p> + +<ul> + <li>브라우저는 우선 <code>person1</code> 객체가 <code>valueOf()</code> 메소드를 가지고 있는지 체크합니다.</li> + <li>없으므로 <code>person1</code>의 프로토타입 객체(<code>Person()</code> 생성자의 프로토타입)에 <code>valueOf()</code> 메소드가 있는지 체크합니다.</li> + <li>여전히 없으므로 <code>Person()</code> 생성자의 프로토타입 객체의 프로토타입 객체(<code>Object()</code> 생성자의 프로토타입)가 <code>valueOf()</code> 메소드를 가지고 있는지 체크합니다. 여기에 있으니 호출하며 끝납니다!</li> +</ul> + +<div class="note"> +<p><strong>Note</strong>: 프로토타입 체인에서 한 객체의 메소드와 속성들이 다른 객체로 <strong>복사되는 것이 아님</strong>을 재차 언급합니다. — 위에서 보시다 시피 체인을 타고 올라가며 접근할 뿐입니다.</p> +</div> + +<div class="note"> +<p><strong>Note</strong>: 특정 객체의 프로토타입 객체에 바로 접근하는 공식적인 방법은 없습니다. — Javascript 언어 표준 스펙에서<code>[[prototype]]</code>으로 표현되는 프로토타입 객체에 대한 "링크"는 내부 속성으로 정의되어 있습니다. ({{glossary("ECMAScript")}} 참조). 하지만 많은 수의 모던 브라우저들이 <code><a href="/ko/docs/Web/JavaScript/Reference/Global_Objects/Object/proto">__proto__</a></code> (앞뒤로 언더바 2개씩) 속성을 통해 특정 객체의 프로토타입 객체에 접근할 수 있도록 구현하였습니다. 예를 들자면 <code>person1.__proto__</code> 또는 <code>person1.__proto__.__proto__</code> 코드로 체인이 어떻게 구성되어 있는지 확인해 보세요!</p> + +<p>ECMAScript 2015부터는 <code>Object.getPrototypeOf(obj)</code> 함수를 통해 객체의 프로토타입 객체에 <strong>바로 접근할 수 있게</strong> 되었습니다..</p> +</div> + +<h2 id="프로토타입_속성_상속_받은_멤버들이_정의된_곳">프로토타입 속성: 상속 받은 멤버들이 정의된 곳</h2> + +<p>그럼 상속 받은 속성과 메소드들은 어디에 정의되어 있을까요? <code><a href="/ko/docs/Web/JavaScript/Reference/Global_Objects/Object">Object</a></code> 레퍼런스 페이지에 가시면 좌측에 수 많은 속성과 메소드들이 나열되어 있는 것을 볼 수 있습니다. — 위 스크린샷에서 person1가 상속받은 멤버들보다 훨씬 많죠. 일부는 상속 되었지만 나머지는 아닙니다. — 왜일까요?</p> + +<p>정답은 상속 받는 멤버들은 <code>prototype</code> 속성(sub-namespace라고도 하죠)에 정의되어 있기 때문입니다. — <code>Object.</code>로 시작하는게 아니라, <code>Object.prototype.</code>로 시작하는 것들이죠. <code>prototype</code> 속성도 하나의 객체이며 프로토타입 체인을 통해 상속하고자 하는 속성과 메소드를 담아두는 버킷으로 주로 사용되는 객체입니다.</p> + +<p>So <code><a href="/ko/docs/Web/JavaScript/Reference/Global_Objects/Object/watch">Object.prototype.watch()</a></code>, <code><a href="/ko/docs/Web/JavaScript/Reference/Global_Objects/Object/valueOf">Object.prototype.valueOf()</a></code>등등은, 생성자를 통해 새로 생성되는 인스턴스는 물론 <code>Object.prototype</code>을 상속 받는 객체라면 어떤 객체에서든지 접근할 수 있습니다.</p> + +<p><code><a href="/ko/docs/Web/JavaScript/Reference/Global_Objects/Object/is">Object.is()</a></code>, <code><a href="/ko/docs/Web/JavaScript/Reference/Global_Objects/Object/keys">Object.keys()</a></code>등 <code>prototype</code> 버킷에 정의되지 않은 멤버들은 상속되지 않습니다. 이 것들은 <code>Object()</code> 생성자에서만 사용할 수 있는 멤버들이죠.</p> + +<div class="note"> +<p><strong>Note</strong>: 척 보기엔 이상합니다. — 함수에 불과한 생성자에 멤버를 정의한다니요? 함수 역시 객체의 하나입니다 — 못 미더우시면 <code><a href="/ko/docs/Web/JavaScript/Reference/Global_Objects/Function">Function()</a></code> 생성자 레퍼런스 페이지를 확인해 보세요.</p> +</div> + +<ol> + <li>prototype 속성을 직접 확인해 볼 수 있습니다. — 예제로 돌아가서 Javascript console에 아래 코드를 타이핑 해 보세요: + <pre class="brush: js">Person.prototype</pre> + </li> + <li>출력되는 것이 별로 많지 않을 겁니다 — 아직 이 커스텀 생성자 프로토타입에 아무것도 정의하지 않았거든요! 기본적으로 생성자의 프로토타입은 비어있습니다. 이번에는 아래 코드를 실행해 봅시다: + <pre class="brush: js">Object.prototype</pre> + </li> +</ol> + +<p>위의 예제에서 확인했듯이 <code>Object</code>를 상속받은 객체에서 사용 가능한 수 많은 메소드들이 <code>Object</code>의 <code>prototype</code> 속성에 정의되어 있음을 알 수 있습니다.</p> + +<p>Javascript 전반에 걸쳐 프로토타입 체인 상속이 어떻게 구성되어 있는지 확인할 수 있습니다 — 전역 객체인 <code><a href="/ko/docs/Web/JavaScript/Reference/Global_Objects/String">String</a></code>, <code><a href="/ko/docs/Web/JavaScript/Reference/Global_Objects/Date">Date</a></code>, <code><a href="/ko/docs/Web/JavaScript/Reference/Global_Objects/Number">Number</a></code>, <code><a href="/ko/docs/Web/JavaScript/Reference/Global_Objects/Array">Array</a></code>의 프로토타입에 정의된 메소드와 속성들을 체크해 보세요. 이 프로토타입 객체들에는 이미 많은 수의 메소드가 정의되어 있으며 이는 아래처럼 문자열 객체를 생성 했을 때:</p> + +<pre class="brush: js">var myString = 'This is my string.';</pre> + +<p><code>myString</code> 인스턴스가 생성되는 즉시 <code><a href="/ko/docs/Web/JavaScript/Reference/Global_Objects/String/split">split()</a></code>, <code><a href="/ko/docs/Web/JavaScript/Reference/Global_Objects/String/indexOf">indexOf()</a></code>, <code><a href="/ko/docs/Web/JavaScript/Reference/Global_Objects/String/replace">replace()</a></code>등의 문자열을 위한 유용한 메소드들을 사용할 수 있는 이유입니다.</p> + +<div class="warning"> +<p><strong>Important</strong>: <code>prototype</code> 속성은 Javascript에서 가장 헷갈리는 명칭중 하나입니다. — 보통 <code>this</code>가 현재 객체의 프로토타입 객체를 가리킬 것이라 오해하지만 그렇지 않죠. (프로토타입 객체는 <code>__proto__</code> 속성으로 접근 가능한 내장 객체인 것 기억 하시나요?). 대신에 <code>prototyp</code>e 속성은 상속 시키려는 멤버들이 정의된 객체를 가리킵니다.</p> +</div> + +<h2 id="create()_다시보기">create() 다시보기</h2> + +<p>이전에 새 인스턴스를 생성하기 위해서 <code>Object.create()</code> 메소드를 사용하는 법을 알아 보았습니다.</p> + +<ol> + <li>예를 들어서 이전 예제에서 아래 코드를 Javascript console에서 실행했었다면: + <pre class="brush: js">var person2 = Object.create(person1);</pre> + </li> + <li><code>create()</code> 메소드가 실제로 하는 일은 주어진 객체를 프로토타입 객체로 삼아 새로운 객체를 생성합니다. 여기서 person2는 person1을 프로토타입 객체로 삼습니다. 아래 코드를 실행하여 이를 확인할 수 있습니다: + <pre class="brush: js">person2.__proto__</pre> + </li> +</ol> + +<p>콘솔 상에는 <font face="consolas, Liberation Mono, courier, monospace"><span style="background-color: rgba(220, 220, 220, 0.5);">person1</span></font>이 출력됩니다.</p> + +<h2 id="생성자_속성">생성자 속성</h2> + +<p>모든 생성자 함수는 <code><a href="/ko/docs/Web/JavaScript/Reference/Global_Objects/Object/constructor">constructor</a></code> 속성을 지닌 객체를 프로토타입 객체로 가지고 있습니다. 이 <code>constructor</code> 속성은 원본 생성자 함수 자신을 가리키고 있습니다. 다음 장에서 볼 수 있듯이 <code>Person.prototype</code> 속성(또는 위 절에서 언급된 아무 생성자 함수의 prototype 속성)에 정의된 속성들은 <code>Person()</code> 생성자로 생성된 모든 인스턴스에서 사용할 수 있습니다. 그러므로 person1과 person2에서도 constructor 속성에 접근할 수 있습니다.</p> + +<ol> + <li>예를 들어 아래 코드를 콘솔에서 실행해 보세요: + <pre class="brush: js">person1.constructor +person2.constructor</pre> + + <p>두 구문 모두 <code>Person()</code> 생성자 함수를 반환할 것입니다.</p> + + <p><code>constructor</code> 속성에 괄호를 붙이고 실행하여(인자가 필요하면 전달하구요) 새 인스턴스를 생성하는 트릭이 있습니다. 어쨌든 생성자도 함수의 일종이므로 괄호를 붙이면 실행할 수 있습니다; new 키워드를 통해 실행하면 함수를 인스턴스를 생성하기 위한 생성자로 사용할 수 있죠.</p> + </li> + <li>아래 코드를 실행해 보세요: + <pre class="brush: js">var person3 = new person1.constructor('Karen', 'Stephenson', 26, 'female', ['playing drums', 'mountain climbing']);</pre> + </li> + <li>새로 생성된 객체를 테스트 해보세요, 아래처럼요: + <pre class="brush: js">person3.name.first +person3.age +person3.bio()</pre> + </li> +</ol> + +<p>잘 동작함을 알 수 있습니다. 이런 방식을 자주 사용할 필요는 없지만 실행 도중 명시적인 생성자 함수를 예측할 수 없는 상황에서 인스턴스를 생성해야 하거나 하는 경우 유용하게 사용할 수 있는 방법입니다.</p> + +<p><code><a href="/ko/docs/Web/JavaScript/Reference/Global_Objects/Object/constructor">constructor</a></code> 속성은 여러 사용법이 있습니다. 예를 들어 인스턴스의 생성자 이름이 필요한 경우 아래의 코드로 알아낼 수 있습니다:</p> + +<pre class="brush: js">instanceName.constructor.name</pre> + +<p>아래 코드도 시험해 보세요:</p> + +<pre class="brush: js">person1.constructor.name +</pre> + +<div class="note"> +<p><strong>Note</strong>: <code>constructor.name</code> 는 변경이 가능하므로(상속이나 바인딩, 전처리, 트랜스파일러 등에 의해) 복잡한 로직에 적용하기 위해서는 <code><a href="/ko/docs/Web/JavaScript/Reference/Operators/instanceof">instanceof</a></code> 연산자를 사용하세요.</p> +</div> + +<ol> +</ol> + +<h2 id="프로토타입_수정하기">프로토타입 수정하기</h2> + +<p><code><font face="Open Sans, arial, x-locale-body, sans-serif"><span style="background-color: #ffffff;">생성자의 </span></font>prototype</code> 속성을 수정하는 법에 대해 알아봅시다(프로토타입에 메소드를 추가하면 해당 생성자로 생성된 모든 객체에서 사용 가능합니다).</p> + +<ol> + <li><a href="http://mdn.github.io/learning-area/javascript/oojs/introduction/oojs-class-further-exercises.html">oojs-class-further-exercises.html</a> 예제로 돌아가서 <a href="https://github.com/mdn/learning-area/blob/master/javascript/oojs/introduction/oojs-class-further-exercises.html">source code</a>를 다운 받으세요. 기존 코드에 아래 샘플 코드를 추가하여 <code>prototype</code> 속성에 새 메소드를 추가하세요: + + <pre class="brush: js">Person.prototype.farewell = function() { + alert(this.name.first + ' has left the building. Bye for now!'); +};</pre> + </li> + <li>저장한 코드를 브라우저로 실행하고 콘솔에서 아래 코드를 실행해 보세요. + <pre class="brush: js">person1.farewell();</pre> + </li> +</ol> + +<p>생성자에서 지정했던 person의 name이 alert 창으로 출력되는 것을 확인할 수 있습니다. 매우 유용한 기능이지만 중요한 점은 prototype에 새 메소드를 추가하는 순간 동일한 생성자로 생성된 모든 객체에서 추가된 메소드를 바로 사용할 수 있다는 점입니다.</p> + +<p>잠시 정리해 봅시다. 예제에서는 생성자를 정의하고, 객체를 생성하였으며, 그 이후에 프로토타입에 새 메소드를 추가하였습니다:</p> + +<pre class="brush: js">function Person(first, last, age, gender, interests) { + + // 속성과 메소드 정의 + +} + +var person1 = new Person('Tammi', 'Smith', 32, 'neutral', ['music', 'skiing', 'kickboxing']); + +Person.prototype.farewell = function() { + alert(this.name.first + ' has left the building. Bye for now!'); +};</pre> + +<p>그런데도 person1에서 바로 farewell() 메소드를 사용할 수 있습니다 - 자동으로 업데이트 되기 때문이죠(역주:원문은 이런 뉘앙스입니다만 실제로는 프로토타입 객체는 모든 인스턴스에서 공유하기 때문에 정의하는 즉시 별도의 갱신 과정 없이 접근이 가능합니다).</p> + +<div class="note"> +<p><strong>Note</strong>: 코드가 잘 동작하지 않는다면 <a href="https://github.com/mdn/learning-area/blob/master/javascript/oojs/advanced/oojs-class-prototype.html">oojs-class-prototype.html</a> 코드를 참조하세요 (<a href="http://mdn.github.io/learning-area/javascript/oojs/advanced/oojs-class-prototype.html">running live</a> 페이지도 보시구요).</p> +</div> + +<p>prototype에 속성을 정의하는 경우는 별로 본 적이 없을겁니다. 왜냐면 별로 좋은 방법이 아니거든요. 속성을 추가할 때 아래와 같이 할 수 있습니다:</p> + +<pre class="brush: js">Person.prototype.fullName = 'Bob Smith';</pre> + +<p>사람들이 항상 밥 스미스로 부르지 않을 수 있으니 별로 좋은 방법 같지는 않아 보입니다. <code>fullname</code>을 <code>name.first</code>와 <code>name.last</code>로 나누어 보죠:</p> + +<pre class="brush: js">Person.prototype.fullName = this.name.first + ' ' + this.name.last;</pre> + +<p>이 경우 <code>this</code>는 함수 범위가 아닌 전역 범위를 가리키므로 코드가 의도대로 동작하지 않습니다. 이대로 실행해도 <code>undefined undefined</code>만 볼 수 있죠. 윗 절에서 프로토타입에 정의한 메소드 내에서는 정상적으로 동작하는데 이는 코드가 함수 범위 내에 있으며 객체의 멤버 함수로써 동작하기에 객체 범위로 전환되었기 때문입니다. 따라서 프로토타입에 상수(한 번 할당하면 변하지 않는 값)를 정의하는 것은 가능하지만 일반적으로 생성자에서 정의하는 것이 낫습니다.</p> + +<p>사실 일반적인 방식으로는 속성은 생성자에서, 메소드는 프로토타입에서 정의합니다. 생성자에는 속성에 대한 정의만 있으며 메소드는 별도의 블럭으로 구분할 수 있으니 코드를 읽기가 훨씬 쉬워집니다. 아래처럼요:</p> + +<pre class="brush: js">// 생성자에서 속성 정의 + +function Test(a, b, c, d) { + // 속성 정의 +} + +// 첫 메소드 정의 + +Test.prototype.x = function() { ... }; + +// 두번째 메소드 정의 + +Test.prototype.y = function() { ... }; + +// 그 외.</pre> + +<p>이런 패턴은 Piotr Zalewa의 <a href="https://github.com/zalun/school-plan-app/blob/master/stage9/js/index.js">school plan app</a> 예제 코드에서 볼 수 있습니다.</p> + +<h2 id="요약">요약</h2> + +<p>이 글에서는 객체 프로토타입에 대한 설명과 프로토타입 체인을 통해 다른 객체를 상속하는 방법, 프로토타입 속성과 생성자에 새 메소드를 추가하는 방법과 그와 관련된 지식을 다루고 있습니다.</p> + +<p>다음 글에서는 직접 만든 객체간의 상속을 구현하는 방법에 대해 알아봅시다.</p> + +<p>{{PreviousMenuNext("Learn/JavaScript/Objects/Object-oriented_JS", "Learn/JavaScript/Objects/Inheritance", "Learn/JavaScript/Objects")}}</p> + +<p> </p> + +<h2 id="In_this_module">In this module</h2> + +<ul> + <li><a href="/en-US/docs/Learn/JavaScript/Objects/Basics">Object basics</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Objects/Object-oriented_JS">Object-oriented JavaScript for beginners</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Objects/Object_prototypes">Object prototypes</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Objects/Inheritance">Inheritance in JavaScript</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Objects/JSON">Working with JSON data</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Objects/Object_building_practice">Object building practice</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Objects/Adding_bouncing_balls_features">Adding features to our bouncing balls demo</a></li> +</ul> + +<p> </p> |