코딩딩/Javascript

날것 - this

전낙타 2026. 7. 14. 20:27

this

나는 나다

this 키워드

일단 읽기도 너무 이상함
그냥 이상함

const circle = {
	radius = 5;
	getDiameter() {
		return 2 * circle.radius;
	}
}

getdiameter가 호출되는 시점엔 이미 circle 변수에 객체 리터럴이 할당된 상태임
그래서 getDiameter는 해당 객체의 radius 값을 참조하게 된다.

하지만 자기 자신을 재귀적으로 참조하는건 딱봐도 이상함

function Circle(radius) {
	// 이 시점에는 this가 뭔지 알 수 없음. 생성자 함수가 실행되지 않았기 때문이지
	????.radius = radius;
}

Circle.prototype.getDiameter = function () {
	// 이 시점에는 생성자 함수 자신이 생성할 인스턴스를 가리키는 식별자를 알 수 없다.
	return 2 * ????.radius;
}

// 생성자 함수로 인스턴스를 생성하려면 먼저 생성자 함수를 정의해야 한다.
const circle = new Circle(5);

생성자 함수 내부에서는 프로퍼티 또는 메서드를 추가하기 위해 자신이 생성할 인스턴스를 참조할 수 있어야함
하지만 이를 위해선 생성자 함수 정의 + new 연산자와 함께 생성자 함수를 호출하는 단계가 추가로 필요함

생성자 함수를 정의하는 시점에는 아직 인스턴스가 없어서 자신이 속한 객체를 가르키는 특수한 식별자가 필요함

이를 위해 나온데 this임

근데 어떻게 없는 객체를 this 쓴다고 뿅 만들어지는것도 아니고 어떻게 참조한다는거여 <- 라고 생각할수도 있음
그래서 this는 본인이 속한 객체 또는 자신이 생성할 인스턴스를 가리키는 자기참조 변수로 사용됨

this는 암묵적으로 생성되며, 코드 어디서든 참조할 수 있음.

함수를 호출하면 arguments 객체와 this가 암묵적으로 함수 내부에 전달된다.
함수 내부에서 arguments 객체를 지역 변수처럼 사용할 수 있는것처럼 this도 지역변수처럼 사용할 수 있음.

단 this는 this가 가리키는 값, 즉 this 바인딩은 함수 호출 방식에 의해 동적으로 결정된다.

자바나 C++같은 클래스 기반 언어는 this는 언제나 클래스가 생성하는 인스턴스를 가리킨다.
하지만 자바스크립트의 this는 상위 객체도 this를 갖고 있음으로 this가 바인딩 되지 않은 상황에서는 상위 객체의 this를 생성해버림 레전드 레 전 드 레 전 드

모든것이 동적인 우리 자바스크립트 선생님의 온몸 비틀기를 보는 느낌

함수 호출 방식과 this 바인딩

동일한 함수도 호출 방식에 따라 this가 달라진다 레 전    드       레           전                드                    레                                  전                                                드

기본적으로 전역 객체 바인딩, strict mode에서는 undefined. 중첩 함수·콜백 함수도 일반 함수로 호출되면 전역 객체를 가르킨다

const foo = function() {
	console.dir(this);
}

foo(); // window

const obj = { foo };
obj.foo(); // obj

new foo(); // foo{}

const bar = { name: 'bar' };

foo.call(bar) // bar
foo.apply(bar) // bar
foo.bind(bar) // bar

각각 어떤 방식으로 호출되는지 좀 더 디테일하게 알아보자

일반 함수 호출

일반 함수에서 this를 호출하면 주로 전역 객체가 바인딩된다.

const foo = function() {
	console.log("foo's this: ", this); // window
	const bar = function() {
		console.log("bar's this: ", this); // window
	}
}

foo();

같은 코드에서 use strict를 적용하면 undefined가 바인딩 된다

메서드 내에서 정의한 중첩 함수도 일반 함수로 호출되면 중첩 함수 내부의 this에는 전역 객체가 바인딩된다.

var value = 1;

const obj = {
	value: 100;
	
	foo() {
		console.log("foo's this: ", this); // { value: 100, foo: ƒ }
		console.log("foo's this.value: ", this.value); // 100 
		
		// 메서드 내에서 정의한 중첩 함수
		function bar() {
			console.log("bar's this: ", this); // window
			console.log("bar's this.value: ", this.value); // 1
		}
		// 메서드 내에서 정의한 중첩 함수도 일반 함수로 호출되면 중첩 함수 내부의 this에는
		// 전역 객체가 바인딩된다.
		bar();
	}
}


obj.foo();

obj.bar 가 아닌 이상 콜백 함수가 일반 함수로 호출된다면 콜백 함수 내부의 this에도 전역 객체가 바인딩된다.

와 진짜 레전드네

그나마 가독성을 좀 높히기 위해 bind를 제공하는 모양

var value = 1;

const obj = {
	value: 100;
	
	foo() {
		setTimeout(function() {
			console.log(this.value); // 100
		}.bind(this), 100);
	}
}

obj.foo();

아오 ㅋㅋ

그나마 최근에 나온 문법인 화살표 함수에는 알아서 바인딩 된다고 함

var value = 1;

const obj = {
	value: 100;
	foo() {
		setTimeout(() => console.log(this.value), 100); // 100
	}
}

obj.foo();

메서드 호출

메서드를 소유한 객체가 아니라 "호출한" 객체.
메서드를 변수에 할당하거나 다른 객체에 붙이면 바인딩이 달라짐

const person = {
	name: 'Lee',
	getName() {
		return this.name;
	}
};

console.log(person.getName()); // Lee

모두가 이해할 수 있는 정상적인 사용 예시
그렇다면 이제 모두가 이해할 수 없는 비정상적인 사용 예시를 보여주마

name = 'Kim';

const anotherPerson = {
	name: 'Jeon'
}

anotherPerson.getName = person.getName; // 자바스크립트로개발을시작한걸후회하게해주마

console.log(anotherPerson.getName()); // Jeon

const getName = person.getName;

// 다시는자바스크립트로짜여진코드를정면으로바라보지못하게해주마
console.log(getName()); // 'Kim' 

이론상 뒷마당에 핵 원자로를 만들 수 있다고 해서 이를 실행하면 안되듯이, 절대로 이런 코드는 세상에 존재해서는 안된다

생성자 함수 호출

생성자 함수 내부의 this에는 생성자 함수가 미래에 생성할 인스턴스가 바인딩된다.

function Circle(radius) {
	this.radius = radius;
	this.getDiameter = function () {
		return 2 * this.radius;
	};
}

const circle1 = new Circle(5);
const circle1 = new Circle(10);

console.log(circle1.getDiameter()); // 10
console.log(circle2.getDiameter()); // 20

생성자 함수도 함정이 잇슴
new 로 생성하지 않으면 그냥 일반함수로 동작해 버린다는것 ㅋㅋ

const circle3 = Circle(15);

console.log(circle3); // undefined

console.log(radius); // 15

Function.prototype.apply / call / bind 메서드에 의한 간접 호출

모두가 가지고 있음.
prototype이 모든 객체에 상속하기 때문임

apply와 call 메서드는 함수를 호출하면서 첫 번쨰 인수로 전달한 특정 객체를 호출한 함수의 this에 바인딩 해줌

이놈이 사실상 this을 결정해주는것임

call, apply와 bind의 차이는 사실상 실행을 시키는가 혹은 그냥 할당만 하는가의 차이임

const person = {
	name: 'Lee',
	foo(callback) {
		// bind 메서드로 callback 함수 내부의 this 바인딩을 전달
		setTimeout(callback.bind(this), 100);
	}
};

person.foo(function () {
	console.log(`Hi! my name is ${this.name}.`); // Hi my name is Lee
})


참고 자료

  • 모던 자바스크립트 Deep Dive 22장
  • 빌트인 객체 — 21장. apply/call/bind는 표준 빌트인 객체 Function의 prototype 메서드다
  • 생성자 함수 — new 바인딩에서 this가 인스턴스를 가리키게 되는 과정
  • this (기존 정리) — 1월에 정리한 4가지 바인딩 규칙·화살표 함수 노트
반응형