클로저, this, 프로토 타입

FAST FOX·2025년 7월 22일

About. JavaScript

목록 보기
3/10
post-thumbnail

1. 클로저란?

클로저는 렉시컬 스코프 규칙을 띄는 JS가 가지게 되는 주요 특징 중 하나이다.
정의를 해보자면, 함수가 정의된 스코프가 아니 다른 스코프에서 실행되더라도 스코프 밖에 있는 변수를 기억하고 이 외부 변수에 계속 접근할 수 있는 경우를 말한다.

우선 예시를 확인해보자

function greeting(msg) {
  return function who(name) {
    console.log(`${name}, ${msg}!);
  };
}

const hello = greeting("안녕하세요");
cosnt howdy = greeting("잘 지내시나요");

hello("카일"); // 카일 님, 안녕하세요!
hello("보라"); // 보라 님, 안녕하세요!
howdy("호진"); // 호진 님, 잘 지내시나요!

위의 예제에서 hello()에서 호출된 greeting()을 통해서 "안녕하세요"가 넘어가고 hello()에서는 기존에 msg("안녕하세요")가 가비지 컬렉션의 대상이 되어 메모리에서 삭제된다고 생각할 수 있지만 사실을 그렇지 않다.
외부 스코프에 있는 변수를 기억하는 현상을 close over라고 부르는데 위의 예제에서 who()greeting()을 통해서 넘어온 msg를 close over하고 있다.

클로저는 변수를 복사한 값을 사용하지 않고 변수 자체와 직접적인 관계를 맺어 변수가 업데이트되는 것을 관찰하고 최신 값을 가져와서 사용한다.

2. this 키워드

this 키워드는 정적인 스코프에서 함수의 실행 컨텍스트를 동적으로 지정할 수 있고 다른 객체에도 해당 함수를 재사용할 수 있도록 해주는 도구라고 할 수 있다.

말로만 해도 이해가 어려우니 우선 예시를 보자

function classroom(teacher) {
  return function study() {
    console.log(`${teacher} 선생님이 ${this.topic}을/를 공부하라고 했습니다.`);
  };
}

const assignment = classroom("카일");

assignment(); // 카일 선생님이 undefined을/를 공부하라고 했습니다...1️⃣

let homework = {
  topic : "JS",
  assignment : assignment
};

homework.assignment(); // 카일 선생님이 JS을/를 공부하라고 했습니다...2️⃣
  • 1️⃣ 설명
    classroom("카일")을 호출하면 반환되는 내부 함수 study()는 변수 assignment에 할당된다.
    그 상태에서 assignment()를 호출했지만 구체적인 컨텍스트를 지정하지 않았기 때문에 기본 컨텍스트가 전역 객체가 되었고 전역 객체에는 물론 topic이라는 속성이 없기 때문에 this.topicundfined가 되었다.

  • 2️⃣ 설명
    두 번째에서는 assignment 함수의 참조 복사본을 homework 객체의 assignment 속성의 값으로 설정하고 homework.assignment()를 호출했다.
    이렇게 하면 호출을 할 때 thishomework.topic이 되게 된다.

let otherHomework = {
  topic : "수학"
};

assignment.call(otherHomework); // 카일 선생님이 수학을/를 공부하라고 했습니다.

이번에 사용한 .call() 메서드는 함수가 참조할 객체를 결해준 것이다.

원래라면 스코프가 지정된 함수는 다른 스코프를 참조할 수 없고 변수를 지정할 수도 없겠지만 예시들에서 본 것처럼 this를 사용하면 컨텍스트를 동적으로 지정할 수 있고 다른 객체에도 해당 함수를 재사용할 수 있어서 유연성이 매우 좋아진다.

3. 프로토타입

프로토타입은 두 객체를 연결하는 연결 장치라고 볼 수 있다.
프로토타입은 객체가 생성될 때 만들어지고 이걸 통해서 새롭게 생성된 객체는 기존에 존재하는 다른 객체에 연결된다.
이렇게 프로토타입을 통해 연결된 일련의 객체를 프로토타입 체인이라고 부른다.
프로토타입이 존재하는 이유는 B에 업는 속성이나 메서드에 접근하려고 할 때 A에서 위임을 받아 해당 접근을 처리할 수 있도록 하기 위해서이다.

모든 객체 타입(배열, 함수, 날짜 등)은 결국 Object를 기본으로 하는 프로토타입 체인을 가지기 때문에 객체라면 모두 Object.prototype에 정의된 내장 메서드를 상속받아 사용할 수 있는 것이다.
한 번 예시를 보자

let homework = {
  topic : "JS"
};

console.log(homework.toString()); // [object Object]

자바스크립트 객체에서 toString() 메서드를 호출하면, 기본적으로 상속받고 있는 Object.prototype.toString() 메서드가 실행된다.
그리고 이 메서드는 객체의 타입을 다음과 같은 형식의 문자열로 반환한다. [object 타입]
그렇기 때문에 결과적으로 [object Object]와 같은 결과 같이 나온 것이다.

3-1. 객체 연결 장치

만약에 객체와 객체의 연결 장치를 직접 정의하고 싶을 때는 Object.create()를 사용하면 된다.

let homework = {
  topic : "JS"
};

let otherHomework = Object.create(homework);

consoe.log(otherHomework.topic); // "JS"

단 주의 할 것은 otherHomework에는 실제로 topic 프로퍼티가 없다는 점이다.

let obj = {
  topic : "JS"
};

let obj_1 = Object.create(obj);

console.log(obj_1.topic); // "JS" ... 1️⃣
console.log(obj_1); // {} ... 2️⃣

obj_1.topic = "Math"; ... 3️⃣

console.log(obj_1) // {topic : "Math"} 

위에 예시와 가치 1️⃣에서 obj_1.topic의 값이 "JS"가 나왔지만 2️⃣에서 정작 obj_1은 비어있는 객체인 상태이다.
그리고 3️⃣에서 obj_1.topic에 "Math"를 할당해줘야 obj_1에 실제로 topic 프로퍼티가 생기고 그 뒤로는 "JS"는 "Math"에 가려지게 된다.

4. this와 prototype

this와 프로토타입은 각자 있어도 그 효과가 명확하지만 이 둘을 합쳤을 때 더 강한 시너지를 발휘하게 된다.

let homework = {
  study() {
    console.log(`${this.topic}을/를 공부하세요`);
  }
};

let jsHomework = Object.create(homework);
jsHomework.topic = "JS";


let mathHomework = Object.create(homework);
mathHomework.topic = "Math"

jsHomework.study() // JS을/를 공부하세요
mathHomework.study() // Math을/를 공부하세요

다른 언어들에서는 this가 정적이기 때문에 study() 메서드가 homework 객체에 정의되어 있으므로 this는 homework가 되었을 것이다.
하지만 JS에서는 this가 동적이기 때문에 각각 jsHomework와 mathHomework가 되어서 위와 같은 결과를 낼 수 있는 것이고 이런 특징이 프로토타입을 통한 위임, 특히 class에서 위임을 가능하게 만드는 요소이다.

profile
준비하는 개발자

0개의 댓글