메가바이트스쿨 프론트엔드 4기 4주차 - Javascript 기초

임성열·2023년 1월 9일

메가바이트스쿨

목록 보기
4/13
post-thumbnail

4주차 배운 내용

자바스크립트 자료형과 함수의 활용을 배웠습니다.

자바스크립트의 특징

자바스크립트는 객체지향의 싱글스레드 언어라고 검색해보면 나온다.

객체지향(Object Oriented Programming 또는 OOP)이란 말은 주체지향의 반대라고 보면 편하다.
구현하고자 하는 기능을 코딩할 때, 한 줄 한 줄이 주체적으로 동작하는 것이 아니라 하나의 개념 또는 객체(object)로 묶어서 공통된 부분을 만들어 중복되는 동작을 묶어 작성하는 구조이다.

싱글스레드는 한 번에 한 작업씩 수행한다고 생각하면 된다. 스레드(Thread)는 하나의 프로세스를 하는 구분 단위 같은 것이고, 싱글스레드면 한 프로세스만 작업한다는 말이다. 멀티스레드라면 서버 요청과 같이 여러 프로세스를 동시다발적으로 수행하는 것을 말한다.

객체지향의 경우에는 우리가 코딩을 하는 방법론에 가까운 형태이므로, 건물을 지을 때의 설계도의 형식을 바라보는 관점이라면, 싱글스레드의 경우에는 우리가 건물을 지을 방법을 인식하는 관점이라고 생각한다.

이 외에도 자바스크립트의 특징은 세부적으로 여러 구조를 지닌다.

1. 자바스크립트의 구조

개념들

들어가기에 앞서 스택(Stack)과 큐(Queue)의 개념과 비동기성에 대해 이해할 필요가 있다.

  1. 스택
    스택은 한국어로 쌓다를 뜻한다. 스택 구조 역시 쌓이는 개념이다.


    위의 그림과 같이 제일 마지막에 쌓인 요소부터 접근할 수 있다.


  1. 큐는 줄을 서는 행위를 뜻한다. 선착순의 개념과 같다.

  2. 비동기성
    자바스크립트에서는 동기적인 프로세스와 비동기적인 프로세스로 나누어 동시성을 달성한다. 동기적이라 함은 자바스크립트 엔진 내에서 수행할 프로세스를 말하고, 비동기는 엔진 외적으로 요청하는 작업을 말한다.

내부 구조

위 그림을 살펴보면 다음과 같은 요소들이 있다.
1. 자바스크립트 엔진 내의 요소(노란 점선 안쪽)

  • 힙 또는 메모리힙: 사용자의 동적 할당을 위한 저장 공간이다. 객체나 배열과 같이 할당량이 언제든 동적으로 변하는(Mutable) 자료형을 저장한다.
  • 콜스택: 스택 메모리에는 변하지 않는(Immutable) 자료형인 원시형을 저장하고 수행할 작업을 한 번에 한 작업씩 수행한다.

2 브라우저 Runtime 환경 또는 Node.js내의 요소

  • Web APIs: 웹 엔진에서 제공되는 요소들이다. 자세한 건 잘 모르겠고, 웹페이지를 구성할 때 자바스크립트와 연동하여 제공되는 요소와 기능(DOM이나 setTimeout function같은)을 모아둔 것 같다.
  • 콜백 큐: 비동기적 요청 수행이 완료되면 큐 방식으로 완료 후 작업할 요소를 줄 세운다.
  • 이벤트루프: 콜스택이 비어있을 때만 콜백 큐의 작업 요소를 넣어주는 역할을 한다.

간단하게 생각하면,

배달의 민족 주문(비동기)을 미리 해두고,
할 거(동기) 다 하고 있다가,
배달원(이벤트루프)이 도착하면,
초인종(스택이 비었는지 확인)을 누르고,
배달음식(콜백 큐 요소)을 건내 받아서,
밥을 먹는(동기) 행위와 비슷하다.

2. 자료형

자료형은 크게 원시형과 참조형으로 나눌 수 있으며,
원시형은 자료의 원형을 담고,
참조형은 원형을 묶어서 각 원시형이 담긴 주소를 참조하는 식이다.

1. 원시형의 불변성

원시형의 경우 선언되면 그 값은 변하지 않는다. 다만 값이 저장된 곳의 주소를 바꾸는 방식을 쓴다.
예를 들어, 아래와 같은 가상의 주소록이 존재한다고 하자.

let 영희네주소 = 486
let 우리집주소 = 114

영희네주소 = 우리집주소 
console.log(우리집주소) // 486

이 때, 영희네집주소 값을 완벽히 복사한다기 보다는 영희네집주소 값인 486가 저장된 주소를 가리키게 된다(그래서 이를 얕은 복사(shallow copy)라고 부른다). 주소록에 등록된 주소만 바꾼다고 영희네집이 우리집이 되지 않는 것과 같다.

스택에 남아있는 114라는 값은 다른 변수가 114로 할당될 때 재사용 된다. 하지만, 사용하지 않을 경우 아무도 가리키고 있지 않기 때문에 Garbege Collector라는 자바스크립트 내장 기능이 없애준다.

또한 아래와 같이 집주소를 변경하면 우리집 주소도 같이 바뀐다.

영희네주소 = 112

console.log(우리집주소) //112
console.log(우리집주소 === 112) //true

참조형은 여러 원시값 또는 객체값을 묶어서 포함한 형태로, 여러 주소록을 묶어 하나의 책으로 만들어 놓은 형태라고 생각하면 편하다.

참조형이 선언되면 원시형 값만을 지닌 변수와 다르게 객체의 경우 프로퍼티 내의 값이 변할 수 있다(다른 변수로 바뀐다던지).

이러한 특성 때문에 자료를 복사 또는 수정 하는데에도 값과 주소의 구분이 명확히 필요해진다.

2. 깊은 복사(deep copy)와 얕은 복사(shallow copy)

  1. 얕은 복사
    아래는 원본 객체가 저장된 힙의 주소값을 사본이 가리키게 되었는데, 문제는 주소값을 복사 하였기 때문에 사본에서 프로퍼티에 접근하여 주소값의 재할당이 가능하다.

    const 원본 = {
      우리집주소: 123,
      영희네주소: 486,
      철수네주소: '경기도 안양시 무슨동'
    }
    //Shallow copy
    let 사본 = 원본 // 원본이 저장된 주소를 가리키게 됨
    
    사본.우리집주소 = 112
    
    console.log(원본.우리집주소) // 123이 아닌 112로 변경됨
  2. 깊은 복사
    깊은 복사는 주소값 뿐만 아니라 프로퍼티의 값 자체도 복사해오는 경우이다. 이 경우 원본에 영향이 가지 않지만, 방법에 따라 단점이 따라온다.

    const 원본 = {
      우리집주소: 123,
      영희네주소: 486,
      철수네주소: {
        전체주소: '경기도 안양시 무슨동'
      }
    }
  • JSON.stringify()JSON.parse()
    함수를 복사할 수 없다.
    사본 = JSON.parse(JSON.stringify(user))
  • Object.assign()
    중첩된 하위 데이터를 복사할 수 없다.
    사본 = Object.assign({}, 원본)
  • ... Spread Operator
    중첩된 하위 데이터를 복사할 순 있는데 손이 좀 간다.
    사본 = {
        ...사본,
      영희네주소: 486,
      철수네주소: {
        ...사본.철수네주소,
        전체주소: '경기도 안양시 무슨동'
      }
    }
  • -.cloneDeep() Lodash
    간편하게 다 깊은 복사가 되지만, 개발 의존성이 생긴다.

3. 원시형

자료형비고
String'', "",``문자가 연속된 문자열이다 배열처럼 취급할 수 있다
NumberInteger정수를 표현할 때 사용한다
Float소수점을 표현할 때 사용한다
NaNNot a Number의 약어로 숫자와 숫자가 아닌 값의 연산을 표현할 때 사용한다
BigInt2^53 - 1보다 큰 수를 표현할 때 사용한다
Booleantrue or false참과 거짓을 표현할 때 사용한다
Symbolkey유일한 key값을 가진다
undefinedundefined암시적(자동적)으로 정의 되지 않은 값이다
nullnull명시적(임의적)으로 정의 하지 않은 값이다

4. 표준 내장 객체 메서드(Method)

가장 가벼운 할당량을 가지는 원시형 자료를 보다 손쉽게 사용하기 위해 고안된 부분으로 구조는 아래와 같다

  1. 원시형 자료에 메서드를 호출한다.
  2. 일시적으로 래퍼 객체를 생성하여 객체 내에서 함수 호출로 명령을 처리한다.
  3. 명령이 종료된 후 일시적으로 생성되었던 래퍼 객체는 사라진다.
  4. 원시형 자료는 그대로 있다.

대표적인 예시로 String.prototype.toUpperCase()Number.prototype.toFixed()가 있다.

5. 형변환

자바스크립트에서는 함수나 연산자로 전달되는 자료의 자료형을 암시적으로 변환할 수 있고, 이에 따른 동등연산자 평가를 Truthy/Falsy로 나누기도 한다.

자료형변환
String'', "" , ``false, 0
String'Some Value'true, 1
String'123'true, 숫자 123
Booleanfalse or true0 or 1
undefinedundefinedfalse
nullnullfalse
{}, []empty prop, arrtrue
0, -0, 0nzero and zero BigIntfalse
infinityinfinitytrue

6. 참조형

  1. 배열(Array)

    • 자바스크립트에서 배열은 순서가 있는 목록이다. 순서를 index라고 하며 0부터 시작해서 목록의 길이의 -1의 끝을 가진다.
    • 아무것도 넣지 않은 배열은 길이가 0이며 내용물은 undefined를 반환한다.
  2. 객체(Object)

    • 객체란 순서가 없이 이름표만 달린 목록이다. 이 이름표를 key라고 부르고, 이것으로 반환받은 값을 value라고 부른다. 그리고 key와 value의 쌍을 property라고 부른다.
    • 자바스크립트에서는 객채의 이러한 구조로 함수의 이름을 key로, 함수의 기능을 value로 지정할 수도 있다.

3. 변수와 상수

자바스크립트의 선언 방식에는 var, let, const가 있다.

var가 가장 먼저 만들어 졌지만, 전역 변수로 선언되고, 호이스팅도 되고, 되는게 너무 많아서 무질서해지거나 아리송해지는 코드들이 많아서 이제는 let과 const만 쓴다고 한다.

var를 쓰는 경우는 강사님 말로는 일평생 드물 것이며, 굉장히 오래된 레거시 코드를 수정/보완 하는 작업이 아닌 이상 보기 힘들 것이므로 그냥 쓰지말라고 했다.

let은 주소값이 변해도 되는 변수이고, const는 주소값이 변하지 못하는 상수(Constant)이다.

4. 함수

1. 콜백함수

자바스크립트에서 함수는 객체(Object)와 같은 취급을 받으며, 함수에 매개변수로 전달이 가능하다. 이를 고차 함수이자 콜백함수라고 한다.

console.log(덧셈(1, 1, 곱셈)) // 2

function 덧셈(x, y, 곱셈) {
  x = x + y // x = 2
  곱셈(x, y) // 곱셈(2, 1)
}
function 곱셈(x, y) { //콜백함수
  return x * y // 2 * 1 반환
}

자바스크립트에서 콜백함수를 쓸 일은 무척이나 많다. 코드 재사용 면에서도 그렇고, 특히나 비동기 작업을 할 때 요청이 끝나면 그 다음 작업을 미리 지시하는 용도로 사용된다.

단점은 콜백지옥이 생성될 수 있으나, 이를 완화하기 위한 Promise의 then,catch 이다. 그러나, 코드가 가로로 길어지면서 가독성이 떨어져서 async, await 등이 도입되었다고 한다.

힘찬 콜백지옥

2. for문

데이터 구조가 커지면 이를 배열화 또는 객체화 하는 것이 효율적이고, 이러한 구조에서는 항상 반복 작업이 많기 때문에 자바스크립트에 내장되어있는 문법이다.

  • for
    for ( let index = 0; i < 배열.length; i ++) {
      배열[index].작업()// index를 통해 접근 가능
    }
    index는 0 부터 배열의 길이만큼 변하기 때문에 let으로 한다.
  • for of(배열 순환 시)
    for ( let item in 배열 ) {
      item.작업() // 배열 내의 item에 순서대로 작업 가능
    }
  • for in(객체 순환 시)
    for ( let property in 객체 ) {
      property.작업() //객체 내의 property에 접근하여 작업을 수행 가능
    }
  • for of과 for in의 차이
    for of는 배열에 사용하는 용도이며 객체로 사용하면 TypeError가 나온다.
    대신 for in에 배열을 넣으면 되긴 하는데 index만 나온다.

3. .foreach, .map, 그리고 .filter

자바스크립트 표준 내장 Array객체 메서드들이고, 자주 쓰인다.
모두 매개 변수(parameter)로 콜백함수를 받는다.

  • .foreach
    배열.foreach( function (item) {
      item.작업() 
    }
  • .map
    const 새배열 = 기존배열.map( function (item) {
      return // 새로 만드는 작업 후 새 배열 반환
    }
  • .filter
    const 새배열 = 기존배열.filter( function (item) {
    	return  // 필터링할 작업 후 새 배열 반환
    }
    .foreach는 동작의 개념만 있는데 반해 .map.filter는 새로운 배열을 반환한다.

4. 함수선언식과 함수표현식

함수선언식

function 함수이름 (매개변수) {
     //작업할 내용
}

함수표현식

const 함수이름 = function (매개변수) {
     //작업할 내용
}

함수 표현식의 경우 아래처럼 콜백함수로 사용할 수 있어서 쓴다고 한다.

function 내함수 (내매개변수) {
  return function 콜백함수(내매개변수) {
    // 내 매개변수를 콜백함수에서 접근 가능하다.
  }
}

5. 호이스팅

호이스팅이란 자바스크립트가 처음 코드를 읽어들일 때 전역 변수와 함수를 먼저 읽어들이는 것을 말한다.

함수 선언식과 표현식의 차이도 여기서 나타난다. 선언식의 경우 호이스팅이 되지만 표현식의 경우에는 호이스팅이 되지 않는다.

5. 동기와 비동기

1. Promise

Promise란 자바스크립트 비동기 처리를 위해 사용되는 객체로, 비동기적 처리의 특성상 혼자 따로 놀기 때문에 이것이 꼭 실행될 것이라고 약속하는 개념이라고 보면 된다.

코드로 보면,

new Promise() // Pending 입니다

function promise () {
  return new Promise( function ( resolve, reject ) {
  resolve(); // Fulfilled 되면 알려주세요
  reject(); // Rejected 되면 Error 주세요
	}
}
                    
promise() //Promise가 return 되면
  .then( () => {
    // 정상작동(resolve) 했을 경우 작업을 수행해 주세요
  })
  .catch( () => {
    reject(); // 문제발생(reject)시에는 ...
  })

2. fetch()

fetch()는 보통 API에 요청할 때 사용한다.
return값이 Promise이며 다음과 같이 동작 가능하다.

fetch(API_URL) //Promise가 리턴되면
    .then( (response) => {
        //response가 정상적으로 온 걸로 작업을 수행해 주세요
    })
    .catch( (response) => {
        //문제발생(reject)시에는 ...
    })

3. async/await

비동기적 함수를 명시적으로 표현해주는 표준 내장 기능이다. asynchronous 의 약어인 async, 기다리다라는 뜻의 영어인 await로 이해할 수 있으며 await는 항상 async 안에서만 존재할 수 있다는 것과 await는 항상 Promise 객체를 반환한다.

코드로 보면 아래와 같다.

async function 비동기함수 () {
 let response = await fetch (API_URL) //응답을 기다려 주세요
 let respondedData = await response.json() //받은 응답을 json으로 바꿔주세요.
}

마치며

저번 주에 왼쪽 팔 부분 골절과, 우측 손목 인대 부상으로 오른손가락 네 개로 코딩하다보니 힘들어서 2차 공통과제 코딩은 간간히만 했다. 사실 개인 블로그 작성이 제일 난제였다. 결국 과제는 아직 진행중이지만, 개인 블로그 작성은 어찌저찌 했다.

그래도 그동안, 자바스크립트 학습에 비중을 쏟게 되서 그런지 막상 과제를 본격적으로 하려고 하니 도움이 더 많이 된다.

자바스크립트는 HTML, CSS처럼 손에 익히는 느낌과 다르게 구조적인 이해와 사고 능력을 우선 요구하는 것 같다. 이해하기 전과 후의 코딩 속도가 다르다.

이렇게 보면 더 크게 다치지도 않았고, 사실 운이 좋았던게 아닌가 싶다.

0개의 댓글