[제로초] 2장 - 기본 문법 배우기

joyful·2024년 9월 16일
0

JavaScript

목록 보기
1/1

들어가기 앞서

이 글은 「제로초의 자바스크립트 입문」을 읽으며 습득한 내용을 정리한 글입니다. 모든 출처는 해당 저서에 있습니다.


1. 코드 작성 규칙


1.1 세미콜론(;)

  • 하나의 명령이 끝날 때 필수는 아니지만 붙이기를 권장함
  • 한 줄에 여러 명령을 넣을 때는 명령마다 붙여주어 그다음 명령과 구분해야 함
console.log('Hello, world!'); console.log('Hello, javascript!'); console.log('Hello');



1.2 주석(comment)

  • 사람이 알아볼 수 있도록 설명을 작성한 부분
  • 코드 실행에 영향을 미치지 않음
  • 코드에 관한 자세한 설명을 작성하거나 특정 코드를 임시로 사용하지 않게 할 때 사용

1.2.1 한 줄 주석(//)

  • 코드가 실행되지 않도록 코드 앞에 // 기호를 붙여 주석 처리
// console.log('Hello, world!');
  • 코드 뒤에 // 기호를 붙여 주석 작성
console.log('Hello, world!');	// Hello, world! 출력
  • 보기 좋도록 // 기호 뒤에 띄어쓰기 권장

1.2.2 여러 줄 주석(/* */)

  • 한 줄로 작성하기에 주석이 너무 길 때 사용
  • 주석 처리하고 싶은 부분을 /* */ 기호로 감싸서 사용
    /* console.log('Hello, world!');
    console.log('Hello, comment!'); */
  • 코드 중간에도 사용 가능(주석을 제외한 나머지 부분 실행)
    console.log('Hello, world!');/* 여러 줄
    주석
    테스트 */ console.log('Hello, comment!');



1.3 들여쓰기

  • 제한은 없으나, 보통 스페이스로 2칸 혹은 4칸, 탭으로 4칸 공백을 표시
    if (condition) {
    	console.log('Hello, world!');
    }
  • 코드의 가독성 향상을 위해 들여쓰기할 것을 권장

2. 자료형

  • 값(value) : 프로그램에서 조작할 수 있는 데이터
  • 자료형(data type) : 값의 종류

2.1 문자열(string)

  • 문자(하나의 글자)들이 하나 이상 나열되어 있는 자료형

  • 식(또는 표현식, expression) : 값이 나오는 명령

  • 시작과 끝이 작은따옴표('') 또는 큰따옴표("")로 감싸진 값

    > 'Hello, world!';
    < Hello, world!
    
    > "Hello, world!';
    < Hello, world!
    • 문자열을 감싸는 따옴표는 시작과 끝을 같은 종류로 사용해야 함
  • typeof : 값의 자료형을 확인할 수 있는 연산자

    > typeof "Hello, world!";
    < 'string'
  • 비교 연산자(==) : 두 값이 같은 값인지 확인하는 연산자

    > '' == ' ';
    < false
    • 결과 값 : true(참) 또는 false(거짓)

2.1.1 문자열 내 따옴표 사용

> '문자열 안에 작은따옴표(')가 있어요.';
  Uncaught SyntaxError: Unexpected token ')'
  • 에러가 발생하는 이유

    • 자바스크립트 엔진은 문자열을 앞에서부터 파악함
    • 따라서 ( 뒤에 나오는 작은따옴표를 보고 문자열이 끝났다고 인식하여, ) 부터는 내용을 이해하지 못함
  • 해결방법

    • 문자열을 다른 종류의 따옴표로 감싸는 방법

      > "문자열 안에 작은 따옴표(')가 있어요.";
      < "문자열 안에 작은 따옴표(')가 있어요."
      
      > '문자열 안에 큰 따옴표(")가 있어요.';
      < '문자열 안에 큰 따옴표(")가 있어요.'
    • 이스케이핑(escaping)

      • 기호를 다르게 해석하게 하는 행위
      • 문자열 내부의 따옴표에 별도 처리(\, 백슬래시)
      > "문자열 안에 큰 따옴표(\")가 있어요.";
      < '문자열 안에 큰 따옴표(")가 있어요.'
      > '문자열 안에 작은 따옴표(\')가 있어요.';
      < "문자열 안에 작은 따옴표(')가 있어요."
      > '문자열 안에 백슬래시(\\)가 있어요.';
      < '문자열 안에 백슬래시(\)가 있어요.'
      • 백슬래시가 붙은 특수문자는 일반 문자로 해석됨

2.1.2 한 문자열을 여러 줄로 표시

  • 문자열에서 행갈이할 부분 앞에 \n 문자를 넣어 사용
    alert('여러 줄에 걸쳐\n표시됩니다.');

2.1.3 템플릿 리터럴(template literal)

  • 백틱(\, backtic 또는 backquote)으로 감싸서 문자열 표현

    > `저도 문자열입니다.`;
    < '저도 문자열입니다.'
    > ``;
    < ''
    > `문자열 안에 백틱(\`)이 있어요.`;
    < '문자열 안에 백틱(`)이 있어요.'
    • 행갈이할 때 \n 문자를 사용하지 않아도 되므로 유용함

      alert(`여러 줄에 걸쳐
      표기됩니다.
      
      줄을 더 늘려볼까요?`);

2.1.4 문자열 합치기

  • 문자열 사이에 + 연산자를 사용하면 문자열이 하나로 합쳐짐
    > '문자열이 긴 경우에는 ' + '문자열을 ' + '나눈 뒤 ' + '다시 합칩니다.';
    < '문자열이 긴 경우에는 문자열을 나눈 뒤 다시 합칩니다.'



2.2 숫자(number)

  • 따옴표로 감싸지 않고 그대로 적음

    5;
    
    // 소수
    5.04
    
    // 음수
    -5
    • 숫자를 따옴표로 감싸면 문자열로 인식
  • 지수 표기법(exponential notation)

    • 아주 큰 숫자나 소수점 이하 자릿수가 많은 숫자를 표현하는 방식
      534;	// 5 * 10^4(10000) = 50000
      5e+4;	// 5 * 10^4(10000) = 50000
      53-3;	// 5 * 10^-3(1/1000) = 0.005
  • 진법 표현

    // 2진법: 0b(숫자 영, 소문자 b) + 숫자
    > 0b11;
    < 3
    
    // 8진법: 0(숫자 영) 또는 0o(숫자 영, 소문자 o) + 숫자
    > 0o15;
    < 13
    > 015;
    < 13
    
    // 16진법: 0x(숫자 영, 소문자 x) + 숫자(10~15: 알파벳 a, b, c, d, e, f)
    > 0x1c;
    < 28

2.2.1 문자열 → 숫자

// parseInt(), Number()
> parseInt('5');
< 5
> Number('5');
< 5
종류설명비고
parseInt()문자열을 정수로 변환• 정수가 아닌 값을 입력하면 정수 부분만 추출하여 표시
• 다른 기수법 적용시 parseInt(숫자, 진법)으로 사용
parseFloat()문자열을 실수로 변환
Number()문자열을 숫자로 변환인자에 문자열 입력시 NaN 출력

2.2.2 NaN(Not a Number)

  • typeof 적용 시 'number' 출력
    > typeof NaN;
    < 'number'

2.2.3 산술 연산자

// +
> 1 + 2;
< 3;

// -
> 6 - 10;
< -4;

// *
> 3 * 4;
< 12;

// /
> 6 / 4;
< 1.5;

// %(나머지)
> 6 % 4;
< 2

// **(거듭제곱)
> 2 ** 4;
< 16

2.2.4 무한 값(infinity)

> 2/0;
< infinity

> typeof Infinity;
< 'number'

// 음수
> -2 / 0;
< -Infinity

// 사칙연산
> Infinity - 100;
< Infinity

// 무한 값끼리 계산 -> 성립하지 않음
> Infinity - Infinity;
< NaN

> 0 / 0;
< NaN

2.2.5 문자와 숫자 덧셈

  • 형 변환(type casting) : 값의 자료형이 바뀌는 현상 또는 행위

    // 문자열 + 숫자 = 문자열
    > '문자열' + 0
    < '문자열0'
    
    > '1' + 0
    < '10'
    • + 연산자 사용 시 숫자보다 문자열 우선
      > '문자열' - 0;
      < NaN	// 문자열이 NaN이 되어 0을 빼도 NaN이 됨
    • 연산자 사용 시 다른 자료형이 먼저 숫자로 형 변환된 후 빼기 실행

2.2.6 연산자 우선순위

우선순위연산자(쉼표로 구분)
19()(그룹화)
18.. [], new, ()(함수 호출), ?.
17new(인수 없이)
16++(후위), --(후위)
15!, ~, +(단항), -(단항), ++(전위), --(전위), typeof, void, delete, await
14**
13*, /, %
12+(다항), -(다항)
11<<, >>, >>>
10<, <=, >=, in, instanceof
9==, !=, ===, !==
8&
7^
6
5&&
4
3? :(삼항 연산자)
2=, +=, -=, +=, =, /=, %=, <<=, >>=, >>>=, &=, ^=,
1,(쉼표)
  • 연산자 우선순위가 높을수록 먼저 계산
  • 같은 우선순위의 연산자가 여러 개 나오면 먼저 나온 순서대로 계산

2.2.7 실수 연산 시 주의할 점

  • 부동소수점 문제: 실수 연산에서 오차가 발생하는 문제
    → 실수를 정수로 바꿔 계산하고 마지막에 다시 실수로 바꿈
    > (0.3 * 10 - 0.1 * 10) / 10;
    < 0.2



2.3 불 값(boolean)

설명
1참(true)
0거짓(false)

2.3.1 불 값 표현

> true;
< true

> false;
< false

> typeof true;
< 'boolean'
  • 따옴표로 감싸지 않고 입력

2.3.2 비교 연산자

종류설명
>왼쪽 값이 오른쪽 값보다 크다(초과)
<왼쪽 값이 오른쪽 값보다 작다(미만)
>=왼쪽 값이 오른쪽 값보다 크거나 같다(이상)
<=왼쪽 값이 오른쪽 값보다 크거나 작다(이하)
==왼쪽 값과 오른쪽 값이 같다(같음)
!=왼쪽 값과 오른쪽 값이 같지 않다(같지 않음)

✅ 숫자

// 같음
> 5 == 5;
< true

// 같지 않음
> 5 != 5;
< false

// 초과
> 5 > 3;
< true

// 미만
> 5 < 3;
< false

// 이상
> 5 >= 3;
< true

// 이하
> 5 <= 3;
< false
  • 참(true), 거짓(false) -> 논리식의 결과 값으로 주로 사용

✅ NaN

// NaN
> NaN == NaN
< false
> NaN != NaN
< true

✅ 불 값

> true > false;
< true
  • true: 1, false: 0

✅ 문자열

  • 문자 번호 기준(문자 번호가 클 수록 값이 큼)

    // b: 98, a: 97
    > 'b' > 'a';
    < true
    
    // 첫 문자가 같은 글자면 나머지를 다시 비교
    // b: 98, d: 100
    > 'ad' > 'ab';
    < true
    
    // 다음 문자가 존재하는 문자열 값이 더 큼
    > 'ab' > 'a';
    < true
  • 다른 자료형과의 비교

    > '3' < 5;
    < true
    
    // abc -> NaN
    > 'abc' < 5;
    < false
    
    // 0: 0, true: 1
    > '0' < true;
    < true;
    • 다른 자료형이 숫자로 형 변환된 후 비교

2.3.3 == VS ===

  • === : 값과 자료형이 같은지 비교하는 연산자

    > 1 === 1;
    < true
    
    > 1 !== '1';
    < true

2.3.4 논리 연산자

종류설명예시
&&(AND)왼쪽 식과 오른쪽 식이 모두 true일 때 결과도 true10 > 5 && 6 < 8;
(OR)
!(NOT)참 → 거짓, 거짓 → 참!true
// 예시: 형 변환 시 false가 되는 값
> !!false
< false

> !!''
< false

> !!0
< false

> !!NaN
< false
  • undefined, null -> 형 변환 시 false

2.3.5 논리 연산자 사용 시 유의할 점

✅ &&(AND)

> 5 && 4
< 4

> '' && 6
< ''
  • 앞에 나오는 값이 참이면 뒤에 나오는 값, 거짓이면 앞에 나오는 값을 결과로 반환

✅ ||(OR)

> 'hi' && 5
< 'hi'

> 0 && 6
< 6

> null || 6
> 6
  • 앞에 나오는 값이 참이면 앞에 나오는 값, 거짓이면 뒤에 나오는 값을 결과로 반환

✅ ??(널 병합 연산자, nullish coalescing operator)

> 'hi' ?? 5
< 'hi'

> 0 ?? 6
< 0

> null ?? 6
< 6
  • 앞에 나오는 값이 null 또는 undefined인 경우 뒤에 나오는 값을, 그 외에는 앞에 나오는 값을 결과로 반환



2.4 빈 값

2.4.1 undefined

> typeof undefined;
< 'undefined'

> !!undefined;
< false

> undefined == false;
< false

> undefined == 0;
< false;

> undefined == '';
< false;
  • 반환할 결과 값이 없을 경우
  • 기본값으로 사용

2.4.2 null

> undefined == null;
< true

> undefined === null;
< false

> null == false;
< false

> null == 0;
< false

> null == '';
< false

> typeof null;
< 'object'
  • 값이 null인지 확인하려면 === 연산자 필요

3. 변수

  • 변수(variable) : 값을 저장하고 저장한 값을 불러올 수 있게 하는 공간
  • 선언(declaration) : 변수를 만드는 행위

3.1 let

  • 변수를 선언하는 방법 → let, const, var
  • 형식 : let 변수명 = 식;
    • let + ... : 선언문
    • ... = ... : 초기화
  • 변수명과 값은 메모리에 저장되며, 메모리에서 변수명으로 값을 가져올 수 있음
  • 메모리를 초기화하면 메모리에 저장되어 있던 변수도 사라짐
  • 변수 선언 시 변수에 값을 대입하지 않아도 됨(기본값: undefined)
  • 이미 선언한 변수를 다시 선언하면 에러가 발생함



3.2 변수명 짓기

  • 특수문자는 $_만 사용 가능

  • 숫자로 시작 불가능

  • 한글, 한자, 유니코드 사용 가능(영어 사용 권장)

  • 예약어(reserved word)는 변수명으로 사용하지 않음

    await, break, case, catch, class, const, continue, debugger, default, delete, do, else, enum, export, extends, false, finally, for, function, if, import, in, instanceof, let, new, null, return, static, super, switch, this, throw, true, try, typeof, var, void, while, with, yield

    • 예외 존재(예약어 - 변수명 O, 일반 단어 - 변수명 X)



3.3 변수값 수정

  • 다양한 자료형의 값 저장 가능

  • 변수 값 초기화

    > change = undefined;
    < undefined
    
    > change = null;
    < null



3.4 변수 활용

  • 변수의 값을 다른 변수에 대입
    let string = 'Hello, variable';
    let string2 = string;
    string;
  • 자신에 대입
    let number = 5;
    number = number + 3;
    // number += 3;	// 위와 동일한 코드
  • 코드 중복 제거
    // 개선 전
    console.log('긴 문자열');
    console.log('긴 문자열');
    console.log('긴 문자열');
    // 개선 후
    let string = '긴 문자열입니다.';
    console.log(string);
    console.log(string);
    console.log(string);



3.5 const로 상수 선언

  • 실수로 값을 수정하는 일을 막기 위해 사용
  • 한 번 값을 대입하면 다른 값을 대입할 수 없음
  • 이미 선언한 상수를 다시 선언할 수 없음
    • 상수 선언 시 초기화하지 않으면 에러 발생



3.6 var

// 변수문
var variable = '다시 선언할 수 있습니다.';
  • 변수(variable)
  • 과거에 주로 사용
  • 기존에 선언했던 변수를 다시 선언해도 에러가 발생하지 않음
  • 예약어에 사용하는 단어를 변수명으로 사용할 수 있음

4. 조건문

4.1 중첩 if 문

  • 중첩 if 문은 피하는 것이 좋음
    • 조건문이 중첩되어 들여쓰기가 깊어질수록 가독성이 떨어짐
  • 가독성을 위해 중첩 if 문을 if-else if-else 문으로 변환하여 사용할 것

💻 개선 전

let first = true;
let second = false;

if (first) {
  console.log('첫 번째 조건 충족!');
  if (second) {
    console.log('두 번째 조건도 충족!');
  } else {
    console.log('두 번째 조건은 불충족!');
  }
} else {
  console.log('첫 번째 조건 불충족!');
}

💻 개선 후

let first = true;
let second = false;

if (first && second) {	// first와 second 모두 true
  console.log('첫 번째 조건 충족!');
  console.log('두 번째 조건도 충족!');
} else if (first) {	// first만 true
  	console.log('첫 번째 조건 충족!');
    console.log('두 번째 조건은 불충족!');
} else {	// 둘 다 false
  console.log('첫 번째 조건 불충족!');
}



4.2 switch 문

  • 실행문 안에 식을 여러 개 둘 수 있으며, 중괄호 없이 사용 가능함
    let value = 'A';
    switch (value) {
      case 'A':
        console.log('A');
        console.log('B');
    }
  • default 는 위치 제한 없음
    let value = 'F';
    switch (value) {
      case 'A':
        'A';
        break;
      case 'B':
        'B';
        break;
      case 'C':
        'C';
        break;
      default:
        '어느 것도 일치하지 않음';
    }
    let value = 'F';
    switch (value) {
      default:
        '어느 것도 일치하지 않음';
        break;
      case 'A':
        'A';
        break;
      case 'B':
        'B';
        break;
      case 'C':
        'C';
    }



4.3 조건부 연산자

  • 조건문에서 대입하는 부분을 짧게 줄이기 위해 사용
  • 중첩 사용 가능

💻 기본

let condition1 = true;
let condition2 = false;

let value = condition1 ? condition2 ? '둘 다 참' : 'condition1만 참' : 'condition1이 거짓';
value;

< 'condition1만 참'

💻 가독성 향상 1 - 소괄호 연산자 사용

let value = condition1 ? (condition2 ? '둘 다 참' : 'condition1만 참') : 'condition1이 거짓';
value;

💻 가독성 향상 2 - 들여쓰기 사용

let value = condition1
	? condition2
		? '둘 다 참' : 'condition1만 참'
	: 'condition1이 거짓';
value;

5. 반복문

5.1 for 문

  • 시작, 조건식, 종료식 생략 가능
// 무한 반복
for (;;) {
}

6. 객체(object)

다양한 값을 모아 둔 값으로, 자료형의 일종


6.1 배열

6.1.1 생성

형식 : [값1, 값2, ...]

  • 대괄호([], 배열 리터럴)로 값들을 한꺼번에 감싸고, 각 값은 쉼표로 구분

  • 값의 자료형이 같지 않아도 됨

    const arrayOfArray = [[1, 2, 3], [4, 5]];
    arrayOfArray[0];
    < (3) [1, 2, 3]
    
    const a = 10;
    const b = 20;
    const variableArray = [a, b, 30];
    variableArray[1];
    < 20
  • 중복값 허용


6.1.2 요소 개수 구하기

형식 : 배열명.length

const everything = ['사과', 1, undefined, true, '배열', null];
everything.length;	// 6

✅ 원하는 위치의 요소 찾기

형식 : 배열명.at()

const findLastElement = ['a', 'b', 'c', 'd', 'e'];
findLastElement.at(4);	// e
findLastElement.at(-1);	// e
  • 인자가 0 또는 양의 정수면 배열의 에서부터, 인자가 음의 정수이면 배열의 마지막에서부터 요소를 찾음

6.1.3 요소 추가

  • 원하는 배열의 인덱스에 값 대입
    const target = ['a', 'b', 'c', 'd', 'e'];
    target[5] = 'f';
    target;	// (6) ['a', 'b', 'c', 'd', 'e', 'f']
    // 배열의 맨 뒤에 새로운 요소 추가
    const target = ['가', '나', '다', '라', '마'];
    target[target.length] = '바';
    target;	// (6) ['가', '나', '다', '라', '마', '바']

✅ 배열의 맨 앞에 요소 추가

형식 : 배열명.unshift()

const target = ['나', '다', '라', '마'];
target.unshift('가');
target;	// (6) ['가', '나', '다', '라', '마', '바']

✅ 배열의 맨 뒤에 요소 추가

형식 : 배열명.push()

const target = ['가', '나', '다', '라', '마'];
target.push('바');
target;	// (6) ['가', '나', '다', '라', '마', '바']

6.1.4 요소 수정

  • 원하는 인덱스에 변경할 값 대입

    const target = ['가', '나', '다', '라', '마'];
    target[3] = '카';
    target;	// (6) ['가', '나', '다', '카', '마']
  • 마지막 요소 수정 시 주의할 점

    const target = ['가', '나', '다', '라', '마'];
    target[target.length - 1] = '카';
    target;	// (5) ['가', '나', '다', '라', '카']
    • 배열명.at(-1) = 변경할 값으로는 수정 불가능
      • at()은 위치가 아닌 값을 나타내기 때문

6.1.5 요소 삭제

✅ 마지막 요소 삭제

형식 : pop()

const target = ['가', '나', '다', '라', '마'];
target.pop();
target;	// (4) ['가', '나', '다', '라']

✅ 첫 번째 요소 삭제

형식 : shift()

const target = ['가', '나', '다', '라', '마'];
target.shift();
target;	// (4) ['나', '다', '라', '마']

✅ 중간 요소 삭제

형식 : splice()

  • splice(<시작 인덱스>, <삭제할 요소의 갯수>)
    const target = ['가', '나', '다', '라', '마'];
    target.splice(1, 1);
    target;	// (4) ['가', '다', '라', '마']
    const target = ['가', '나', '다', '라', '마'];
    target.splice(2, 2);
    target;	// (3) ['가', '나', '마']
  • splice(<시작 인덱스>)
    • 해당 인덱스부터 배열 끝까지 모든 요소 삭제
    const target = ['가', '나', '다', '라', '마'];
    target.splice(1);
    target;	// (1) ['가']
  • splice(<시작 인덱스>, <삭제할 요소의 갯수>, <채울 값1>, <채울 값2>, ...)
    // 요소를 삭제 후 값을 채워 넣기
    const target = ['가', '나', '다', '라', '마'];
    target.splice(1, 3, '타', '파');
    target;	// (4) ['가', '타', '파', '마']
    // 요소 삭제 없이 값 추가
    const target = ['가', '나', '다'];
    target.splice(1, 0, '하');
    target;	// (4) ['가', '하', '나', '다']

6.1.6 요소 찾기

✅ 존재 여부 확인

형식 : 배열명.includes()

const target = ['가', '나', '다', '라', '마'];
const result1 = target.includes('다');
result1;	// true
const result2 = target.includes('카');
result2;	// false
  • 요소와 찾는 값의 자료형이 일치해야 함
  • || 연산자를 사용한 코드 개선에 유용
    const diff = '사과';
    diff === '바나나' || diff === '사과' || diff === '오렌지';	// true
    ['바나나', '사과', '오렌지'].includes(diff);	// true

✅ 위치 검색

const target = ['가', '나', '다', '라', '마'];
const result = target.indexOf('다');
result;	// 2

result = target.lastIndexOf('라');
result;	// 3

result = target.indexOf('카');
result;	// -1
메서드설명비고
indexOf()앞에서부터 검색
lastIndexOf()뒤에서부터 검색요소와 찾는 값의 자료형이 일치해야 함

6.1.7 배열 자르고 합치기

✅ slice()

형식 : 배열.slice(<시작 인덱스>, <종료 인덱스>)

  • 시작 인덱스부터 종료 인덱스까지 배열을 잘라 새 배열 생성
  • 시작 인덱스는 새 배열에 포함되나 종료 인덱스는 포함되지 않음
  • 인덱스가 음수면 뒤에서부터 실행
  • 종료 인덱스가 없으면 배열의 마지막 요소까지 모두 포함
  • 시작 인덱스가 없으면 처음부터 모두 포함
  • 인덱스 미지정 시 배열의 모든 요소 포함
['2', '3', '4', '5'].slice(1);	// (3) ['3', '4', '5']
['2', '3', '4', '5'].slice(1, 3);	// (2) ['3', '4']
['2', '3', '4', '5'].slice(2, 3);	// (1) ['4']
['2', '3', '4', '5'].slice(1, -1);	// (2) ['3', '4']
['2', '3', '4', '5'].slice();	// (4) ['2', '3', '4', '5']

✅ concat()

형식 : 배열.concat(값1, 값2, ...)

  • 두 배열을 합쳐 하나의 새로운 배열 생성
  • 배열 외에도 합성 가능
  • 여러 값을 넣으면 하나로 합쳐짐
  • 아무 값도 넣지 않으면 기존 배열과 같은 모양의 새로운 배열 생성
[1, 2].concat([3, 4]);	// (4) [1, 2, 3, 4]
[1, 2].concat(3, 4);	// (4) [1, 2, 3, 4]
[1, 2].concat([3, 4], [5, 6]);	// (6) [1, 2, 3, 4, 5, 6]
[1, 2].concat([3, 4], 5, 6);	// (6) [1, 2, 3, 4, 5, 6]
[1, 2].concat();	// (2) [1, 2]

6.1.8 문자열

✅ 문자열을 문자로 분리

형식 : 문자열[자릿수]

'hello'[0];	// 'h'
'hello'[1];	// 'e'

✅ 문자열의 길이 구하기

형식 : 문자열.length

'hello'.length;	// 5

✅ 문자 검색

  • 배열에서 사용했던 방법과 동일

✅ 배열 ↔ 문자열 변환

  • 배열 → 문자열 : join()

    ['1', '2', '3'].join();	// '1,2,3'
    ['1', '2', '3'].join('x');	// '1x2x3'
    ['1', '2', '3'].join('');	// '123' => '1' + '' + '2' + '' + '3'과 동일
  • 문자열 → 배열 : split()

    '2345'.split();	// ['2345']
    '2345'.split('x');	// ['2345']
    '2345'.split('');	// (4) ['2', '3', '4', '5']
    '2,3,4,5'.split('');	// (7) ['2', ',', '3', ',', '4', ',', '5']
    '2,3,4,5'.split(',');	// (4) ['2', '3', '4', '5']

✅ 배열 자르고 합치기

// slice()
'2345'.slice(1, 3) === '34';	// true
'2345'.slice(1, -1) === '34';	// true
'2345'.slice(1) === '345';	// true

// concat()
'23'.concat('45') === '2345';	// true
'23'.concat('4', '5') === '2345';	// true

// 인자가 배열일 경우, 배열에 join()이 적용되어 문자열로 바뀐 후 대상 문자열과 합침
'23'.concat(['4', '5']) === '234,5';	// true

6.1.9 flat()과 fill()

✅ flat()

  • 배열의 차원을 한 단계 낮춤 (n차원 → n-1차원)
const array1 = [[1, 2, 3], [4, 5, 6], [7, 8, 9]];
array1.flat();	// (9) [1, 2, 3, 4, 5, 6, 7, 8, 9];
const array2 = [1, 2, 3, [[4, 5, 6], [7, 8, 9]]];
array2.flat();	// (5) [1, 2, 3, (3) [4, 5, 6], (3) [7, 8, 9]];

✅ fill()

  • Array(길이) : 배열 생성
    const empty = Array(5);
    empty;	// (5) [empty x 5]
  • fill() : 빈 배열의 요소를 미리 특정 값으로 채워넣음
    empty.fill();	// (5) [undefined, undefined, undefined, undefined, undefined];
    empty.fill(1);	// (5) [1, 1, 1, 1, 1];

6.1.10 Set

  • 배열과 비슷하지만 중복을 허용하지 않는 객체
    new Set([1, 2, 1, 3, 3, 5]);	// Set(4) {1, 2, 3, 5}
    new Set('가가나나다다');	// Set(3) {가, 나, 다}
  • size : 요소 개수
    const a = new Set([1, 2, 1, 3, 3, 5]);
    a.size;	// 4
  • Set → 배열
    Array.from(new Set([1, 2, 1, 3, 3, 5]));	// (4) [1, 2, 3, 5]

❗ const를 수정할 수 있는 이유

const로 선언한 변수에 값이 아닌 객체(배열, 함수, 객체, 리터럴)가 대입되면 객체 내부의 속성이나 배열의 요소를 수정할 수 있음

const target = ['a', 'b', 'c', 'd', 'e'];
target = ['f', 'g'];	// 불가능
target[0] = 'h';	// 가능



6.2 함수(function)

  • 특정한 작업을 수행하는 코드

6.2.1 선언

✅ 익명 함수(anonymous function)

  • 이름이 없는 함수
  • 형식
    • function() {};
    • () => {};
  • 다른 곳에서 사용할 수 없음

✅ 함수 선언문(function declaration statement)

  • function 뒤에 함수의 이름을 넣는 방식
  • 형식 : function 이름() { 실행문 }

✅ 함수 표현식(function expression)

  • 함수를 상수나 변수에 대입하는 방식
  • 형식 : 이름 = function() { 실행문 }

✅ 화살표 함수(arrow function)

  • 화살표 기호를 사용한 함수
  • 형식
  • () => { 실행문 }
  • () => 반환식

6.2.2 반환값

  • 기본값 : undefined
  • return문을 추가하여 반환값 지정 가능
  • 다른 식이나 문에 넣어 사용 가능
  • 상수나 변수에 대입 가능
  • 함수의 실행을 중단하는 역할 수행
    • return 문 실행시 return 문 아래 코드는 실행되지 않음

6.2.3 매개변수와 인수

  • 매개변수와 인수를 여러 개 가질 수 있음

  • 매개변수와 인수의 개수가 일치하지 않아도 됨

    • 매개변수에 대응되는 인수가 없을 경우 자동으로 undefined 값 대입

    • arguments를 사용하여 인수의 개수 추정

      function a(w, x, y, z) {
        console.log(w, x, y, z);
        console.log(arguments);
      }
      
      a('Hello', 'Parameter', 'Argument');
      
      			< Hello Parameter Argument undefined
      Arguments(3) ['Hello', 'Parameter', 'Argument']
      • function으로 선언한 함수에서만 사용 가능
    • 매개변수의 개수가 인수보다 작을 경우, 대응되지 않는 인수는 버려짐


6.2.4 변수 사용

  • 스코프에 따라 접근 여부가 달라짐
  • 순수 함수(pure function) : 자신의 매개변수나 내부 변수(또는 상수)만 사용하는 함수

6.2.5 고차 함수 사용

✅ 매개변수 X

const func = () => {
  function () => {
    console.log('hello');
  };
}

const innerFunc = func();
// const innerFunc = () => {
//   console.log('hello');
// };

✅ 매개변수 O

const func = (msg) => {
  function () => {
    console.log(msg);
  };
}
// 함수 축약
// const func = (msg) => () => {
//   console.log(msg);
// };

const innerFunc1 = func('hello');
const innerFunc2 = func('javascript');
const innerFunc3 = func();

innerFunc1();
innerFunc2();
innerFunc3();

< hello
javascript
undefined	// 빈 값은 undefined



6.3 객체 리터럴(object literal)

  • 객체 : 여러 변수를 하나의 변수로 묶을 때 사용
  • 객체 리터럴 : 중괄호를 사용해 객체를 표현하는 것

6.3.1 객체 생성

  • 변수를 선언한 후 정보를 모아 중괄호({})로 묶어 변수에 대입
  • 형식
    {
      <속성1 이름>: <속성1>,
      <속성2 이름>: <속성2>,
      <속성3 이름>: <속성3>,
      ...
    }

6.3.2 객체 속성 접근

6.3.2.1 방식

✅ 마침표(.)

  • 형식 : 변수.속성
    const zerocho = {
      name: '조현영',
      year: 1994,
      month: 8,
      date: 12,
      gender: 'M',
    };
    zerocho.name;
    < '조현영'
    zerocho.date;
    < 12

✅ 대괄호([])

  • 형식 : 변수['속성']
    const zerocho = {
      name: '조현영',
      year: 1994,
      month: 8,
      date: 12,
      gender: 'M',
    };
    const name = 'date';
    zerocho['name'];
    < '조현영'
    zerocho.[name];	// zerocho.['date']와 같은 의미
    < 12

6.3.2.2 참고

  • 객체에 존재하지 않는 속성에 접근 시 undefined 출력

  • 대부분 마침표를 사용해 속성에 접근

  • 속성 이름에 띄어쓰기나 마침표가 들어 있는 경우 []를 사용해 속성에 접근

  • 속성으로 변수를 가질 수 있음

    const name = '조현영';
    const year = 1994;
    const zerocho = {
      name: name,
      year: year,
    };
    // 위의 형식을 다음과 같이 축약 가능
    // const zeroch = { name, year };
    
    zerocho.name;	// 조현영
    zerocho.year;	// 1994

6.3.3 객체 속성 추가/수정/삭제

✅ 추가/수정

  • 형식 : 변수.속성 = 값;
    zerocho.married = false;	// false
    zerocho.married;	// false
    zerocho.married = true;
    zerocho.married;	// true

✅ 삭제

  • 형식 : delete 변수.속성;
    zerocho.gender = 'F';
    delete zerocho.gender;
    zerocho.gender;	// undefined;

6.3.4 메서드(method)

  • 객체의 속성 값으로 사용되는 함수
const debug = {
  log: function(value) {
    console.log(value);
  },
}
// 축약
// const debug = {
//   log(value) {
//     console.log(value);
//   }
// }

debug.log('Hello, Method');

6.3.5 객체 간 비교

  • 형식 : ({} === {});

    💡 객체 비교 시 소괄호로 감싸는 이유
    자바스크립트에서의 중괄호({})가 객체 리터럴뿐만 아니라 블록 문(Block Statement)을 의미하기 때문

  • 객체는 모양이 같아도 생성할 때마다 새로 생성됨

  • 기존 객체를 변수에 저장해야 같은 객체인지 비교 가능

    const a = { name: 'zerocho' };
    const array = [1, 2, a];
    a === array[2];	// true

💡 [참고] NaN끼리 비교했을 때 false가 나오는 이유


6.3.6 중첩된 객체와 옵셔널 체이닝 연산자

6.3.6.1 중첩 객체

  • 속성 값으로 다른 객체를 넣음

✅ 예시 1 - 객체 내 객체

const zerocho = {
  name: {
    first: '현영',
    last: '조',
  },
  gender: 'm',
};

zerocho.name.first;	// '현영'
zerocho['name']['first'];	// '현영'
zerocho['name'].first;	// '현영'
zerocho.name['first'];	// '현영'

✅ 예시 2 - 객체 내 배열

const family = [
  { name: '제로초', age: 29, gender: '남' },
  { name: '레오', age: 5, gender: '남' },
  { name: '체리', age: 3, gender: '여' },
];

6.3.6.2 옵셔널 체이닝 연산자(optional chaining operator)

  • ?. : 존재하지 않는 중첩 객체의 속성에 접근 시 에러가 발생하는 것을 막아주는 연산자
// 객체 내 속성 접근
zerocho.girlfriend?.name;	// undefined
zerocho.name?.first;	// '현영'

// 메서드 접근
zerocho.sayHello?.();	// undefined

// 배열 요소 접근
zerocho.girlfriend?.[0];	// undefined

6.3.7 참조와 복사

6.3.7.1 참조(reference)

같은 객체를 가리키고 있는 경우

const a = { name: 'zerocho' };
const b = a;
b.name;	// 'zerocho'
a.name = 'hero';
b.name;	// 'hero'

  • a와 b가 같은 객체를 참조하고 있다
  • 변수 a와 b 그리고 객체 간에 참조 관계가 있다

6.3.7.2 복사(copy)

어떤 값을 다른 변수에 대입할 때 기존 값과 참조 관계가 끊기는 경우

let a = 'zerocho';
let b = a;
a = 'hero';
b;	// 'zerocho'

  • 객체가 아닌 값은 참조 관계가 없으므로 복사만 가능

6.3.7.3 객체 복사

✅ 얕은 복사(shallow copy)

외부 객체만 복사되고 내부 객체는 참조 관계를 유지하는 복사

  • 스프레드 문법(spread syntax)

    • ... 연산자

    • 기존 객체의 속성을 새 객체에 대입할 때 사용

    • 형식

      // 배열
      [...배열]
      
      // 객체
      {...객체}`
const array = [{ j: 'k' }, { l: 'm' }];
const shallow = [...array];	// 얕은 복사
console.log(array === shallow);	// false
console.log(array[0] === shallow[0]);	// true

const shallow2 = array.slice();	// 얕은 복사
const shallow3 = array.concat();	// 얕은 복사
console.log(array === shallow2);	// false
console.log(array[0] === shallow2[0]);	// true
console.log(array === shallow3);	// false
console.log(array[0] === shallow3[0]);	// true

✅ 깊은 복사(deep copy)

내부 객체까지 참조 관계가 끊기는 복사

const array = [{ j: 'k' }, { l: 'm' }];
const deep = JSON.parse(JSON.stringify(array));	// 깊은 복사
console.log(array === deep);	// false
console.log(array[0] === deep[0]);	// false


6.3.8 구조분해 할당(destructuring assignment)

객체에서 객체의 속성 이름과 대입하는 변수명이 같을 때 축약할 수 있는 방법

  • 여러 속성을 한 번에 변수에 대입할 때 유용

✅ 예시 1

const person = { name: '제로초' };
// const name = person.name;
const { name } = person;	// 앞 줄과 같은 의미
name;	// '제로초'
const obj = { a: 1, b: 2 };
// const a = obj.a;
// const b = obj.b;
const { a, b } = obj;
a;	// 1

✅ 예시 2 - 배열

const array = [1, 2, 5];
// const one = array[0];
// const two = array[1];
// const five = array[2];
const { one, two, five } = array;
two;	// 2
// 변수 a와 b의 값을 교환
let a = 5;
let b = 3;
[b, a] = [a, b];	// (2) [5, 3]

6.3.9 유사 배열 객체(array-like object)

  • 배열 모양을 한 객체
const array = {
  0: 'hello',
  1: 'I\'m',
  2: 'Object',
  length: 3,
}
array[0];	// 'hello'
array[1];	// "I'm"
array[2];	// 'Object'
array.length;	// 3
array.push(1);	// Uncaught TypeError: array.push is not a function
  • 배열이 아니므로 배열 메서드를 사용할 수 없음
Array.from(array).indexOf('hello');	// 0
  • Array.from() 메서드를 사용하여 유사 배열 객체를 배열로 변경 후 배열 메서드 사용 가능

❗ 배열과 함수가 객체인 이유

  • 객체의 성질을 모두 사용할 수 있음
  • 객체 리터럴은 중괄호({})를 사용해 만든 객체를 구분하기 위해 지칭하는 단어



6.4 함수를 인수로 받는 배열 메서드

6.4.1 forEach() 와 map()

6.4.1.1 forEach()

  • 배열에서 제공하는 메서드 중 반복문 역할을 수행하는 메서드

  • 형식 : 배열.forEach(함수)

    const arr = [1, 5, 4, 2];
    arr.forEach((number, index) => {
      console.log(number, index);
    });
    
    1 0
    5 1
    4 2
    2 3
    • 인수로 받은 함수를 배열 요소에 각각 적용

💻 예시 1

(number, index) => {}

💻 예시 2

const arr = [1, 5, 4, 2];
arr.forEach((v, i) => {
  console.log(v, i);
});

💻 예시 3

const arr = [1, 5, 4, 2];
arr.forEach((v) => {
  console.log(v);	// 1, 5, 4, 2
});
arr.forEach((v, i) => {
  console.log(i);	// 0, 1, 2, 3
});
  • 미사용 매개변수 생략
  • 요소의 인덱스를 사용하는 경우 배열의 요소를 가리키는 매개변수 사용 필요
    • 요소의 인덱스가 두 번째 매개변수로 고정되어 있기 때문

💡 콜백 함수(callback function)

  • 다른 메서드에 인수로 넣었을 때 실행되는 함수

  • 매개변수

    위치설명
    첫 번째배열의 요소
    두 번째요소의 인덱스
    • 매개변수의 이름은 자유롭게 작명 가능

6.4.1.2 map()

  • 배열 요소들을 일대일로 짝지어서 다른 값으로 변환해 새로운 배열을 변환하는 메서드
  • 형식 : 배열.map(<콜백 함수>);

💻 예시 1

const numbers = [];
for (let n = 1; n <= 5; n += 1) {
  numbers.push(n);
}
numbers;	// (5) [1, 2, 3, 4, 5]

💻 예시 2

// 반환값을 이용하여 배열의 요소 변경
const numbers = Arrays(5).fill(1).map((v, i) => i + 1);
numbers;	// (5) [1, 2, 3, 4, 5]

💻 예시 2

// 요소를 사용하여 새로운 배열 생성
const array = [1, 3, 5, 7];
const newArray = array.map((v, i) => {
  return v * 2;
});
console.log(array);	// (4) [1, 3, 5, 7]
console.log(newArray);	// (4) [2, 6, 10, 14]

6.4.2 find(), findIndex(), filter()

6.4.2.1 find()

  • 콜백 함수의 반환값이 true인 요소를 찾는 메서드

  • 형식 : 배열.find(<콜백 함수>);

  • true인 요소가 여러 개인 경우 처음 찾은 요소 반환

    const array = [1, 3, 5, 7];
    array.find((v, i) => {
      return v > 1;
    });
    
    < 3
  • 배열 내부 객체 검색 시 유용

    const nested = [{ age: 29 }, { age: 5 }, { age: 3 }];
    nested.includes({ age: 29 });	// false
    nested.find((v) => v.age === 29);	// { age: 29 }

6.4.2.2 findIndex()

  • 찾은 요소의 인덱스를 반환하는 메서드
  • 형식 : 배열.findIndex(<콜백 함수>);
  • 검색 실패 시 -1 반환
const array = [1, 3, 5, 7];
array.findIndex((v, i) => {
  return v > 1;
});	// 1

6.4.2.3 filter()

  • 콜백 함수의 반환값이 true가 되는 요소를 찾는 메서드
  • 형식 : 배열.filter(<콜백 함수>);
  • 해당하는 모든 요소를 찾아 결과를 배열로 반환
[1, 2, 3, 4, 5].filter((v) => v % 2 === 0);	// (2) [2, 4]

const nested = [{ age: 29 }, { age: 5 }, { age: 3 }];
nested.filter((v) => v.age < 29);	// (2) [{ age: 5 }, { age: 3 }]

6.4.3 sort()

  • 비교 함수의 반환값에 따라 배열을 정렬하는 메서드
  • 형식 : 배열.sort(<비교 함수>);
    • 비교함수 : (a, b) => 반환값
      • a - b : 오름차순 정렬
      • b - a : 내림차순 정렬
  • 원본 배열 정렬

6.4.4 reduce()

  • 배열의 요소들을 하나의 값으로 합치는 반복 메서드
  • 형식
    배열.reduce((<누적 값>, <현재 값>) => {
      return <새로운 누적 값>;
    }, <초기 값>);

💻 예시 1

[1, 2, 3, 4, 5].reduce((a, c) => {
  return a + c;
}, 0);	// 15

💻 예시 2

[1, 2, 3, 4, 5].reduce((a, c) => {
  return a + c;
});	// 15
  • 초기 값 미제공 시 첫 번째 요소의 값이 초기값이 됨

6.4.5 every()와 some()

every()some()
역할배열에서 모든 요소가 조건에 해당하는지 판단하는 메서드배열에 있는 요소 중 하나라도 조건에 해당하는지 판단하는 메서드
형식배열.every(<조건 함수>);배열.some(<조건 함수>);
특징하나라도 조건을 만족하지 않는 요소를 찾으면 반복 중단하나라도 조건을 만족하는 요소를 찾으면 반복 중단

7. 클래스(class)

  • 객체를 생성하기 위한 템플릿(서식)
  • 속성과 메서드를 한데로 모아 관리의 효율성을 향상시킬 수 있음

7.1 함수로 객체 생성

7.1.1 공장 함수(factory function)

  • 객체를 반환하는 함수
  • 공장처럼 객체를 찍어낸다고 해서 붙은 이름
  • 새로운 객체가 필요할 때마다 함수 호출
function createMonster(name, hp, att) {
  return { name, hp, att };
}
const monster1 = createMonster('슬라임', 25, 10);
const monster2 = createMonster('슬라임', 26, 9);
const monster3 = createMonster('슬라임', 25, 11);

7.1.2 생성자 함수(constructor function)

  • 함수 이름 앞에 new를 붙여 호출하는 함수
    • 해당 키워드를 붙여 호출할 때마다 새로운 객체 생성
  • 이름은 보통 대문자로 시작
function createMonster(name, hp, att) {
  this.name = name;
  this.hp = hp;
  this.att = att;
}
const monster1 = new createMonster('슬라임', 25, 10);
const monster2 = new createMonster('슬라임', 26, 9);
const monster3 = new createMonster('슬라임', 25, 11);
  • this : 새롭게 생성된 객체

7.1.3 프로토타입(prototype)

  • 생성자 함수로 생성한 객체가 공유하는 속성
  • 생성자 함수에서 메서드를 재사용하기 위한 방법
    • prototype 속성 안에 메서드를 추가하여 사용

  • 객체 내부 [[prototype]] 속성 내부에 attack() 메서드 존재
  • 생성자 함수로 생성한 객체는 앞에 생성자 함수의 이름이 붙음



7.2 this

7.2.1 window 객체

💻 예시 1

function a() {
  console.log(this);
}
a();	// window {}

💻 예시 2

function Monster(name, hp, att) {
  this.name = name;
  this.hp = hp;
  this.att = att;
}
const monster = Monster('슬라임', 25, 10);
  • window 객체의 name, hp, att 수정

7.2.2 객체 메서드

  • 해당 객체를 가리키는 키워드로 사용
  • 형식 : 객체.메서드() - 필수
const b = {
  name: '제로초',
  sayName() {
    console.log(this === b);
  }
};
b.sayName();	// true
  • 메서드에 구조분해 할당을 적용할 경우는 제외
const { sayName } = b;
sayName();	// false

7.2.3 bind()

  • 자바스크립트에 내장된 메서드
  • 역할 : this 수정

💻 예시 1 - 함수 선언문

const obj = { name: 'zerocho' };
function a() {
  console.log(this);
}
a.bind(obj)();	// { name: 'zerocho' }

💻 예시 2 - 화살표 함수

const b = () => {
  console.log(this);
}
b.bind(obj)();	// window
  • 화살표 함수는 기존 this 유지

7.2.3 new

  • 생성자 함수 호출 시 앞에 new를 붙일 경우, this는 생성자 함수가 새로 생성하는 객체가 됨



7.3 클래스로 객체 생성

✅ 형식

class <클래스 이름> {
  constructor(매개변수1, 매개변수2, ...) {
    // 생성자 함수 내용
  }
}
  • 클래스 내부에 선언된 함수 → 메서드

💻 예시

class Monster {
  constructor(name, hp, att) {
    this.name = name;
    this.hp = hp;
    this.att = att;
  }
}

const monster1 = new Monster('슬라임', 25, 10);
const monster2 = new Monster('슬라임', 26, 9);
const monster3 = new Monster('슬라임', 25, 11);
  • 객체의 속성과 메서드를 하나로 묶어서 사용할 수 있음
class Monster {
  constructor(name, hp, att) {
    this.name = name;
    this.hp = hp;
    this.att = att;
  }
  attack(monster) {
    monster.hp -= this.att;
  }
}



7.4 클래스 상속

✅ 정의

  • 공통되는 부분을 가진 클래스를 만들고, 새로운 클래스에서 공통되는 부분만 가져와 사용하는 방법
클래스설명
부모 클래스공통부분을 모아 만든 클래스
자식 클래스상속받는 클래스

✅ 형식

class <자식 클래스> extends <부모 클래스> {
  constructor(매개변수1, 매개변수2, ...) {
    super(인수1, 인수2, ...);	// 부모 클래스의 생성자 호출
    this.매개변수 =;	// 자식 클래스만의 속성
  }
  메서드() {	// 부모 클래스의 메서드만 호출 시 생략 가능
    super.메서드();	// 부모 클래스의 메서드 호출
    // 부모 클래스 메서드 호출 이후의 동작
  }
  메서드(매개변수1, 매개변수2, ...) {
      // 자식 클래스만의 동작
  }
}
  • 부모와 하는 일이 같다면 메서드 생략 가능
class Unit {
  constructor(name, hp, att) {
    this.name = name;
    this.hp = hp;
    this.att = att;
  }
}

class Monster extends Unit {}
new Monster('슬라임', 29, 8);

📖 참고

  • 조현영(제로초), 『코딩 자율학습 제로초의 자바스크립트 입문』, 길벗(2024), p40-198.
profile
기쁘게 코딩하고 싶은 백엔드 개발자

0개의 댓글