본문 바로가기

개발/프로그래머스 데브코스

프로그래머스 데브코스 47일차 with. TS 웹 풀스택

📚요약

지난 시간에 이어서 JS의 기본적인 내용을 학습합니다. 그리고 배운 것을 바탕으로 간단하게 가계부를 만들어 보겠습니다.

 

📖JS

📄Flow Control

  • goto : 다른 구문에서 시작
  • choice(조건문) : if...else, switch
  • loop(반복문) : collection loop(for...in, for...of), general loop(for), conditional loop(while, do...while)
  • continue : loop continuation(continue)
  • break : loop early exit(break), 함수 실행 정지(return)
  • non-local control flow : try...catch, throw, generator, async
🍯tip! 조건문 작성 시 참고 요령으로 nested conditional은 지양하고 guard clauses 형태로 구현하는 것이 좋다.
// nested conditional
if(조건문) {
  return 1;
} else {
  if(조건문2) {
  	return 2;
  }
}
return 3;

// guard clauses
if(조건문) return 1;
if(조건문2) return 2;
return 3;

 

📄표현식(Expression) vs 문(Statement)

표현식이란 어떤 값으로 이행되는 임의의 유효한 코드 단위로 값으로 평가될 수 있는 문을 말합니다.

 

문은 프로그램을 구성하는 기본 단위이며 최소 실행 단위입니다. 조건문, 선언문, 반복문, 할당문, 블록문 등 다양하게 있습니다.

🍯tip! JS에서 항상 false로 평가되는 값들이 존재합니다. false, undefined, null, 0, NaN, ""(empty string)이 그 값들입니다.

 

📄예외 처리

예외(Exception)는 런타임 때 발생하는 의도하지 않은 상황을 의미합니다. 예외는 코드 문제, 하드웨어나 장치의 문제, 입력 실수 등 다양한 상황이 존재합니다. 코드에서 발생할 수 있는 예외의 경우 ECMAScript Error와 DOMException 및 기타 예외가 있습니다.

 

📑ECMAScript Error

JS에서 발생하는 에러로 MDN 사이트에서 자세히 확인할 수 있습니다.

 

Error - JavaScript | MDN

Error 객체는 런타임 오류가 발생했을 때 던져집니다. Error 객체를 사용자 지정 예외의 기반 객체로 사용할 수도 있습니다. 아래 표준 내장 오류 유형을 참고하세요.

developer.mozilla.org

 

📑DOMException

Web API 레벨에서 발생하는 에러로 MDN 사이트에서 자세히 확인할 수 있습니다.

 

DOMException - Web APIs | MDN

The DOMException interface represents an abnormal event (called an exception) that occurs as a result of calling a method or accessing a property of a web API. This is how error conditions are described in web APIs.

developer.mozilla.org

 

📑기타 예외 핸들링

나머지 예외들은 개발자가 상황을 예상하거나 직접 만났을 때 JS의 Error 객체를 활용해 다룰 수 있습니다. throw문을 통해 에러를 던지고, try...catch문을 통해 던져진 에러를 핸들링하면 됩니다.

모든 예외 상황을 가정해서 try...catch문을 사용한다라고 하면 개발자에게 너무나 큰 노동이 될 것입니다. 그렇기에 큰 기준을 따져보면 외부에 의존하는 상황 즉, 외부 모듈을 사용하는 경우나 network 에러가 발생하는 경우, 에러를 꼭 확인해야 하는 로직의 경우 등 예상하지 못한 상황을 대비할 때 사용하는 것이 좋습니다.

 

📄객체(Object)

📑객체 생성 방법

// literal
const obj = {
  'key' : 1,
  'key2' : 2,
  func() {
    return 3;
  }
}

console.log(obj.key); // 1
console.log(obj['key2']); // 2
console.log(obj.func()); // 3

// 생성자 함수
function Student(name, id) {
  this.name = name;
  this.id = id;
}

const obj2 = new Student('nulzi', 1);

console.log(obj2); // Student {name: 'nulzi', id: 1}
console.log(obj2.name); // nulzi
console.log(obj2.id); // 1

// Object.create
const Animal = {
  name: 'tigi',
  type: 'Tiger',
  getName: function () {
    console.log(this.name);
  }
}

const Jam = Object.create(Animal);
Jam.name = 'Jam';
Jam.getName(); // Jam

 

자세한 내용은 MDN 사이트를 참고하면 좋습니다.

 

Object - JavaScript | MDN

Object 클래스는 JavaScript의 데이터 유형 중 하나를 나타냅니다. 다양한 키 모음 및 더 복잡한 엔티티들을 저장하는 데 사용됩니다. 객체는 Object() 생성자 또는 객체 초기자 / 리터럴 구문를 통해 생

developer.mozilla.org

🍯tip! 정적 메서드는 객체를 생성하지 않고 사용할 수 있는 메서드를 의미합니다.

 

📑속성 조작하기

const parent = {
  name: 'nl',
  age: 56
}

function Child(hobby) {
  this.hobby = hobby;
}

// 속성 추가
parent.gender = 'male';
console.log(parent); // {name: 'nl', age: 56, gender: 'male'}

// 속성 나열
Child.prototype = parent;

const nulzi = new Child('tennis');

console.log(Object.keys(nulzi)); // ['hobby']
console.log(Object.getOwnPropertyNames(nulzi)); // ['hobby']
for(const key in nulzi) {
  console.log(key);
}
/*
hobby
name
age
gender
*/

// 속성 삭제
delete parent.gender;
console.log(parent); // {name: 'nl', age: 56}

 

📑객체 복사하기

  1. 얕은 복사(shallow copy) : 복사를 했는데 객체의 속성 중 하나라도 같은 참조를 하고 있다면 이를 얕은 복사라고 한다. Object.assign()과 ...(spread 연산자)를 사용하는 방법이 있다.
  2. 깊은 복사(deep copy) : 복사된 객체의 모든 속성이 같은 참조를 하고 있지 않는 경우를 말한다. 재귀함수를 이용해 내부에 참조 타입을 확인해서 다 끊어내는 방법(라이브러리 활용-lodash)과 JSON.stringfy를 통해 문자열로 만들었다가 다시 객체로 변환시키는 방법이 있다. 하지만 JSON.stringfy의 경우 연산에 부담이 있어 많이 사용하지 않는 것이 좋다.

📑객체의 종류

  • 기초 객체 : Object, Function, Boolean, Symbol
    • 오류 객체 : Error
    • 숫자 및 날짜 : Number, BigInt, Math, Date
    • 텍스트 처리 : Regex, String
    • Collection
      • 인덱스 기반 collection : Array
      • 키 기반 collection : Map, WeakMap, Set, WeakSet, ...
  • 구조화된 데이터 객체 : JSON
  • 국제화 객체 : Intl
  • 제어 추상화 객체 : Promise, Generator, AsyncFunction

각 객체들은 정적 속성과 메서드, 인스턴스의 속성과 메서드를 가지고 있습니다.

🍯tip! JS의 배열에는 정수가 아닌 문자열로도 값을 저장할 수 있다. 하지만 해당 값은 배열의 요소가 아닌 객체의 속성으로 저장되기 때문에 배열의 길이에 영향을 주지 않는다.
const arr = [1,2,3];
arr['test'] = 4;

console.log(arr.length); // 3
🍯tip! 배열의 길이를 통해 강제로 배열의 내용을 자를 수 있다.
const arr = [1,2,3];
arr.length = 1;

console.log(arr); // [1]

 

📄Prototype

객체지향 프로그래밍은 크게 클래스 기반과 프로토타입 기반이 있습니다. JS는 프로토타입 기반 객체지향 언어인데, 클래스로 만들던 부모 객체를 프로토타입으로 만든다고 생각하면 됩니다.

 

다른 객체 타입이 아닌 함수 타입에만 prototype 필드가 존재합니다. 생성자 함수를 만들어서 new 키워드와 함께 호출해 인스턴스를 만든다면 인스턴스의 부모객체는 생성자 함수.prototype이 됩니다. prototype의 내부에 있는 constructor 필드는 자기 자신을 생성한 객체를 참조합니다.

function test() {}

console.dir(test); // prototype 필드 존재

const obj = {}

console.dir(obj); // prototype 필드 없음

function Animal() {}

Animal.prototype.name = 'tiger';

const tiger = new Animal();

console.log(tiger.__proto__); // {name: 'tiger'}
console.log(Animal.prototype); // {name: 'tiger'}

 

📑prototype chain

객체의 속성을 참조하는데 해당 객체가 속성을 가지고 있지 않는 경우 최상위 부모 객체(prototype)까지 속성을 찾아가는 프로토타입 체인이 있습니다. 하지만 자식 객체와 부모 객체가 모두 가지고 있는 경우 자식 객체 즉, 가장 가까이에 있는 속성을 먼저 참조합니다. 이를 property shadowing, method overriding이라고 합니다.

 

📄class

ES 6 이후로 추가된 문법으로 prototype을 바탕으로 클래스 기반 언어에 익숙한 개발자를 위해 추가되었습니다.

class Animal {
  constructor(type) {
    this.type = type;
  }
  
  static walk() {
	console.log('chap chap');
  }
  
  get uppercaseType() { // 일반 메서드처럼 호출하는 것이 아닌 참조하는 형식
    return this.type.toLocaleUpperCase();
  }
  
  set changeType(type) { // 일반 메서드처럼 호출하는 것이 아닌 할당하는 형식
    this.type = type
  }
}

const Tiger = new Animal('tiger');

console.log(Tiger.type);
console.log(Tiger.uppercaseType);

Tiger.chageType = 'small tiger';
console.log(Tiger.type);

Animal.walk();

 

📑상속

상속을 받기 위해서는 extends 키워드를 사용해야 하고, 부모 클래스의 속성에 접근하기 위해서는 super 키워드를 사용해서 부모 클래스를 바인딩해야 사용할 수 있습니다. 자식 클래스의 생성자 내에서 필드를 생성하기 전에 super를 호출한 이후에 사용해야 합니다. 또한 부모 클래스의 메서드에는 super.메서드()로 접근할 수 있습니다.

class Animal {
  constructor(type) {
    this.type = type;
  }
}

class Tiger extends Animal {
  constructor(name) {
    super('tiger');
    this.name = name;
  }
  
  growl() {
    console.log(this.type + this.name + 'Krrr');
  }
}

const tiger = new Tiger('tiny');

console.log(tiger.name); // tiny
tiger.growl() // tigertinyKrrr

 

📄자바스크립트 컨텍스트(Context)

📑this와 화살표 함수

this는 컨텍스트에 참조 가능하게 해주는 키워드입니다. 참조가 가능한 키워드는 전역 컨텍스트와 함수 컨텍스트가 있습니다. 어떤 컨텍스트를 참조할지는 동적으로 결정이 됩니다.

 

함수가 호출될 때 this가 매개변수로 암묵적으로 전달이 되어서 호출 방식에 따라 this에 바인딩되는 객체가 달라집니다. 특이하게도 화살표 함수는 this 바인딩이 제공되지 않아 항상 상위 스코프의 this에 바인딩이 되어있습니다. 그렇기 때문에 객체의 메서드로 사용하거나 생성자 함수로 화살표 함수를 사용하는 것은 지양해야 합니다.

 

this의 바인딩

  • 함수 호출 방식 : 함수 내부에서의 this는 전역 객체에 바인딩되는데, Browser 환경에서는 window 객체, Server 환경에서는 global 객체가 전역 객체입니다. 함수 안의 내부 함수에서도 전역 객체에 바인딩됩니다. 또한 객체의 메서드 내에 내부 함수에서도 함수 호출 방식으로 취급되어 전역객체를 바라봅니다.
  • 객체의 메서드 호출 : 메서드를 호출한 객체에 바인딩 됩니다. 프로토타입 객체의 메서드도 동일하게 호출한 객체에 바인딩 됩니다.
  • 생성자 함수 호출 : `1. 빈 객체에 바인딩, 2. 바인딩된 this로 속성과 메서드 생성, 3. 생성된 객체 반환` 과정을 통해 생성된 객체에 바인딩 됩니다.
  • apply, call, bind 호출 : this를 명시적으로 바인딩하는 방법입니다. apply와 call은 바인딩과 함수 호출이 동시에 이루어지지만, bind의 경우 바인딩만 동작합니다.

📑scope

스코프는 변수가 유효성을 가질 수 있는 범위(영역)를 의미합니다.

 

규칙

  1. 정적(렉시컬 스코프 규칙) : 자바스크립트가 선택한 규칙. 호출이 아닌 선언에 따라 스코프가 결정됩니다.
  2. 동적(dynamic 스코프 규칙) : 런타임 때 호출에 따라 스코프가 결정이 됩니다.

종류

  • 전역 : 전범위. 브라우저 기준으로 window의 속성을 의미합니다.
  • 모듈 : 모듈 내.
  • File : 파일 내. <script type="module"..>로 조회되는 파일 내를 의미합니다.
  • 함수 : 함수 내. 자바스크립트는 함수 레벨 스코프를 기반으로 하고 있습니다.
  • 블록 : 코드 블록 내.

📑실행 컨텍스트

과정

  1. Creation Phase(코드 평가 단계, 실행 컨텍스트 생성 단계) : Lexical Environment를 생성합니다. 이때 Environment Record(함수와 변수를 기록)에서 선언과 객체를 정의하고, this를 바인딩 합니다. Outer Environment Reference(외부 환경 참조 == 외부 실행 컨텍스트)에서 스코프 체인이 형성됩니다.
  2. Execution Phase(코드 및 실행 컨텍스트 실행 단계) : 위에서 아래로 코드가 실행되며 변수에 값이 할당되고, 함수도 실행됩니다. 이때 새로운 함수의 실행 컨텍스트 과정을 반복합니다.

종류

  1. global context : 함수 내 실행 코드가 아니면 전역 컨텍스트에서 실행됩니다. 브라우저에서는 window 객체를 의미합니다.
  2. functional context : 함수가 호출될 때마다 실행 컨텍스트가 생성됩니다.
  3. eval context : eval 함수만의 실행 컨텍스트가 존재합니다.

📑Call Stack

JS에서는 실행 컨텍스트를 추적하고 관리하기 위해서 call stack라는 것을 사용합니다. 어떤 함수가 동작하고 있고 다음에 동작할 함수를 제어합니다. 스택 자료구조를 따르기 때문에 LIFO 형태의 구조를 가집니다. 콜 스택에는 실행 컨텍스트들이 쌓이고 나가고를 반복하며 동작하게 됩니다.

 

📑클로저

"외부 함수가 종료되었지만, 내부 함수 내에서 외부 함수의 변수를 참조하고 있어(= 외부 함수의 참조가 유지되어) 외부 함수 환경에 접근할 수 있는 상황이 된 함수"를 클로저라고 합니다. 쉽게 얘기해서 "내부 함수가 반환되었지만 선언되었던 환경을 기억해 기존 환경에 접근할 수 있는 함수"를 클로저라고 합니다.

function test() {
  const a = 1;
  
  return function() {
    return a;
  }
}

const closure = test();
console.log(closure()); // 1

이를 활용해 상태를 유지하거나 코드를 은닉화할 때 사용합니다.

❔▪❓

Q. 현 커리큘럼에서 가계부 구현은 무슨 도움을 주는 영상인가?

 

다음 시간에 계속...

 

출처 & 참고

강의

신택틱 슈거, 위키백과, 2024.06.11