From e75d473fae9bdf2cff7c824f58ef69759c066e4a Mon Sep 17 00:00:00 2001 From: Heejay Kong Date: Mon, 28 Oct 2024 01:15:49 +0900 Subject: [PATCH 1/3] Update chapter_10.md --- .../chapter_10.md" | 114 ++++++++++++++++++ 1 file changed, 114 insertions(+) diff --git "a/book/\352\263\265\355\235\254\354\236\254/chapter_10.md" "b/book/\352\263\265\355\235\254\354\236\254/chapter_10.md" index 6acfd54..3d632ba 100644 --- "a/book/\352\263\265\355\235\254\354\236\254/chapter_10.md" +++ "b/book/\352\263\265\355\235\254\354\236\254/chapter_10.md" @@ -1 +1,115 @@ # Chapter 10 - 객체 리터럴 + +## 1. Object: 객체란? +자바스크립트에서 원시 값을 제외한 나머지 값(**함수, 배열, 정규 표현식** 등)은 **모두** 객체입니다. + +**객체 타입(Object/Reference Type)** 이란? +* 객체 타입은 원시 값 또는 다른 객체를 하나의 단위로 구성한 **복합적인 자료구조**입니다. +* 객체 타입의 값은 변경 가능한 값(**mutable value**)입니다. 이 특징은 변경 불가능한 값을 지닌다는 원시 타입의 특징과 대비됩니다. (11장 '원시 값과 객체의 비교'에서 자세히 볼 예정) + +그래서 **객체**란? +* 자바스크립트의 객체는 0개 이상의 **1. 프로퍼티** 또는 **2. 메서드**로 구성된 집합체입니다. + 1. **프로퍼티**는 객체의 **상태**를 나타내는 값이며, key와 value로 구성합니다. + 2. **메서드**는 객체 내 **프로퍼티 값으로 사용하는 함수**를 뜻하며, _(그렇습니다. 자바스크립트에선 무엇이든 객체의 프로퍼티 값이 될 수 있으며, 함수도 예외가 아닙니다.)_ 프로퍼티를 참조하거나 조작하는 동작(behavior)을 수행합니다. + + + + +_이미지 출처: https://blog.vietnamlife.info/%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8%EC%9D%98-object-keys-%EC%99%80-values-%EB%A5%BC-%EC%98%88%EC%A0%9C%EC%99%80-%ED%95%A8%EA%BB%98-%EC%89%BD%EA%B2%8C-%EB%B0%B0%EC%9B%8C%EB%B3%B4/_ +

+ +객체가 무엇인지 알아봤으니, 이제 객체를 어떻게 생성하는지 알아봅시다. + + +## 2. 객체 리터럴에 의한 객체 생성 +자바스크립트는 C++나 자바 같은 클래스 기반 객체지향 언어와는 다르게, 객체를 생성할 때 반드시 클래스를 사전에 정의하거나 new 연산자로 생성자를 호출할 필요는 없습니다. + +대신 자바스크립트는 **프로토타입 기반 객체지향 언어**이기 때문에, 다음처럼 다양한 객체 생성 방법을 지원합니다. +* 객체 리터럴 +* Object 생성자 함수 +* 생성자 함수 +* Object.create 메서드 +* 클래스(ES6) + +이 중에서 가장 일반적인 방법은 **객체 리터럴** 입니다.
+객체 리터럴은 아래처럼 중괄호`{...}` 내에 0개 이상의 프로퍼티를 정의하며 객체를 생성하는 표기법입니다. +```javascript +const person = { + name: 'Kong', + sayHello: function () { + console.log(`Hello! My name is ${this.name}`); + } +}; +console.log(typeof person); // object +console.log(person); // {name: "Kong", sayHello: f} +person.sayHello(); // Hello! My name is Kong +``` +참고: 우리가 객체 리터럴로 객체를 표기하면, 자바스크립트 엔진은 변수에 할당되는 시점에 객체 리터럴을 해석해 우리의 객체를 생성해 줍니다. +

+ +객체 리터럴은 자바스크립트의 **유연함과 강력함을 대표**하는 객체 생성 방식입니다. 마치 숫자나 문자열을 만드는 것처럼 리터럴로 간편하게 객체를 생성할 수 있을 뿐더러, 객체 리터럴에 프로퍼티를 포함해 객체를 생성함과 동시에 프로퍼티를 만들거나, **객체 생성 이후 프로퍼티를 동적으로 추가**할 수도 있습니다. + +지금까지 객체를 생성하는 가장 일반적인 객체 리터럴 방식을 알아 보았습니다. 나머지 객체 생성 방식은 12장 '함수'에서 알아보는 것으로 하고, 이제는 프로퍼티를 자세히 살펴봅시다. + + +## 3. 프로퍼티 +앞서 말했듯, 자바스크립트의 객체는 프로퍼티의 집합이며, 프로퍼티는 key와 value로 이루어집니다. + + + +프로퍼티는 각각 쉼표(`,`)로 구분하며, key와 value는 각각 다음과 같은 특징이 있습니다. +* **프로퍼티 key의 특징:** + 1. 프로퍼티 key로 사용할 수 있는 값은 **문자열** 또는 심벌 값입니다. 일반적으로 문자열을 이용합니다. + 2. 프로퍼티 key는 프로퍼티 value에 접근하는 식별자로서 기능하기 때문에, **식별자 네이밍 규칙을 사용하는 것을 권장**합니다. (식별자 네이밍 규칙을 따르지 않으면 반드시 따옴표를 붙여야 하는 등 번거롭기 때문) + * e.g., + ```javascript + const person = { + firstName: 'Ung-mo', // 식별자 네이밍 규칙을 준수하는 프로퍼티 키 + 'last-name': 'Lee' // 식별자 네이밍 규칙을 준수하지 않는 프로퍼티 키 + }; + console.log(person); // {firstName: "Ung-mo", last-name: "Lee"} + + // 따옴표를 붙이지 않으면 SyntaxError가 발생한다. + const person = { + firstName: 'Ung-mo', + last-name: 'Lee' // SyntaxError: Unexpected token - + }; + ``` + 3. 문자열 또는 문자열로 평가되는 표현식을 사용해 **동적으로 프로퍼티 key를 생성**할 수도 있습니다. 이 경우엔 표현식을 대괄호`[]`로 묶어야 합니다. + * e.g., + ```javascript + const obj = {}; + const key = 'hello'; + + // ES5: 프로퍼티 키 동적 생성 + obj[key] = 'world'; + // ES6: 계산된 프로퍼티 이름 + // const obj = { [key]: 'world' }; + + console.log(obj); // {hello: "world"} + ``` + 4. 프로퍼티 key에 문자열이나 심벌 값 외의 값을 사용하면 **암묵적 타입 변환**을 통해 문자열이 됩니다. + * e.g., + ```javascript + var foo = { + 0: 1, + 1: 2, + 2: 3 + }; + + console.log(foo); // {0: 1, 1: 2, 2: 3} + ``` + 5. 이미 존재하는 프로퍼티 key를 중복 선언하면 나중에 선언한 프로퍼티가 **먼저 선언한 프로퍼티를 덮어쓰며**, 이때 에러가 발생하지 않는다는 점을 주의해야 합니다. + * e.g., + ```javascript + var foo = { + name: 'Lee', + name: 'Kim' + }; + + console.log(foo); // {name: "Kim"} + ``` + + +* **프로퍼티 value의 특징:** + 1. 프로퍼티 value로 사용할 수 있는 값은 자바스크립트에서 사용할 수 있는 **모든 값**입니다. From 8e88f14993dbe01cdedab40b9ba7d14a586171ee Mon Sep 17 00:00:00 2001 From: wooy0ng Date: Mon, 28 Oct 2024 21:54:57 +0900 Subject: [PATCH 2/3] Create chapter_10.md --- .../chapter_10.md" | 291 ++++++++++++++++++ 1 file changed, 291 insertions(+) create mode 100644 "book/\354\235\264\354\232\251\354\232\260/chapter_10.md" diff --git "a/book/\354\235\264\354\232\251\354\232\260/chapter_10.md" "b/book/\354\235\264\354\232\251\354\232\260/chapter_10.md" new file mode 100644 index 0000000..2d4b169 --- /dev/null +++ "b/book/\354\235\264\354\232\251\354\232\260/chapter_10.md" @@ -0,0 +1,291 @@ +# Chapter 10 - 객체 리터럴 + +### 객체 +자바스크립트를 구성하는 거의 모든 것은 객체입니다. +원시 값을 제외한 나머지 값(함수, 배열, 정규 표현식 등)은 모두 객체입니다. + +객체 타입(object/reference type)은 다양한 타입의 값(원시 값 또는 다른 객체)을 하나의 단위로 구성한 자료구조입니다. +또한 원시 값은 변경 불가능한 값(immutable value)이지만 객체는 변경 가능한 값(mutable value)입니다. + +객체는 0개 이상의 프로퍼티로 구성된 집합이며, +프로퍼티는 key와 value로 구성됩니다. + +``` js +let person = { + name: 'Lee', + age: 27 +}; +``` + +자바스크립트에서 사용할 수 있는 모든 값은 프로퍼티 값이 될 수 있습니다. +따라서 함수도 프로퍼티 값으로 사용할 수 있습니다. 프로퍼티 값이 함수일 경우, 일반 함수와 구분하기 위해 메소드(method)라 부릅니다. + +``` js +let counter = { + num: 0, + increase: function (){ + this.num++; + } +}; +``` + +객체는 객체의 상태를 나타내느 값(프로퍼티)와 프로퍼티를 참조하고 조작할 수 있는 메소드를 모두 포함할 수 있기 때문에 +상태와 동작을 하나의 단위로 구조화할 수 있습니다. + +

+ +### 객체 리터럴에 의한 객체 생성 +C++나 자바와 같이 클래스 기반 객체지향 언어는 클래스를 사전에 정의하고 +필요한 시점에 `new` 연산자와 함께 생성자(Constructor)를 호출하여 +인스턴스를 생성하는 방식으로 객체를 생성합니다. + +자바스크립트는 프로토타입 기반 객체지향 언어로써 클래스 기반 객체지향 언어와는 달리 +**다양한 객체 생성 방법을 지원합니다.** + +- 객체 리터럴 +- `Object` 생성자 함수 +- 생성자 함수 +- `Object`, `create` 메소드 +- 클래스(ES6) + + +
+ +일반적으로 사용하는 방법은 '객체 리터럴'을 사용하는 자바스크립트의 유연함을 대표하는 방식입니다. +객체 리터럴은 중괄호(`{...}`) 내에 0개 이상의 프로퍼티를 정의하는 방식입니다. + +``` js +let person = { + name: 'Lee', + printHello: function () { + console.log(`Hello! My name is ${this.name}.`); + } +}; +``` +> 객체 리터럴은 코드 블록을 의미하지 않는다는 것에 주의하도록 합시다. (세미콜론을 붙이도록 하자) + + +

+ +### 프로퍼티 +객체는 프로퍼티의 집합이며, 프로퍼티는 key와 value로 구성됩니다. + +``` js +let person = { + name: 'Lee', + age: 27 +}; +``` + +여기서 프로퍼티 키는 문자열이므로 `''`나 `""`로 묶어야 하지만, +식별자 네이밍 규칙을 준수하는 이름의 경우에는 이를 생략할 수 있습니다. + +``` js +let person = { + firstName: 'Hong', // 식별자 네이밍 규칙을 준수하는 프로퍼티 키 + 'last-name': 'Gil Dong' // 식별자 네이밍 규칙을 준수하지 않는 프로퍼티 키 +}; +``` + +> 자바스크립트는 key에 있는 `-` 문구를 연산자가 있는 표현식으로 해석해버린다. + +
+ +문자열 또는 문자열로 평가할 수 있는 표현식을 사용해 프로퍼티 key를 동적으로 생성할 수도 있습니다. +이 경우에는 대괄호(`[...]`)로 묶어주어야 합니다. +``` js +let obj = {}; +let key = 'hello'; + +obj[key] = 'world'; +console.log(obj); // {hello: 'world'} +``` + +
+ +이미 존재하는 key를 중복으로 선언하면 나중에 선언한 프로퍼티가 먼저 선언한 프로퍼티 키를 덮어씁니다. +때문에 에러가 발생하지 않으니 이를 주의해야 합니다. + +``` js +let sample = { + alphabet: 'A', + alphabet: 'B' +}; + +console.log(sample); // {alphabet: "B"} +``` + +

+ +### 메소드 + +프로퍼티 값이 함수일 경우 일반 함수와 구분하기 위해 메소드(method)라고 부릅니다. +객체에 묶여 있는 함수를 지칭하는 말입니다. + +``` js +let person = { + name: 'Lee', + printHello: function () { + console.log(`Hello! My name is ${this.name}.`); + } +}; +``` + +메소드 내부에서 사용한 `this` 키워드는 객체 자신을 참조하는 참조 변수입니다. + + +

+ +### 프로퍼티 접근 +프로퍼티에 접근하는 방법은 아래와 같이 2가지입니다. +- 마침표 표기법(dot notation) +- 대괄호 표기법(bracket notation) + +``` js +let person = { + name: 'Lee', + printHello: function () { + console.log(`Hello! My name is ${this.name}.`); + } +}; + +console.log(person.name); // 'Lee' (마침표 표기법) +console.log(person['name']); // 'Lee' (대괄호 표기법) +``` + +

+ +### 프로퍼티 값 갱신 +이미 존재하는 프로퍼티에 값을 할당하면 프로퍼티 값이 갱신(update)됩니다. + +``` js +let person = { + name: 'Lee' +}; + +person.name = 'Kim'; +console.log(person); // {name: "Kim"} +``` + +

+ +### 프로퍼티 동적 생성 +존재하지 않는 프로퍼티에 값을 할당하면 동적으로 프로퍼티가 생성되고 프로퍼티 값이 할당됩니다. + +``` js +let person = { + name: 'Lee' +}; + +person.age = 27; +console.log(person); // {name: "Lee", age: 27} +``` + + +

+ +### 프로퍼티 삭제 +`delete` 연산자는 객체의 프로퍼티를 삭제합니다. +이때 `delete` 연산자의 피연산자는 프로퍼티 값에 접근할 수 있는 표현식이어야 합니다. +존재하지 않는 프로퍼티를 삭제하면 아무 에러가 발생하지 않으며, 무시됩니다. + +``` js +let person = { + name: 'Lee' +}; + +person.age = 27; +delete person.age; // age 프로퍼티를 삭제 +``` + +

+ +### 객체 리터럴 확장 기능 (ES6) +ES6에서는 간편하고 표현력 있는 객체 리터럴의 확장 기능을 제공합니다. + +
+ +#### 프로퍼티 축약 표현 +ES6에서는 프로퍼티의 value로 변수를 사용하는 경우, +변수 이름과 프로퍼티 key가 동일한 이름일 때 프로퍼티 key를 생략할 수 있습니다. +이때 프로퍼티 키는 변수 이름으로 자동 생성됩니다. + +``` js +let x = 1, y = 2; + +// 프로퍼티 축약 표현 +const obj = { x, y }; +console.log(obj); // {x: 1, y: 2} +``` + +
+ +#### 계산된 프로퍼티 이름 (Computed property name) +표현식을 사용해 프로퍼티 key를 동적으로 생성할 수 있습니다. +이 방식을 사용하려면 대괄호로 묶어 사용해야 합니다. + +ES5에서는 아래와 같이 사용되었습니다. +``` js +let prefix = 'prop'; +let i = 0; + +let obj = {}; + +// 프로퍼티 키를 동적으로 생성 +obj[perfix + '-' + ++i] = i; +obj[perfix + '-' + ++i] = i; +obj[perfix + '-' + ++i] = i; + +console.log(obj); // {prop-1: 1, prop-2: 2, prop-3: 3} +``` + +
+ +ES6에서는 객체 리터럴 내부에서도 프로퍼티 키를 동적으로 생성할 수 있습니다. + +``` js +let prefix = 'prop'; +let i = 0; + +// 객체 리터럴 내부에서 프로퍼티 키를 동적으로 생성 +const obj = { + [`${prefix}-${++i}`]: i, + [`${prefix}-${++i}`]: i, + [`${prefix}-${++i}`]: i +}; + +console.log(obj); // {prop-1: 1, prop-2: 2, prop-3: 3} +``` + + +

+ +#### 메소드 축약 표현 +ES5에서 객체의 메소드를 선언하려면 프로피터 value로 함수를 할당해야 합니다. + +``` js +let person = { + name: 'Lee', + printHello: function () { + console.log('Hello ' + this.name); + } +}; + +person.printHello(); // "Hello Lee" +``` + +ES6에서는 메소드를 정의할 때 `function` 키워드를 생략한 축약 표현을 사용할 수 있습니다. + +``` js +let person = { + name: 'Lee', + printHello() { + console.log('Hello ' + this.name); + } +}; + +person.printHello(); // "Hello Lee" +``` + +단, 메소드 축약 표현으로 정의한 메소드는 프로퍼티에 할당한 함수와는 다르게 동작합니다. +이에 대해서는 26절에서 자세히 다룹니다. \ No newline at end of file From 6a83b0199fa1d84952f57e89993f85dda7976966 Mon Sep 17 00:00:00 2001 From: YongWoo Lee Date: Mon, 28 Oct 2024 21:55:53 +0900 Subject: [PATCH 3/3] =?UTF-8?q?chapter=2004,=20chapter=2005=20=EC=97=85?= =?UTF-8?q?=EB=A1=9C=EB=93=9C=20(#1)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: chapter_04, chapter_05 업로드 * feat: _toc.yml에 chapter_04, chapter_05 섹션 추가 * chapter_05.md 오타 수정 --- book/_toc.yml | 1 + book/docs/chapter_04.md | 232 +++++++++++++++++- book/docs/chapter_05.md | 224 +++++++++++++++++ .../chapter_05.md" | 2 +- 4 files changed, 457 insertions(+), 2 deletions(-) create mode 100644 book/docs/chapter_05.md diff --git a/book/_toc.yml b/book/_toc.yml index 411e30c..af489b5 100644 --- a/book/_toc.yml +++ b/book/_toc.yml @@ -8,6 +8,7 @@ parts: - caption: Chapters chapters: - file: docs/chapter_04 + - file: docs/chapter_05 - caption: 개인 공간 chapters: - file: 공희재/main diff --git a/book/docs/chapter_04.md b/book/docs/chapter_04.md index cf1a25a..b8af82d 100644 --- a/book/docs/chapter_04.md +++ b/book/docs/chapter_04.md @@ -1 +1,231 @@ -# Chapter 04 - 변수 \ No newline at end of file +# Chapter 04 - 변수 +### 개요 +``` js +10 + 20 +``` + +변수는 프로그래밍 언어에서 데이터를 관리하기 위한 핵심 개념입니다. +위와 같은 계산식이 자바스크립트에서는 어떻게 동작하는지 알아보도록 합시다. + +자바스크립트의 실행 방식은 사람이 변수를 바라보는 시각과 비슷합니다. +자바스크립트 엔진이 위 수식을 계산(평가: evaluation)하려면 +먼저 `10`, `20`, `+`라는 기호(리터럴과 연산자)의 의미를 알고 있어야 하며, +`10 + 20`이라는 식(표현식)의 의미도 해석(파싱)할 수 있어야 합니다. + +자바스크립트가 `10 + 20` 이라는 식의 의미를 해석하면 +먼저 `+` 연산자의 좌변과 우변의 숫자 값, 즉 피연산자(operand)를 기억합니다. + +메모리는 데이터를 저장할 수 있는 메모리 셀(memory cell)의 집합체입니다. +메모리 셀 하나의 크기는 1 byte이며, +컴퓨터는 메모리 셀의 크기인 1 byte 단위로 데이터를 저장하거나 읽어들입니다. + + + +위 예제의 숫자 값 10과 20은 메모리 상의 임의의 메모리 주소에 저장되고 +CPU는 이 값을 읽어들여 연산을 수행합니다. +연산 결과 또한 임의의 위치에 저장됩니다. + + +변수는 하나의 값을 저장하기 위해 확보한 메모리 공간 자체, +또는 그 메모리 공간을 식별하기 위해 붙인 이름을 의미합니다. + +메모리 공간 내의 특정 위치에 저장, 저장된 값을 참조하는 매커니즘으로 +값의 위치를 가리키는 상징적인 이름을 의미합니다. + +변수는 프로그래밍 언어의 컴파일러, +혹은 인터프리터에 의해 값이 저장된 메모리 공간의 주소로 치환되어 실행됩니다. +따라서 개발자는 직접 메모리 주소에 직접 접근할 필요 없이 +변수를 통해 안전하게 값에 접근할 수 있습니다. + +

+ +### 식별자 +**변수 이름은 식별자(identifier)라고 부릅니다.** +식별자는 어떤 값을 구별해서 식별할 수 있는 고유한 이름을 의미합니다. + +값은 메모리 공간에 저장되어 있기 때문에. +식별자는 메모리 공간에 저장되어 있는 특정 값을 구별해서 식별해낼 수 있어야 합니다. +이를 위해 식별자는 특정 값이 저장되어 있는 메모리 주소를 기억해야 합니다. + +때문에 식별자는 값이 저장되어 있는 메모리 주소와 매핑되어야 하며, +이 매핑 정보를 가지고 있어야 합니다. + +즉, 식별자는 값이 아니라 메모리 주소를 가지고 있습니다. +식별자는 메모리 주소를 통해 메모리 공간에 저장된 값에 접근할 수 있습니다. + +image + +
+ +"식별자"라는 용어는 변수 이름에서만 사용되는 것이 아니라 함수, 클래스 등의 이름을 모두 포함합니다. +**즉, 메모리 상에 존재하는 어떤 값을 식별할 수 있는 이름은 모두 식별자라고 부릅니다.** + +변수, 함수, 클래스 등의 이름과 같은 식별자는 +선언(declaration)에 의해 자바스크립트 엔진에 식별자의 존재를 알립니다. +이제부터 변수 선언 방식에 대해 알아보겠습니다. + +

+ +### 변수 선언 +변수 선언이란, 변수를 생성하는 것을 의미합니다. +값을 저장하기 위한 메모리 공간을 확보하고 +변수 이름과 확보된 메모리 공간의 주소를 연결해서 값을 저장할 수 잇게 준비하는 것을 의미합니다. + +변수를 사용하려면 반드시 선언이 필요합니다. +변수 선언 시에는 `var`, `let`, `const` 키워드를 사용합니다. + +아래 코드를 살펴봅시다. +`var` 키워드는 뒤에 오는 변수 이름으로 새로운 변수를 선언할 것을 지시하는 키워드입니다. + +``` js +var score; +``` + +위 변수 선언문은 다음과 같이 변수 이름을 등록하고 값을 저장할 메모리 공간을 확보합니다. + +image + +아직 변수에 값을 할당하지 않았기 때문에 확보된 메모리 공간은 비어 있을 것이라 생각할 수도 있지만, +확보된 메모리 공간에는 자바스크립트 엔진에 의해 `undefined`라는 값이 암묵적으로 할당되어 초기화됩니다. **이는 자바스크립트만의 특징입니다.** + +정리하자면, 자바스크립트 엔진은 변수 선언을 다음과 같이 2단계에 걸쳐 수행합니다. +- 선언 단계: 변수 이름을 등록해서 변수의 존재를 알립니다. +- 초기화 단계: 값을 저장하기 위한 메모리 공간을 확보하고 암묵적으로 `undefined`를 할당해 초기화합니다. + +> ※ 변수 이름의 등록 위치 +> 변수 이름을 비롯한 모든 식별자는 실행 컨텍스트에 등록됩니다. +> 실행 컨텍스트(execution context)는 자바 스크립트 엔진이 소스코드를 평가하고 +> 실행하기 위해 필요한 환경을 제공하고 코드의 실행 결과를 관리하는 영역입니다. +> 자바 스크립트 엔진은 실행 컨텍스트를 통해 식별자와 스코프를 관리합니다. + + + +

+ +### 변수 선언의 실행 시점과 변수 호이스팅 +``` js +console.log(score); // undefined +var score; +``` +위 코드는 변수 선언문보다 변수를 참조하는 코드가 앞에 있습니다. +자바스크립트 코드는 인터프리터에 의해 한 줄씩 순차적으로 실행되므로 +`console.log(score);`가 먼저 실행되고 다음 줄에 있는 코드를 실행합니다. + +따라서 `console.log(score);`가 실행되는 시점에서는 아직 `score` 변수가 선언되지 않았으므로 +참조 에러가 발생할 것처럼 보이는 코드입니다. +하지만 참조 에러가 발생하지 않고 `undefined`가 출력됩니다. + +자바스크립트 엔진은 소스 코드를 한 줄씩 순차적으로 실행하기에 앞서 +먼저 소스코드의 평가 과정을 거치면서 소스코드를 실행하기 위한 준비를 합니다. + +이때 평가 과정에서 자바스크립트 엔진은 변수 선언을 포함한 +모든 선언문(변수 선언, 함수 선언 등)을 소스코드에서 찾아내 먼저 실행합니다. + +이처럼 자바스크립트 엔진은 변수 선언이 +소스코드의 어디에 있든 상관없이 다른 코드보다 먼저 실행됩니다. + +이는 변수 선언문이 코드의 선두로 끌어 올려진 것처럼 동작하는 +자바스크립트 고유의 특징인 변수 호이스팅이라고 부릅니다. + +> 변수 선언 뿐만 아니라 `var`, `let`, `function`, `function*`, `class` 키워드를 사용해서 +> 선언하는 모든 식별자는 호이스팅 됩니다. + +
+ +**※ Temporal Dead Zone** +Temporal Dead Zone은 자바스크립트에서 let, const, class로 선언된 변수가 +호이스팅에 의해 스코프에 들어간 후 초기화 전 까지 접근할 수 없도록 만들어주는 구간을 의미합니다. + +이 동작은 특정 변수에 참조할 때, 코드 상으로 먼저 초기화 되지 않은 경우에 에러를 발생시킵니다. + +``` js +console.log(score); // ReferenceError: 'score'를 초기화하기 전에 TDZ에 의해 접근할 수 없음 +let score; +``` + + +

+ +### 값의 할당 +변수에 값을 할당할 때는 연산자 `=`을 사용합니다. + +``` js +var score; +score = 80; +``` + +여기서 한가지 알고 가야할 점이 있습니다. +변수 선언은 런타임 이전에 먼저 실행되지만 +값의 할당은 소스코드가 순차적으로 실행되는 시점인 런타임에 실행됩니다. + +아래 코드를 실행하면 이 특징을 바로 확인할 수 있습니다. + +``` js +console.log(score); // undefined + +score = 80; +var score; + +console.log(score); // 80 +``` + + +

+ +### 값의 재할당 +변수에 새로운 값을 재할당 할 수 있습니다. + +``` js +var score = 80; +score = 90; +``` + +여기서는 `var` 키워드로 변수를 선언 및 초기화했기 때문에 재할당이 가능합니다. +만약 값을 재할당 할 수 없어서 저장된 값을 변경할 수 없다면 +변수가 아니라 상수(constant)라고 부릅니다. + +변수에 값을 재할당하면 score 변수에서 이전 값 80이 저장된 메모리 공간에 덮어씌우는 것이 아닌, +새로운 메모리 공간을 확보하고 그 메모리 공간에 숫자 값 90을 저장합니다. + +image + +
+ +식별자에 의해 연결되어 있지 않은 메모리 주소는 더이상 필요하지 않은 것으로 판단하여 +가비지 콜렉터에 의해 메모리에서 자동 해제됩니다. (해제 시점은 알 수 없습니다) + +

+ +### 식별자 네이밍 규칙 +식별자는 아래와 같은 네이밍 규칙을 준수해야 합니다. +- 식별자는 특수문자를 제외한 문자, 숫자, 언더스코어(_), 달러 기호($)를 포함할 수 있다. +- 식별자는 숫자로 시작하는 것을 허용하지 않는다. +- 예약어는 식별자로 사용할 수 없다. + +
+ +#### 네이밍 컨벤션 +네이밍 컨벤션은 하나 이상의 영어 단어로 구성된 식별자를 만들 때 +가독성 좋게 단어를 구분하기 위해 규정한 명명 규칙이다. + +다음과 같은 4가지 유형의 네이밍 컨벤션이 자주 사용됩니다. +- 카멜 케이스(camelCase) +- 스네이크 케이스(snake_case) +- 파스칼 케이스(PascalCase) +- 헝가리언 케이스(typeHungarianCase) + +``` js +// 카멜 케이스 +var firstName; + +// 스네이크 케이스 +var first_name; + +// 파스칼 케이스; +var FirstName; + +// 헝가리언 케이스 +var strFirstName; // type + identifier +var $elem = document.getElementById('myId'); +var observable$ = fromEvent(document, 'click'); +``` \ No newline at end of file diff --git a/book/docs/chapter_05.md b/book/docs/chapter_05.md new file mode 100644 index 0000000..c9ca179 --- /dev/null +++ b/book/docs/chapter_05.md @@ -0,0 +1,224 @@ +# Chapter 05 - 표현식과 문 +### 값 +값(value)은 표현식이 평가되어 생성된 결과를 말합니다. +평가란, 식을 해석해서 값을 생성하거나 참조하는 것을 의미합니다. + +아래 예제의 식은 평가되어 숫자 값 30을 생성합니다. +``` js +10 + 20; // 30 +``` + +
+ +변수는 **하나의 값**을 저장하기 위한 메모리 공간 자체, +혹은 그 메모리를 식별하기 위해 붙인 이름입니다. + +따라서 변수에 할당되는 것은 값입니다. + +``` js +var sum = 10 + 20; +``` + +값은 다양한 방법으로 생성할 수 있습니다. +위 예제처럼 식으로 생성할 수도 있지만, 가장 기본적인 방법은 리터럴을 사용하는 것이다. + +

+ +### 리터럴 +리터럴(literal)은 사람이 이해할 수 있는 문자 혹은 약속된 기호를 사용해 값을 생성하는 표기법입니다. + +``` js +5 +``` + +위 예제의 5는 단순 아라비아 숫자가 아니라 **숫자 리터럴** 입니다. +사람이 이해할 수 있는 아라비아 숫자를 사용해 숫자 리터럴 3을 코드에 기술하면 +자바스크립트 엔진은 이를 평가해 숫자 3을 생성합니다. + +
+ +이처럼 리터럴은 사람이 이해할 수 있는 문자(아라비아 숫자, 알파벳, 한글 등) 또는 +미리 약속된 기호('', "", [] 등)로 표기한 코드입니다. + +자바스크립트 엔진은 실행되는 시점인 런타임에 리터럴을 평가해 값을 생성합니다. +즉, 리터럴은 값을 생성하기 위해 미리 약속한 표기법입니다. + +|리터럴|예시| +|:--|:--| +|정수 리터럴|100| +|부동소수점 리터럴|100.5| +|2진수 리터럴|0b01000001| +|8진수 리터럴|0o101| +|16진수 리터럴|0x1b| +|문자열 리터럴|"hello", 'world'| +|boolean 리터럴|true, false| +|null 리터럴|null| +|undefined 리터럴|undefined| +|객체 리터럴|{name: 'Lee', address: 'Seoul'}| +|배열 리터럴|[1, 2, 3]| +|함수 리터럴|function() {}| +|정규표현식 리터럴|/[A-Z]+/g| + + +

+ +### 표현식 +표현식은 값으로 평가될 수 있는 문(statement)입니다. +즉, 표현식이 평가되면 새로운 값을 생성하거나 값을 참조합니다. + +바로 위에서 살펴본 리터럴은 값으로 평가됩니다. 따라서 리터럴도 표현식입니다. + +``` js +var score = 200; +``` + +위 예제의 `200`은 리터럴입니다. +리터럴 `200`은 자바스크립트 엔진에 의해 평가되어 값을 생성하므로 그 자체로 표현힉입니다. + +
+ +``` js +var score = 100 + 100; +``` + +`100 + 100`은 리터럴과 연산자로 이루어져 있습니다. +하지만 `100 + 100`도 평가되어 숫자 값 `200`을 생성하므로 표현식입니다. + + +
+ +``` js +score; // 200 +``` + +변수 식별자를 참조하면 변수 값으로 평가됩니다. +식별자 참조는 값을 생성하지는 않지만 값으로 평가되므로 표현식입니다. + +즉, 값으로 출력될 수 있는 것은 모두 표현식입니다. + +

+ +### 문 +문(statement)은 프로그램을 구성하는 기본 단위이자 최소 실행 단위입니다. +문의 집합으로 이루어진 것이 바로 프로그램이며, +문을 작성하고 순서에 맞게 나열하는 것이 프로그래밍입니다. + +문은 여러 토큰으로 구분됩니다. +토큰(token)이란, 문법적인 의미를 가지며, +문법적으로 더 이상 나눌 수 없는 코드의 기본 요소를 의미합니다. + +예를 들어, 키워드, 식별자, 연산자, 리터럴, 세미콜론(;)이나 마침표(.) 등의 특수 기호는 +문법적인 의미를 가지며, 문법적으로 더 이상 나눌 수 없는 코드의 기본 요소이므로 모두 토큰입니다. + +image + +이런 특징으로, 문은 명령문이라고도 부릅니다. +문을 실행하게 되면 명령이 실행되고 무슨 일인가 일어나게 됩니다. + +``` js +// 변수 선언문 +var x; + +// 할당문 +x = 5; + +// 함수 선언문 +function foo () {} + +// 조건문 +if (x > 1) { console.log(x) } + +// 반복문 +for (var i = 0; i < 2; i++) { + consoe.log(i); +} +``` + + +

+ +### 세미콜론과 세미콜론 자동 삽입 기능 +세미콜론(;)은 문의 종료를 나타냅니다. +즉, 자바스크립트 엔진은 세미콜론으로 문이 종료한 위치를 파악하고 순차적으로 하나씩 문을 실행합니다. +따라서 문을 끝낼 때는 세미콜론을 붙여야 합니다. +단, 중괄호로 묶은 코드 블록({ ... })은 세미콜론을 붙이지 않습니다. +예를 들어, if 문, for 문, 함수 등의 코드 블록 뒤에는 세미콜론을 붙이지 않는다. +코드 블록은 언제나 문의 종료를 의미하는 자체 종결성(self closing)을 가지기 때문입니다. + +
+ +문의 끝에 붙이는 세미콜론은 옵션입니다. 즉, 세미콜론은 생략 가능합니다. +자바스크립트 엔진은 소스코드를 해석할 때 문의 끝이라고 예측되는 지점에 자동으로 세미콜론을 붙여주는 +세미콜론 자동 삽입 기능(ASI; Automatic Semicolon Insertion)이 암묵적으로 수행되기 때문입니다. + +하지만 세미콜론 자동 삽입 기능이 +아래의 예제와 같이 개발자의 예측이 일치하지 않는 경우가 간혹 있습니다. + +``` js +function foo () { + return + {} + // ASI 동작 결과: return; {}; + // 개발자의 의도: return {}; +} + +console.log(foo()); + +var = bar = function() {} +(function() {})(); +// ASI 동작 결과: var bar = function() {}(function() {})(); +// 개발자의 의도: var bar = function() {}; (function() {})(); +``` + +ESLint와 같은 정적 분석 도구에서도 세미콜론의 사용을 기본으로 하고 있고 +TS39(ECMAScript 기술 위원회)도 세미콜론 사용을 권장하는 분위기이므로 +세미콜론을 붙이도록 합시다. + + +

+ +### 표현식인 문과 표현식이 아닌 문 +표현식은 문의 일부일 수도 있고, 그 자체로도 문이 될 수 있습니다. +아래 예제를 살펴봅시다. + +``` js +var x; // 값으로 출력될 수 없으므로 표현식이 아닙니다. +x = 1 + 2; // 표현식이면서 완전한 문입니다. +``` + +표현식인 문과 표현식이 아닌 문을 구별하는 가장 간단하고 명료한 방법은 변수에 할당해보는 것입니다. +표현식인 문은 값으로 평가되므로 변수에 할당이 가능합니다. + +하지만 표현식이 아닌 문은 값으로 평가할 수 없으므로 변수에 할당하면 에러가 발생합니다. + +``` js +var foo = var x; +``` + +

+ +참고: 함수 선언문과 표기식 +```js +// 함수 선언문 +function func2() { + console.log("func2"); +} + +// 함수 표기식 +var func1 = () => { + console.log("func1"); +} +``` + + +

+ +※ 완료 값(completion value) +개발자 도구에서 표현식이 아닌 문을 실행하면 언제나 `undefined`를 출력합니다. +이를 완료 값이라 하며, 완료 값은 표현식의 평가 결과가 아닙니다. + +``` js +var foo; // undefined +if (true) {} // undefined +``` + diff --git "a/book/\354\235\264\354\232\251\354\232\260/chapter_05.md" "b/book/\354\235\264\354\232\251\354\232\260/chapter_05.md" index 141bdbd..eb6dd24 100644 --- "a/book/\354\235\264\354\232\251\354\232\260/chapter_05.md" +++ "b/book/\354\235\264\354\232\251\354\232\260/chapter_05.md" @@ -73,7 +73,7 @@ var score = 200; ``` 위 예제의 `200`은 리터럴입니다. -리터럴 `200`은 자바스크립트 엔진에 의해 평가되어 값을 생성하므로 그 자체로 표현힉입니다. +리터럴 `200`은 자바스크립트 엔진에 의해 평가되어 값을 생성하므로 그 자체로 표현식입니다.