모던 자바스크립트 딥다이브Chapter4~12

HYEON17·2022년 12월 21일
0

WIL

목록 보기
1/13
post-thumbnail

chapter 4 변수

4.1 변수란 무엇인가? 왜 필요한가?

변수(variable)

  • 하나의 값을 저장하기 위해 확보한 메모리 공간 자체 또는 메모리 공간을 식별하기 위해 붙인 이름
  • 값의 위치를 가리키는 상징적인 이름

4.2 식별자

식별자(identifier)

  • 어떤 값을 구별해서 식별할 수 있는 고유한 이름
  • 변수 이름을 식별자라고 한다
  • 식별자는 메모리 주소를 기억한다.

4.3 변수 선언

변수 선언(variable declaration)

  • 변수를 사용하려면 반드시 선언이 필요
  • var, let, const 키워드를 사용

var

  • 블록 레벨 스코프를 지원하지 않고 함수 레벨 스코프를 지원하기 때문에 의도치 않게 전역 변수가 선언되어 심각한 부작용이 발생
  • var 키워드를 사용한 변수 선언은 선언 단계와 초기화 단계가 동시에 진행

키워드

자바스크립트 코드를 해석하고 실행하는 자바스크립트 엔진이 수행할 동작을 규정한 일종의 명령어

undefined

자바스크립트에서 제공하는 원시 타입의 값

4.4 변수 선언의 실행 시점과 변수 호이스팅

  • 자바스크립트 코드는 인터프리터에 의해 한 줄씩 순차적으로 실행
console.log(score);  //undefined

var score;  //변수 선언문

변수 선언이 런타임이 아니라 그 이전 단계에서 먼저 실행되기 때문에 참조에러가 발생하는게 아닌 undefined가 출력

자바스크립트 엔진의 코드 실행 과정

  1. 자바스크립트 엔진은 소스코드의 평가 과정을 거치면서 소스코드를 실행하기 위한 준비를 함
  2. 소스코드의 평가 과정에서 자바스크립트 엔진은 변수 선언을 포함한 모든 선언문을 소스코드에서 찾아내 먼저 실행
  3. 소스코드의 평가 과정이 끝나면 변수 선언을 포함한 모든 선언문을 제외하고 소스코드를 한 줄씩 순차적으로 실행

    즉, 자바스크립트 엔진은 변수 선언이 소스코드 어디에 있든 상관없이 다른 코드보다 먼저 실행. 따라서 변수 선언이 어디에 위치하는지 상관없이 어디서든지 변수 참조 가능

변수 호이스팅(variable hoisting)

  • 변수 선언문이 코드의 선두로 끌어 올려진 것처럼 동작하는 자바스크립트 고유의 특징
  • 변수 선언뿐 아니라 var, let, const, function,* class 키워드를 사용해서 선언하는 모든 식별자(변수, 함수, 클래스 등)는 호이스팅 된다.

4.5 값의 할당

  • 변수 선언은 소스코드가 순차적으로 실행되는 시점인 런타임 이전에 먼저 실행
  • 값의 할당은 소스코드가 순차적으로 실행되는 시점인 런타임에 실행
console.log(score); // undefined

var score;  // ① 변수 선언
score = 80; // ② 값의 할당

console.log(score); // 80

변수에 값을 할당할 때는 이전 값 undefined가 저장되어 있던 메모리 공간을 지우고 그 메모리 공간에 할당 값 80을 새롭게 저장하는 것이 아닌 새로운 메모리 공간을 확보하고 그곳에 할당 값 80을 저장한다

4.6 값의 재할당

상수(constant)

  • 값을 재할당할 수 없어서 변수에 저장된 값을 변경할 수 없다면 상수이다
  • 한번 정해지면 변하지 않는 값
  • 단 한번만 할당할 수 있는 변수

constant 키워드

constant를 사용해 선언한 변수는 재할당이 금지

가비지 콜렉터

  • 애플리케이션이 할당한 메모리 공간을 주기적으로 검사하여 더 이상 사용되지 않는 메모리를 해제
  • 메모리 누수를 방지

4.7 식별자 네이밍 규칙

  • 식별자는 특수문자를 제외한 문자, 숫자, 언더스코어(_), 달러 기호($)를 포함할 수 있다
  • 단, 식별자는 특수문자를 제외한 문자, 언더스코어(_), 달러 기호($)로 시작해야 한다. 숫자로 시작하는 것은 허용하지 않는다.
  • 예약어는 식별자로 사용할 수 없다.

자바스크립트 예약어

  • 예약어는 프로그래밍 언어에서 사용되고 있거나 사용될 예정인 단어

네이밍 컨벤션

하나 이상의 영어 단어로 구성된 식별자를 만들 때 가독성 좋게 단어를 한눈에 구분하기 위해 규정한 명명 규칙

// 카멜 케이스 (camelCase)
var firstName;

// 스네이크 케이스 (snake_case)
var first_name;

// 파스칼 케이스 (PascalCase)
var FirstName;

// 헝가리언 케이스 (typeHungarianCase)
var strFirstName; // type + identifier
var $elem = document.getElementById('myId'); // DOM 노드
var observable$ = fromEvent(document, 'click'); // RxJS 옵저버블

chapter 5 표현식과 문

5.1 값

  • 값은 식이 평가되어 생성된 결과
  • 평가란 식을 해석해서 값을 생성하거나 참조하는 것

5.2 리터럴

리터럴은 사람이 이해할 수 있는 문자 또는 약속된 기호를 사용해 값을 생성하는 표기법

5.3 표현식

  • 표현식은 값으로 평가될 수 있는 문
  • 표현식이 평가되면 새로운 값을 생성하거나 기존값을 참조
// 리터럴 표현식
10
'Hello'

// 식별자 표현식(선언이 이미 존재한다고 가정)
sum
person.name
arr[1]

// 연산자 표현식
10 + 20
sum = 10
sum !== 10

// 함수/메서드 호출 표현식(선언이 이미 존재한다고 가정)
square()
person.getName()
  • 표현식과 표현식이 평가된 값은 동치관계
    • 예) 1+2 = 3

5.4 문

  • 문(statement)은 프로그램을 구성하는 기본 단위이자 최소 실행 단위
  • 토큰이란 문법적인 의미를 가지며, 문법적으로 더 이상 나눌 수 없는 코드의 기본 요소를 의미

5.5 세미콜론과 세미콜론 자동 삽입 기능

  • 세미콜론(;)은 문의 종료를 나타낸다
  • 0개 이상의 문을 중괄호로 묶은 코드 블록 뒤에는 세미콜론을 붙이지 않는다
    • 자체 종결성을 갖기 때문
  • 문의 끝에 붙이는 세미콜론은 옵션
    • 생략 가능

5.6 표현식인 문과 표현식이 아닌 문

// 변수 선언문은 값으로 평가될 수 없으므로 표현식이 아니다.
var x;
// 1, 2, 1 + 2, x = 1 + 2는 모두 표현식이다.
// x = 1 + 2는 표현식이면서 완전한 문이기도 하다.
x = 1 + 2;
  • 표현식인 문과 표현식이 아닌 문을 구별하는 방법은 변수에 할당에 보는 것
// 표현식이 아닌 문은 값처럼 사용할 수 없다.
var foo = var x; // SyntaxError: Unexpected token var

완료 값

  • 크롬 개발자 도구에서 표현식이 아닌 문을 실행하면 언제나 undefined를 출력하는 것이 완료값이다.
  • 완료식은 평가 결과가 아니므로 다른값과 같이 변수에 할당과 참조가 불가능

chapter 6 데이터 타입

  • 자바스크립트는 7개의 데이터 타입을 제공

6.1 숫자 타입

  • 자바스크립트는 하나의 숫자 타입만 존재
  • 모든 수를 실수로 처리
// 모두 숫자 타입이다.
var integer = 10;    // 정수
var double = 10.12;  // 실수
var negative = -20;  // 음의 정수
  • 모두 10진수로 해석됨
var binary = 0b01000001; // 2진수
var octal = 0o101;       // 8진수
var hex = 0x41;          // 16진수

// 표기법만 다를 뿐 모두 같은 값이다.
console.log(binary); // 65
console.log(octal);  // 65
console.log(hex);    // 65
console.log(binary === octal); // true
console.log(octal === hex);    // true
  • 숫자 타입은 세 가지 특별한 값도 표현 가능
    • Infinity: 양의 무한대
    • -Infinity: 음의 무한대
    • NaN: 산술 연산 불가
// 숫자 타입의 세 가지 특별한 값
console.log(10 / 0);       // Infinity
console.log(10 / -0);      // -Infinity
console.log(1 * 'String'); // NaN
  • 자바스크립트는 대소문자를 구별
    • NaNnan

6.2 문자열 타입

  • 문자열 타입은 텍스트 데이터를 나타내는데 사용
  • 문자열은 ' ', " ", 백틱으로 텍스트를 감싼다
// 문자열 타입
var string;
string = '문자열'; // 작은따옴표
string = "문자열"; // 큰따옴표
string = `문자열`; // 백틱 (ES6)

string = '작은따옴표로 감싼 문자열 내의 "큰따옴표"는 문자열로 인식된다.';
string = "큰따옴표로 감싼 문자열 내의 '작은따옴표'는 문자열로 인식된다.";
  • 문자열은 원시 타입이며, 변경 불가능 한 값

6.3 템플릿 리터럴

  • 템플릿 리터럴은 런타임에 일반 문자열로 변환되어 처리
  • 백틱만을 사용해 표현
var template = `Template literal`;
console.log(template); // Template literal

6.3.1 멀티라인 문자열

  • 일반 문자열 내에서는 개행이 불가능
var str = 'Hello
world.';
// SyntaxError: Invalid or unexpected token
  • 일반 문자열 내에서 줄바꿈 등의 공백을 표현하려면 백슬래시(\)로 시작하는 이스케이프 시퀀스를 사용
  • 템플릿 리터럴 내에서는 이스케이프 시퀀스를 사용하지 않아도 개행이 허용, 모든 공백도 그대로 적용 가능

6.3.2 표현식 삽입

  • 문자열은 문자열 연산자 +를 사용해 연결
    • +연산자는 피연산자중 하나 이상이 문자열인 경우 문자열 연결 연산자로 동작
    • 그 외의 경우는 덧셈 연산자로 동작
var first = 'Ung-mo';
var last = 'Lee';

// ES5: 문자열 연결
console.log('My name is ' + first + ' ' + last + '.'); // My name is Ung-mo Lee.
  • 템플릿 리터럴 내에서는 표현식 삽입을 통해 간단히 문자열을 삽입
var first = 'Ung-mo';
var last = 'Lee';

// ES6: 표현식 삽입
console.log(`My name is ${first} ${last}.`); // My name is Ung-mo Lee.
  • ${ }으로 표현식을 감싼다
  • 표현식의 평가 결과가 문자열이 아니더라도 문자열로 타입이 강제로 변환되어 삽입
  • 표현식 삽입은 반드시 템플릿 리터럴 내에서만 사용
    • 일반 문자열에서의 표현식 삽입은 문자열로 취급

6.4 불리언 타입

불리언 타입의 값은 논리적참, 거짓을 나타내는 truefalse뿐이다.

6.5 undefined 타입

  • undefined값은 undefined가 유일
  • undefined는 의도적으로 할당한 값이 아닌 자바스크립트 엔진이 변수를 초기화 할 때 사용하는 값

6.6 null 타입

  • null타입의 값은 null이 유일
  • null은 변수에 값이 엇다는 것으 의도적으로 명시 할때 사용
  • 함수가 유효한 값을 반환할 수 없는 경우 명시적으로 null을 반환

6.7 심벌 타입

  • 변경 불가능한 원시 타입의 값
  • 다른 값과 중복되지 않은 유일무이한 값
  • 주로 이름이 충돌할 위험이 없는 객체의 유일한 프로퍼티 키를 만들기 위해 사용

6.8 객체 타입

자바스크립트를 이루고 있는 거의 모든 것이 객체다

6.9 데이터 타입의 필요성

6.9.1 데이터 타입에 의한 메모리 공간의 확보와 참조

  • 변수에 할당되는 값의 데이터 타입에 따라 확보해야 할 메모리 공간의 크기가 결정
  • 자바스크립트는 숫자 타입의 값을 생성할 때 배정밀도 64비트 부동소수점 형식을 사용

6.9.2 데이터 타입에 의한 값의 해석

데이터 타입이 필요한 이유

  • 값을 저장할 때 메모리 공간의 크기를 결정하기 위해
  • 값을 참조할 때 읽어 들여야 할 메모리 공간의 크기를 결정하기 위해
  • 메모리에서 읽은 2진수를 어떻게 해석할지 결정하기 위해

6.10 동적 타이핑

6.10.1 동적 타입 언어와 정적 타입 언어

  • 자바스크립트는 변수를 선언할 때 타입을 선언하지 않는다
  • 키워드를 사용해 변수를 선언
  • 미리 선언한 데이터 타입의 값만 할당할 수 있는 것이 아닌 어떠한 데이터 값이라도 자유롭게 할당 가능

할당된 데이터 타입을 문자열로 반환하는 코드

var foo;
console.log(typeof foo);  // undefined

foo = 3;
console.log(typeof foo);  // number

foo = 'Hello';
console.log(typeof foo);  // string

foo = true;
console.log(typeof foo);  // boolean

foo = null;
console.log(typeof foo);  // object

foo = Symbol(); // 심벌
console.log(typeof foo);  // symbol

foo = {}; // 객체
console.log(typeof foo);  // object

foo = []; // 배열
console.log(typeof foo);  // object

foo = function () {}; // 함수
console.log(typeof foo);  // function
  • 자바스크립트 변수는 할당에 의해 타입이 결정된다
  • 재할당에 의해 변수의 타입은 언제든지 동적으로 변할수 있다
    • 이러한 특징을 동적 타이핑(dynamic/weak type)이라고 한다

6.10.2 동적 타입 언어와 변수

  • 자바스크립트는 의도와 상관없이 암묵적으로 타입이 자동으로 변환된다

변수를 사용할 때 주의사항

  • 변수는 꼭 필요한 경우에 한해 제한적으로 사용
  • 변수의 유효 범위는 최대한 좁게 만들어 변수의 부작용을 억제
  • 전역 변수는 최대한 사용하지 않는다
  • 변수보다는 상수를 사용해 값의 변경을 억제
  • 변수 이름은 변수의 목적이나 의미를 파악할 수 있도록 네이밍

chapter 7 연산자

7.1 산술 연산자

산술연산이 불가능한 경우 NaN을 반환

7.1.1 이항 산술 연산자

  • 2개의 피연산자를 산술 연산하여 숫자 값을 만듬
  • 피연산자의 값을 변경하는 부수 효과(side effect)가 없다

    부수 효과(side effect)
    값을 반환하는 메서드나 함수가 외부 상태를 변경하는 경우

7.1.2 단항 산술 연산자

  • 1개의 피연산자를 산술 연산하여 숫자 값을 만듬
  • 증가/감소(++/--) 연산자는 피연산자의 값을 변경하는 부수 효과가 있다
    • 피연산자의 값을 변경하는 암묵적 할당이 이루어짐

증가/감소 연산자의 위치에 따른 의미

var x = 5, result;

// 선할당 후증가(postfix increment operator)
result = x++;
console.log(result, x); // 5 6

// 선증가 후할당(prefix increment operator)
result = ++x;
console.log(result, x); // 7 7

// 선할당 후감소(postfix decrement operator)
result = x--;
console.log(result, x); // 7 6

// 선감소 후할당 (prefix decrement operator)
result = --x;
console.log(result, x); // 5 5
  • +단항 연산자는 피연산자에 어떠한 효과도 없다
    • 피연산자를 변경하는것이 아닌 숫자 타입으로 변환한 값을 생성해서 반환
    • 부수 효과는 없음

7.1.3 문자열 연결 연산자

+연산자는 피연산자 중 하나 이상이 문자열인 경우 문자열 연결 연산자로 동작
그 외에는 산술 연산자로 동작

암묵적 타입 변환 예시

// true는 1로 타입 변환된다.
1 + true; // -> 2

// false는 0으로 타입 변환된다.
1 + false; // -> 1

7.2 할당 연산자

  • 우항에 있는 피연산자의 평가 결과를 좌항에 있는 변수에 할당
  • 변수 값이 변하는 부수 효과가 있음
  • 할당문은 값으로 평가되는 표현식인 문으로서 할당된 값으로 평가

7.3 비교 연산자

좌항과 우항의 피연산자를 비교한 다음 결과를 불리언 값으로 반환

7.3.1 동등/일치 비교 연산자

  • 좌항과 우항의 피연산자가 같은 값으로 평가되는지 비교해 불리언 값을 반환
  • 동등 비교 연산자는 느슨한 비교
    • 좌항과 우항의 피연산자를 비교할 때 먼저 암묵적 타입 변환을 통해 타입을 일치시킨 후 같은 값인지 비교
// 타입은 다르지만 암묵적 타입 변환을 통해 타입을 일치시키면 동등하다.
5 == '5'; // -> true
  • 일치 비교 연산자는 엄격한 비교
    • 좌항과 우항의 피연산자가 타입도 같고 값도 같은 경우에 true를 반환
// 암묵적 타입 변환을 하지 않고 값을 비교한다.
// 즉, 값과 타입이 모두 같은 경우만 true를 반환한다.
5 === '5'; // -> false

특징

// NaN은 자신과 일치하지 않는 유일한 값이다.
NaN === NaN; // -> false

// 양의 0과 음의 0의 비교. 일치 비교/동등 비교 모두 결과는 true이다.
0 === -0; // -> true
0 == -0;  // -> true

7.3.2 대소 관계 비교 연산자

피연산자의 크기를 비교하여 불리언 값을 반환

7.4 삼항 조건 연산자

조건식의 평가 결과에 따라 반환할 값을 결정

  • 조건식의 평가 결과가 불리언 값이 아니면 불리언 값으로 암묵적 타입 변환
  • 값으로 평가할 수 있는 표현식인 문

7.5 논리 연산자

  • 논리 부정 연산자는 언제나 불리언 값을 반환
  • 논리합 또는 논리곱 연산자의 결과는 불리언 값이 아닐 수도 있다

7.6 쉼표 연산자

왼쪽 피연산자부터 차례대로 피연산자를 평가하고 마지막 피연산자의 평가가 끝나면 마지막 피연산자의 평가 결과를 반환

7.7 그룹 연산자

  • 연산자의 우선순위를 조절 가능
  • 연산자 우선순위가 가장 높음

7.8 typeof 연산자

  • 피연산자의 데이터 타입을 문자열로 반환
  • typeof 연산자는 7가지 문자열 "string", "number", "boolean", "undefined", "symbol", "object", "function"중 하나를 반환
typeof ''              // -> "string"
typeof 1               // -> "number"
typeof NaN             // -> "number"
typeof true            // -> "boolean"
typeof undefined       // -> "undefined"
typeof Symbol()        // -> "symbol"
typeof null            // -> "object"
typeof []              // -> "object"
typeof {}              // -> "object"
typeof new Date()      // -> "object"
typeof /test/gi        // -> "object"
typeof function () {}  // -> "function"

typeof 연산자가 반환하는 문자열은 7개의 데이터 타입과 정확히 일치하지는 않는다

7.9 지수 연산자

  • 좌항의 피연산자를 밑(base)으로, 우항의 피연산자를 지수(exponent)로 거듭 제곱 하여 숫자 값을 반환
  • 음수를 거듭 제곱이 밑으로 사용할 시 괄호로 묶어야 함
-5 ** 2;
// SyntaxError: Unary operator used immediately before exponentiation expression.
// Parenthesis must be used to disambiguate operator precedence

(-5) ** 2; // -> 25

지수 연산자는 이항 연산자 중 우선순위가 가장 높음

7.12 연산자 우선순위

연산자가 실행되는 순서

7.13 연산자 결합 순서

연산자의 어느쪽 부터 평가를 수행할 것인지를 나타내는 순서

chapter 8 제어문

8.1 블록문

  • 0개 이상의 문을 중괄호로 묶은 것으로, 코드 블록 또는 블록이라고 부른다
  • 블록문을 하나의 실행 단위로 취급
  • 블록문의 끝에는 세미콜론을 붙이지 않는다
// 블록문
{
  var foo = 10;
}

8.2 조건문

주어진 조건식의 평가 결과에 따라 코드 블록의 실행을 결정

8.2.1 if...else 문

주어진 조건식의 평가 결과, 논리적 참 또는 거짓에 따라 실행할 코드 블록을 결정

8.2.2 switch 문

  • 주어진 표현식을 평가하여 그 값과 일치하는 표현식을 갖는 case문으로 실행 흐름을 옮긴다
  • case문은 상황을 의미하는 표현식을 지정하고 콜론으로 마친다

8.3 반복문

  • 조건식의 평가결과가 참인 경우 코드블록을 실행, 그 후 다시 평가하여 참인 경우 코드블록 재실행
  • 조건식이 거짓일 때 까지 반복

8.3.1 for 문

for문의 실행순서

for문 무한루프

// 무한루프
for (;;) { ... }

8.3.2 while 문

주어진 조건식의 평가 결과가 참이면 코드 블록을 계속해서 반복 실행

  • for문은 반복 횟수가 명확할 때 사용
  • while문은 반복 횟수가 불명확할 때 사용

8.3.3 do...while 문

코드블럭을 먼저 실행하고 조건식을 평가

8.4 break 문

  • 코드블록을 탈출
  • switch문, 레이블 문, 반복문 외에 사용시 문법 에러 발생
    • 레이블 문이란 식별자가 붙은 문
// foo라는 레이블 식별자가 붙은 레이블 문
foo: console.log('foo');

8.5 continue 문

  • 반복문의 코드블록 실행을 현 시점에 중단하고 반복문의 증감식으로 실행 흐름을 이동
  • break문처럼 반복문을 탈출하지는 않는다

chapter 9 타입 변환과 단축 평가

9.1 타입 변환이란?

  • 명시적 타입 변환 또는 타입 캐스팅
    • 개발자가 의도적으로 값의 타입을 변환하는 것
  • 암묵적 타입 변환 또는 타입 강제 변환
    • 자바스크립트 엔진에 의해 암묵적으로 타입이 자동 변환
    • 기존 변수 값을 재할당 하여 변경하는 것이 아닌 피연산자의 값을 암묵적 타입 변환해 새로운 타입의 값을 만들어 단 한번 사용하고 버린다

9.2 암묵적 타입 변환

9.2.1 문자열 타입으로 변환

문자열 연결 연산자의 피연산자 중에서 문자열 타입이 아닌 피연산자를 문자열 타입으로 변환한다

1 + '2' // -> "12"

문자열 타입 아닌 값을 문자열 타입으로 변환을 수행 할 때 동작 예제

// 숫자 타입
0 + ''         // -> "0"
-0 + ''        // -> "0"
1 + ''         // -> "1"
-1 + ''        // -> "-1"
NaN + ''       // -> "NaN"
Infinity + ''  // -> "Infinity"
-Infinity + '' // -> "-Infinity"

// 불리언 타입
true + ''  // -> "true"
false + '' // -> "false"

// null 타입
null + '' // -> "null"

// undefined 타입
undefined + '' // -> "undefined"

// 심벌 타입
(Symbol()) + '' // -> TypeError: Cannot convert a Symbol value to a string

// 객체 타입
({}) + ''           // -> "[object Object]"
Math + ''           // -> "[object Math]"
[] + ''             // -> ""
[10, 20] + ''       // -> "10,20"
(function(){}) + '' // -> "function(){}"
Array + ''          // -> "function Array() { [native code] }"

9.2.2 숫자 타입으로 변환

  • 산술 연산자 표현식을 평가하기 위해 피연산자 중에서 숫자타입이 아닌 피연산자를 숫자타입으로 암묵적 타입 변환
  • 피연산자를 숫자 타입으로 변환할 수 없는 경우의 결과는 NaN이 된다

숫자 타입으로 암묵적 타입 변환 수행 예제

// 문자열 타입
+''       // -> 0
+'0'      // -> 0
+'1'      // -> 1
+'string' // -> NaN

// 불리언 타입
+true     // -> 1
+false    // -> 0

// null 타입
+null     // -> 0

// undefined 타입
+undefined // -> NaN

// 심벌 타입
+Symbol() // -> TypeError: Cannot convert a Symbol value to a number

// 객체 타입
+{}             // -> NaN
+[]             // -> 0
+[10, 20]       // -> NaN
+(function(){}) // -> NaN

9.2.3 불리언 타입으로 변환

불리언 타입이 아닌 값을 Truthy 값(참으로 평가되는 값) 또는 Falsy 값(거짓으로 평가되는 값)으로 구분

  • false로 평가되는 Falsy값
    • false, undefined, null, 0, -0, NaN, 빈 문자열
  • Falsy값 외의 모든 값은 true로 평가되는 Truthy 값이다

9.3 명시적 타입 변환

9.3.1 문자열 타입으로 변환

// 1. String 생성자 함수를 new 연산자 없이 호출하는 방법
// 숫자 타입 => 문자열 타입
String(1);        // -> "1"
String(NaN);      // -> "NaN"
String(Infinity); // -> "Infinity"
// 불리언 타입 => 문자열 타입
String(true);     // -> "true"
String(false);    // -> "false"

// 2. Object.prototype.toString 메서드를 사용하는 방법
// 숫자 타입 => 문자열 타입
(1).toString();        // -> "1"
(NaN).toString();      // -> "NaN"
(Infinity).toString(); // -> "Infinity"
// 불리언 타입 => 문자열 타입
(true).toString();     // -> "true"
(false).toString();    // -> "false"

// 3. 문자열 연결 연산자를 이용하는 방법
// 숫자 타입 => 문자열 타입
1 + '';        // -> "1"
NaN + '';      // -> "NaN"
Infinity + ''; // -> "Infinity"
// 불리언 타입 => 문자열 타입
true + '';     // -> "true"
false + '';    // -> "false"

9.3.2 숫자 타입으로 변환

// 1. Number 생성자 함수를 new 연산자 없이 호출하는 방법
// 문자열 타입 => 숫자 타입
Number('0');     // -> 0
Number('-1');    // -> -1
Number('10.53'); // -> 10.53
// 불리언 타입 => 숫자 타입
Number(true);    // -> 1
Number(false);   // -> 0

// 2. parseInt, parseFloat 함수를 사용하는 방법(문자열만 변환 가능)
// 문자열 타입 => 숫자 타입
parseInt('0');       // -> 0
parseInt('-1');      // -> -1
parseFloat('10.53'); // -> 10.53

// 3. + 단항 산술 연산자를 이용하는 방법
// 문자열 타입 => 숫자 타입
+'0';     // -> 0
+'-1';    // -> -1
+'10.53'; // -> 10.53
// 불리언 타입 => 숫자 타입
+true;    // -> 1
+false;   // -> 0

// 4. * 산술 연산자를 이용하는 방법
// 문자열 타입 => 숫자 타입
'0' * 1;     // -> 0
'-1' * 1;    // -> -1
'10.53' * 1; // -> 10.53
// 불리언 타입 => 숫자 타입
true * 1;    // -> 1
false * 1;   // -> 0

9.3.3 불리언 타입으로 변환

// 1. Boolean 생성자 함수를 new 연산자 없이 호출하는 방법
// 문자열 타입 => 불리언 타입
Boolean('x');       // -> true
Boolean('');        // -> false
Boolean('false');   // -> true
// 숫자 타입 => 불리언 타입
Boolean(0);         // -> false
Boolean(1);         // -> true
Boolean(NaN);       // -> false
Boolean(Infinity);  // -> true
// null 타입 => 불리언 타입
Boolean(null);      // -> false
// undefined 타입 => 불리언 타입
Boolean(undefined); // -> false
// 객체 타입 => 불리언 타입
Boolean({});        // -> true
Boolean([]);        // -> true

// 2. ! 부정 논리 연산자를 두번 사용하는 방법
// 문자열 타입 => 불리언 타입
!!'x';       // -> true
!!'';        // -> false
!!'false';   // -> true
// 숫자 타입 => 불리언 타입
!!0;         // -> false
!!1;         // -> true
!!NaN;       // -> false
!!Infinity;  // -> true
// null 타입 => 불리언 타입
!!null;      // -> false
// undefined 타입 => 불리언 타입
!!undefined; // -> false
// 객체 타입 => 불리언 타입
!!{};        // -> true
!![];        // -> true

9.4 단축 평가

9.4.1 논리 연산자를 사용한 단축 평가

  • 논리곱(&&) 연산자와 논리합(||) 연산자는 논리 연산의 결과를 결정하는 피연산자를 타입 변환하지 않고 그대로 반환하는것을 단축평가라 한다
  • 단축평가는 표현식을 평가하는 도중에 평가결과가 확정된 경우 나머지 평가 과정을 생략

단축 평가 규칙

단축 평가 사용시 if문 대체 가능

var done = true;
var message = '';

// 주어진 조건이 true일 때
if (done) message = '완료';

// if 문은 단축 평가로 대체 가능하다.
// done이 true라면 message에 '완료'를 할당
message = done && '완료';
console.log(message); // 완료

-------------------------------------------------------------
  
var done = false;
var message = '';

// 주어진 조건이 false일 때
if (!done) message = '미완료';

// if 문은 단축 평가로 대체 가능하다.
// done이 false라면 message에 '미완료'를 할당
message = done || '미완료';
console.log(message); // 미완료

9.4.2 옵셔널 체이닝 연산자

  • 옵셔널 체이닝 연산자 ?.는 좌항의 피연산자가 null또는 undefined인 경우 undefined를 반환하고, 그렇지 않으면 우항의 프로퍼티 참조
  • 객체를 가리키기를 기대하는 변수가 null또는 undefined가 아닌지 확인하고 프로퍼티를 참조할 때 유용

9.4.3 null 병합 연산자

  • null 병합 연산자 ??는 좌항의 피연산자가 null 또는 undefined인 경우 우항의 피연산자를 반환, 그렇지 않으면 좌항의 피연산자를 반환
  • 변수에 기본값을 설정할 때 유용

chapter 10 객체 리터럴

10.1 객체란?

  • 원시 값을 제외한 나머지 값은 모두 객체
  • 객체는 변경 가능한 값

객체는 0개 이상의 프로퍼티로 구성된 집합, 프로퍼티는 키와 값으로 구성

프로퍼티 값이 함수일 경우 메서드라 부른다

  • 프로퍼티: 객체의 상태를 나타내는 값
  • 메서드: 프로퍼티를 참조하고 조작할 수 있는 동작

10.2 객체 리터럴에 의한 객체 생성

  • 객체를 생성하기 위한 표기법
  • 중괄호({...})내에 0개 이상의 프로퍼티를 정의
  • 값으로 평가되는 표현식, 따라서 세미콜론을 붙인다

예제

var person = {
  name: 'Lee',
  sayHello: function () {
    console.log(`Hello! My name is ${this.name}.`);
  }
};

console.log(typeof person); // object
console.log(person); // {name: "Lee", sayHello: ƒ}

10.3 프로퍼티

  • 프로퍼티 키: 빈 문자열을 포함하는 모든 문자열 또는 심벌 값
  • 프로퍼티 값: 자바스크립트에서 사용할 수 있는 모든 값
var person = {
  // 프로퍼티 키는 name, 프로퍼티 값은 'Lee'
  name: 'Lee',
  // 프로퍼티 키는 age, 프로퍼티 값은 20
  age: 20
};

식별자 네이밍 규칙을 따르지 않는 이름은 따옴표 사용

var person = {
  firstName: 'Ung-mo', // 식별자 네이밍 규칙을 준수하는 프로퍼티 키
  'last-name': 'Lee'   // 식별자 네이밍 규칙을 준수하지 않는 프로퍼티 키
};

console.log(person); // {firstName: "Ung-mo", last-name: "Lee"}

문자열 표현식을 사용해 프로퍼티 키를 동적으로 생성할 시 대괄호로 묶어야 한다

10.4 메서드

프로퍼티 값이 함수일 경우 메서드라 한다

var circle = {
  radius: 5, // ← 프로퍼티

  // 원의 지름
  getDiameter: function () { // ← 메서드
    return 2 * this.radius; // this는 circle을 가리킨다.
  }
};

console.log(circle.getDiameter()); // 10

10.5 프로퍼티 접근

  • 마침표 프로퍼티 접근 연산자(.)를 사용하는 마침표 표기법
  • 대괄호 프로퍼티 접근 연산자([...])를 사용하는 대괄호 표기법
    • 대괄호 프로퍼티 접근 연산자 내부에 지정하는 프로퍼티 키는 반드시 따옴표로 감싼 문자열이어야 한다
    • 프로퍼티 키가 식별자 네이밍 규칙을 준수하지 않는 이름이면 반드시 대괄호 표기법을 사용

10.6 프로퍼티 값 갱신

var person = {
  name: 'Lee'
};

// person 객체에 name 프로퍼티가 존재하므로 name 프로퍼티의 값이 갱신된다.
person.name = 'Kim';

console.log(person);  // {name: "Kim"}

10.7 프로퍼티 동적 생성

var person = {
  name: 'Lee'
};

// person 객체에는 age 프로퍼티가 존재하지 않는다.
// 따라서 person 객체에 age 프로퍼티가 동적으로 생성되고 값이 할당된다.
person.age = 20;

console.log(person); // {name: "Lee", age: 20}

10.8 프로퍼티 삭제

  • delete 연산자는 객체의 프로퍼티를 삭제하며 delete 연산자의 피연산자는 프로퍼티 값에 접근할 수 있는 표현식이어야 한다
  • 존재하지 않는 프로퍼티 삭제 시 에러 없이 무시 된다
var person = {
  name: 'Lee'
};

// 프로퍼티 동적 생성
person.age = 20;

// person 객체에 age 프로퍼티가 존재한다.
// 따라서 delete 연산자로 age 프로퍼티를 삭제할 수 있다.
delete person.age;

// person 객체에 address 프로퍼티가 존재하지 않는다.
// 따라서 delete 연산자로 address 프로퍼티를 삭제할 수 없다. 이때 에러가 발생하지 않는다.
delete person.address;

console.log(person); // {name: "Lee"}

10.9 ES6에서 추가된 객체 리터럴의 확장 기능

10.9.1 프로퍼티 축약 표현

  • 프로퍼티 값으로 변수를 사용하는 경우 변수 이름과 프로퍼티 키가 동일한 이름일 때 프로퍼티 키를 생략 가능
    • 프로퍼티 키는 변수 이름으로 자동 생성

10.9.2 계산된 프로퍼티 이름

10.9.3 메서드 축약 표현

function 키워드를 생략한 축약 표현 사용 가능

// ES5
var obj = {
  name: 'Lee',
  sayHi: function() {
    console.log('Hi! ' + this.name);
  }
};

obj.sayHi(); // Hi! Lee
-------------------------------------------------------------------------------
// ES6
const obj = {
  name: 'Lee',
  // 메서드 축약 표현
  sayHi() {
    console.log('Hi! ' + this.name);
  }
};

obj.sayHi(); // Hi! Lee

chapter 11 원시 값과 객체의 비교

11.1 원시 값

11.1.1 변경 불가능한 값

  • 원시 값은 변경 불가능한 값
  • 한번 생성된 원시 값은 읽기 전용 값으로서 변경할 수 없다
    • 변경 불가능하다는 것은 변수가 아닌 값에 대한 진술

원시 값은 변경 불가능한 값

원시 값을 할당한 변수에 새로운 원시 값을 재할당시 새로운 메모리 공간을 확보하고 재할당한 원시 값을 저장후, 변수는 새롭게 재할당한 원시 값을 가리킨다.

원시 값이 변경 가능한 값인 경우

원시 값은 변경 불가능한 값이어서 직접 변경 불가능하다. 변수 값 변경하기 위해 원시값을 재할당 하면 새로운 메모리 공간을 확보하고 재할당한 값을 저장 후, 변수가 참조하던 메모리 공간의 주소를 변경한다. 값의 이러한 특성을 불변성이라고 한다
불변성을 갖는 원시 값을 할당한 변수는 재할당 이외에 변수 값을 변경할 수 있는 방법은 없다

11.1.2 문자열과 불변성

var str = 'Hello';
str = 'world';
  • 식별자 str'Hello'가 저장된 메모리 공간의 첫 번째 메모리 셀 주소를 가리킴
  • 두번째문이 실행되면 'world'를 메모리에 생성하고 식별자 str은 이것을 가리킴
  • 'Hello'는 사라지는게 아닌 'Hello''world'는 모두 메모리에 존재

11.1.3 값에 의한 전달

변수에 원시 값을 갖는 변수를 할당하면 할당받는 변수에는 할당되는 변수의 원시 값이 복사되어 전달

var score = 80;

// copy 변수에는 score 변수의 값 80이 복사되어 할당된다.
var copy = score;

console.log(score, copy); // 80  80
console.log(score === copy); // true

score변수와 copy변수의 값 80은 다른 메모리 공간에 저장된 별개의 값

score변수의 값을 변경해도 copy변수의 값에는 어떠한 영향도 주지 않음

두 변수가 같은 원시 값을 참조하다 어느 한쪽의 변수에 재할당시 새로운 메모리 공간에 재할당된 값이 저장

값의 의한 전달은 정확히 말하자면 값을 전달하는것이 아닌 메모리 주소를 전달하는 것이다. 단, 전달된 메모리 주소를 통해 메모리 공간에 접근하면 값을 참조 가능
따라서 두 변수의 원시 값은 서로 다른 메모리 공간에 저장된 별개의 값이 되어 어느 한쪽에서 재할당을 통해 값을 변경하더라도 서로 간섭 불가능

11.2 객체

11.2.1 변경 가능한 값

  • 객체는 변경 가능한 값
  • 객체를 할당한 변수가 기억하는 메모리 주소를 통해 메모리 공간에 접근하면 참조 값에 접근 가능
  • 객체를 할당한 변수는 재할당 없이 객체를 직접 변경 가능
var person = {
  name: 'Lee'
};

// 프로퍼티 값 갱신
person.name = 'Kim';

// 프로퍼티 동적 생성
person.address = 'Seoul';

console.log(person); // {name: "Kim", address: "Seoul"}

동작 구조

부작용: 여러개의 식별자가 하나의 객체를 공유할 수 있다

11.2.2 참조에 의한 전달

객체를 가리키는 변수를 다른 변수에 할당하면 원본의 참조 값이 복사되어 전달

  • 두 개의 식별자가 하나의 객체를 공유함
  • 어느 한쪽에서 객체를 변경하면 서로 영향을 주고 받음
var person = {
  name: 'Lee'
};

// 참조값을 복사(얕은 복사). copy와 person은 동일한 참조값을 갖는다.
var copy = person;

// copy와 person은 동일한 객체를 참조한다.
console.log(copy === person); // true

// copy를 통해 객체를 변경한다.
copy.name = 'Kim';

// person을 통해 객체를 변경한다.
person.address = 'Seoul';

// copy와 person은 동일한 객체를 가리킨다.
// 따라서 어느 한쪽에서 객체를 변경하면 서로 영향을 주고 받는다.
console.log(person); // {name: "Kim", address: "Seoul"}
console.log(copy);   // {name: "Kim", address: "Seoul"}

chapter 12 함수

12.1 함수란?

일련의 과정을 문으로 구현하고 코드 블록으로 감싸서 하나의 실행 단위로 정의한 것

  • 매개변수: 함수 내부로 입력을 전달 받는 변수
  • 인수: 함수가 호출될 때 함수로 값을 전달해주는 변수
  • 반환값: 출력

12.2 함수를 사용하는 이유

  • 코드의 중복을 억제
  • 재사용성을 높임
  • 유지보수의 편의성을 높임
  • 코드의 신뢰성을 높임
  • 코드의 가독성 향상

12.3 함수 리터럴

리터럴의 구성요소

12.4 함수 정의

12.4.1 함수 선언문

함수 선언문은 함수 이름을 생략 불가능
함수 선언문은 표현식이 아닌 문이므로 변수에 할당 불가능

// 기명 함수 리터럴을 단독으로 사용하면 함수 선언문으로 해석된다.
// 함수 선언문에서는 함수 이름을 생략할 수 없다.
function foo() { console.log('foo'); }
foo(); // foo

// 함수 리터럴을 피연산자로 사용하면 함수 선언문이 아니라 함수 리터럴 표현식으로 해석된다.
// 함수 리터럴에서는 함수 이름을 생략할 수 있다.
(function bar() { console.log('bar'); });
bar(); // ReferenceError: bar is not defined

bar는 함수 몸체 내에서만 참조할수 있는 식별자이므로 함수 호출 불가능

자바스크립트는 생성된 함수를 호출하기 위해 함수 이름과 동일한 이름의 식별자를 암묵적으로 생성하고, 거기에 함수 객체를 할당

함수는 함수 이름으로 호출하는 것이 아닌 함수 객체를 가리키는 식별자로 호출

12.4.2 함수 표현식

함수 리터럴의 함수 이름은 생략가능, 이러한 함수를 익명 함수라고 한다

12.4.3 함수 생성 시점과 함수 호이스팅

// 함수 참조
console.dir(add); // ƒ add(x, y)
console.dir(sub); // undefined

// 함수 호출
console.log(add(2, 5)); // 7
console.log(sub(2, 5)); // TypeError: sub is not a function

// 함수 선언문
function add(x, y) {
  return x + y;
}

// 함수 표현식
var sub = function (x, y) {
  return x - y;
};

함수 선언문으로 정의한 함수와 함수 표현식으로 정의한 함수의 생성 시점이 다르기 때문에 타입 에러가 난다. 따라서 함수 표현식으로 정의한 함수는 반드시 함수 표현식 이후에 참조 또는 호출

함수 호이스팅

  • 함수 선언문이 코드의 선두로 끌어 올려진 것처럼 동작
  • 함수를 호출하기 전에 반드시 함수를 선언해야 하는 규칙을 무시하는 특징

12.4.5 화살표 함수

  • 키워드 대신 화살표=>를 사용
  • 항상 익명으로 정의
// 화살표 함수
const add = (x, y) => x + y;
console.log(add(2, 5)); // 7

화살표 함수는 생성자 함수로 사용 불가능. 기존 함수와 this 바인딩 방식이 다르고 ,prototype 프로퍼티가 없으며 arguments객체를 생성하지 않음

12.5 함수 호출

12.5.1 매개변수와 인수

함수를 실행하기 위해 필요한 값을 함수 외부에서 내부로 전달할 때 매개변수를 통해 인수를 전달

  • 매개변수의 유효범위는 함수 내부

인수가 부족해서 인수가 할당되지 않은 매개변수의 값은 undefined

function add(x, y) {
  return x + y;
}

console.log(add(2)); // NaN

매개변수보다 인수가 더 많은 경우 초과된 인수는 무시

function add(x, y) {
  return x + y;
}

console.log(add(2, 5, 10)); // 7

12.5.3 매개변수의 최대 개수

  • 이상적인 함수는 한가지 일만 해야 하며 가급적 작게 만들어야 한다
  • 매개변수는 최대 3개 이상을 넘지 말아야 한다

12.5.4 반환문

함수는 return키워드와 반환값으로 이뤄진 반환문을 사용해 실행 결과를 함수 외부로 반환 할 수 있다

반환문의 역할
1. 반환문은 함수의 실행을 중단하고 함수 몸체를 빠져나간다
2. 반환문은 return 키워드 뒤에 오는 표현식을 평가해 반환

  • return 뒤에 반환값으로 사용할 표현식을 명시적으로 지정하지 않으면 undefined가 반환
function foo () {
  return;
}

console.log(foo()); // undefined 
  • 반환문은 생략 가능
function foo () {
// 반환문을 생략하면 암묵적으로 undefined가 반환된다.
}

console.log(foo()); // undefined

12.6 참조에 의한 전달과 외부 상태의 변경

// 매개변수 primitive는 원시 값을 전달받고, 매개변수 obj는 객체를 전달받는다.
function changeVal(primitive, obj) {
  primitive += 100;
  obj.name = 'Kim';
}

// 외부 상태
var num = 100;
var person = { name: 'Lee' };

console.log(num); // 100
console.log(person); // {name: "Lee"}

// 원시 값은 값 자체가 복사되어 전달되고 객체는 참조 값이 복사되어 전달된다.
changeVal(num, person);

// 원시 값은 원본이 훼손되지 않는다.
console.log(num); // 100

// 객체는 원본이 훼손된다.
console.log(person); // {name: "Kim"}
  • 원시 타입 인수는 함수 외부에서 함수 몸체 내부로 전달한 원시 값의 원본을 변경하는 어떠한 부수 효과도 발생하지 않음
  • 객체 타입 인수는 함수 외부에서 함수 몸체 내부로 전달한 참조 값에 의해 원본 객체가 변경

12.7 다양한 함수의 형태

12.7.1 즉시 실행 함수

  • 함수 정의와 동시에 즉시 호출되는 함수
  • 단 한번만 호출되며 다시 호출 불가능
  • 이름이 없는 익명함수를 사용하는것이 일반적
  • 반드시 그룹 연산자(...)로 감싸야 한다
// 즉시 실행 함수도 일반 함수처럼 값을 반환할 수 있다.
var res = (function () {
  var a = 3;
  var b = 5;
  return a * b;
}());

console.log(res); // 15

// 즉시 실행 함수에도 일반 함수처럼 인수를 전달할 수 있다.
res = (function (a, b) {
  return a * b;
}(3, 5));

console.log(res); // 15

12.7.2 재귀 함수

  • 함수가 자기 자신을 호출하는 함수
  • 반복되는 처리를 반복문 없이 구현할 수 있다는 장점
  • 무한 반복에 빠질 위험과 이로 인해 스택 오버플로 에러를 발생시킬 수 있으므로 주의해서 사용

12.7.3 중첩 함수

함수 내부에 정의된 함수

function outer() {
  var x = 1;

  // 중첩 함수
  function inner() {
    var y = 2;
    // 외부 함수의 변수를 참조할 수 있다.
    console.log(x + y); // 3
  }

  inner();
}

outer();

12.7.4 콜백 함수

함수의 매개변수를 통해 다른 함수의 내부로 전달되는 함수

고차 함수

  • 매개변수를 통해 함수의 외부에서 콜백 함수를 전달받은 함수
  • 콜백함수를 자신의 일부분으로 합성함

12.7.5 순수 함수와 비순수 함수

순수 함수

  • 어떤 외부 상태에 의존하지도 않고 변경하지도 않는, 즉 부수 효과가 없는 함수
  • 인수의 불변성을 유지
var count = 0; // 현재 카운트를 나타내는 상태

// 순수 함수 increase는 동일한 인수가 전달되면 언제나 동일한 값을 반환한다.
function increase(n) {
  return ++n;
}

// 순수 함수가 반환한 결과값을 변수에 재할당해서 상태를 변경
count = increase(count);
console.log(count); // 1

count = increase(count);
console.log(count); // 2

비순수 함수

  • 외부 상태에 의존하거나 외부 상태를 변경하는, 즉 부수 효과가 있는 함수
  • 불변성을 지향
var count = 0; // 현재 카운트를 나타내는 상태: increase 함수에 의해 변화한다.

// 비순수 함수
function increase() {
  return ++count; // 외부 상태에 의존하며 외부 상태를 변경한다.
}

// 비순수 함수는 외부 상태(count)를 변경하므로 상태 변화를 추적하기 어려워진다.
increase();
console.log(count); // 1

increase();
console.log(count); // 2
profile
프론트엔드 개발자

0개의 댓글