본문 바로가기
JS 공부

JS문법종합반 정리 5주차 - DOM, Class, Closure

by 나노다 2024. 11. 10.

웹 페이지가 로드되는 과정

사용자가 브라우저에 주소를 입력 (= 클라이언트가 서버에 요청)

→ 서버로부터 HTML 문서를 수신 (= 서버가 클라이언트에 응답)

→ 브라우저가 HTML 파일을 해석(= parsing, rendering)

→ DOM tree와 CSSOM tree 구성 후 둘을 묶어서 Render Tree 구성(= 최종 문서 모델을 나타내는 객체의 계층 구조)

→ 브라우저 레이아웃 계산 → 페인팅

 

 

DOM

Document Object Modeling, HTML파일을 자바스크립트가 해석할 수 있는 객체 형태로 모델링한 것

브라우저 환경에 기본적으로 내장된 API(= 시스템과 사용자 간의 중간 인터페이스)

  • DOM Tree의 최상단 node는 항상 document
  • childeNodes, parentNode 속성을 통해 부모 노드와 자식 노드를 선택할 수 있음
  • createElement()와 append() 메서드를 통해 새로운 노드를 생성할 수 있음
/* 새로운 노드 생성 및 추가 */
const newNode = document.createElement('div'); // div태그 노드 하나를 생성
document.body.append(newNode); // body 태그 안에 생성한 노드 추가

 

 

Class와 Instance의 기본 개념

  • Class : 객체를 생성하기 위한 일종의 설계도. 찍어낼 객체의 속성과 메서드를 담고 있는 템플릿 같은 개념
  • Instance : class를 바탕으로 만들어진 실제 객체들을 일컫는 말

 

Class 구조 분석

  • constructor : 인스턴스가 가질 속성들을 정해주는 생성자 함수. 인스턴스를 생성할 때 호출되며, 객체를 초기화함
  • 메서드는 생성자 함수 밖에서 만듦
  • getter : 속성값을 반환하는 메서드. "get 속성명() {}"
  • setter : 속성값을 설정하는 메서드. "set 속성명(입력값) {}". setter에서 인스턴스 생성 또는 변경시 입력된 값에 대해 유효성 검사를 진행할 수 있음. 요구 조건에 맞지않는 입력값을 반려하는 과정

getter와 setter를 활용하는 경우 class 함수 내부의 모든 this.속성에 언더스코어(_)를 끼워줘야 함. 그렇지 않으면 콜스택이 배가 터져 오류를 뱉음

class 함수 내부의 모든 this는 앞으로 생성될 인스턴스를 가리킴

class Rectangle {  // 클래스 생성은 "class 이름 {}"
  constructor(height, width) { // 생성자 함수
    this._height = height; // 왼쪽의 height는 key값, 오른쪽의 height는 입력받을 value값
    this._width = width;
  }

  get width() { // width 속성에 대한 getter
    return this._width; // 언더바를 통해 오류 방지
  }

  set width(value) { // width 속성에 대한 setter
    /* 유효성 검사 */
    if (value <= 0) { 
      console.log("[오류] 가로길이는 0보다 커야 합니다!");
      return; // 조건에 안 맞는 입력 값일 시 적용하지 않기 위해 return으로 함수를 끝내버림
    } else if (typeof value !== "number") {
      console.log("[오류] 가로길이로 입력된 값이 숫자타입이 아닙니다!");
      return;
    }
    this._width = value;
  }

  getArea() { // 메서드 생성
    const a = this._width * this._height;
    console.log(`넓이는 => ${a}입니다.`);
  }
}

 

인스턴스 생성 및 속성 변경, 메서드 활용

/* 인스턴스 생성 */
const rect1 = new Rectangle(10, 7);

/* 메서드 활용 */
rect1.getArea(); // 반환 : 70

/* setter의 거름망 */
rect1.width = -1;
console.log(rect1.width); 
// 반환 : [오류] 가로길이는 0보다 커야 합니다! 
// 반환 : 10, 유효성 검사를 통과하지 못했기 때문에 변경되지 않음

 

 

클래스 상속

상속을 하는 클래스를 superclass 또는 base class라 하고, 상속을 받는 클래스를 subclass 또는 derived class라 함

상속받는 클래스를 생성할 때 "extends 상속하는클래스명"을 추가해줌

이 때 상속 받는 메서드의 실행로직을 수정할 수 있음 (중괄호 안의 내용)

/* 상속 */
class Dog extends Animal {
}
  • 속성에 대한 변경이 필요하다면 constructor() {}안에 super()를 활용
class Animal {
  constructor(name, isCute) {
    this.name = name;
    this.isCute = isCute;
  }
   speak() {
    console.log(`${this.name} makes a noise.`);
  }
}

/* name 속성 그대로 상속 */
class Dog extends Animal { 
   speak() {
    console.log(`${this.name} bark!`); // 메서드 내용을 바꿔 받을 수 있음
  }
}

/* 속성 변경 */
class Dog extends Animal { 
  constructor(name, isBark) { // isCute 값을 고정해주고 싶으니 매개변수로 받지 않음
    super(name, true); // name은 그대로 입력 받고, Dog 클래스에서 isCute는 항상 true
    this.isBark = isBark; // isBark라는 새로운 속성 생성
  }
}

 

 

Static Method

인스턴스를 생성할 필요가 없는 클래스에서 메서드만 생성해 활용하는 방법. 함수를 저장해놓는 클래스 느낌?

메서드 이름 앞에 static 키워드를 기입. 인스턴스를 만들지 않으니 construcor 함수가 필요 없음

/* 예시 */
class Calculator { // 생성자 함수 없음
  static add(a, b) { // 메서드 생성하며 static을 앞에 써줌
    return a + b;
  }
  static subtract(a, b) {
    return a - b;
  }
} // 더하기 메서드와 빼기 메서드가 저장된 계산기 클래스

/* 실행 */
console.log(Calculator.add(1, 2)); // 반환 : 3
console.log(Calculator.subtract(3, 2)); // 반환 : 1

 

 

클로저 Closure

  • 정확한 개념 : 함수와 그 함수가 선언된 렉시컬 환경(LE)와의 조합
  • 실활용 느낌 : 외부 함수보다 중첩 함수가 더 오래 유지되는 경우, 중첩 함수는 이미 콜 스택에서 사라진 외부 함수의 변수를 여전히 참조할 수 있음. 이 때 중첩 함수가 바로 클로저!

자바스크립트에선 함수의 호출 위치가 아니고, 함수를 선언한(= 정의한) 위치에서 상위 스코프(참조할 outer)를 기억

const x = 1; // 전역 스코프의 x, 할당된 값은 1

function outer() {
  const x = 10; // 외부함수 스코프의 x, 할당된 값은 10
  /* inner함수의 LE에 저장된 외부환경정보는 outer 스코프 */
  const inner = function () { // inner함수는 중첩함수로, outer의 스코프 안에서 선언됨
    console.log(x); // 중첩함수에서 x의 참조를 요구
  };
  return inner;
}
// 아래에서 outer함수가 실행되고, 
// 그 결과가 innerFunc에 할당되는 순간 outer함수는 콜스택에서 퇴장
const innerFunc = outer();
/* inner함수가 실행되는 시점엔 outer는 주근 상태 */
innerFunc(); // 반환 : 10, outer는 죽었지만 inner는 여전히 outer에서 x를 참조

 

 

클로저의 활용

상태가 의도치 않게 변경되지 않도록 안전하게 은닉하고, 특정 함수에게만 상태 변경을 허용