티스토리 뷰

javascript의 this는 java의 this와는 완전히 다르다.

 

this는 모든 함수 스코프 내에 자동으로 설정되는 특수한 식별자

function identify() {
	return this.name.toUpperCase();
}

function speak() {
	var greeting = "Hello, I'm " + identify.call( this );
	console.log( greeting );
}

var me = {
	name: "Kyle"
};

var you = {
	name: "Reader"
};

identify.call( me ); // KYLE
identify.call( you ); // READER

speak.call( me ); // Hello, I'm KYLE
speak.call( you ); // Hello, I'm READER

이것 대신 context를 명시해서 사용할 수도 있다

function identify(context) {
	return context.name.toUpperCase();
}

function speak(context) {
	var greeting = "Hello, I'm " + identify( context );
	console.log( greeting );
}

identify( you ); // READER
speak( me ); // Hello, I'm KYLE

어떻게든 사용할 수 있지만, 암시적인 객체 레퍼런스를 함께 넘기는 this가 더 깔금하다.

 

사용 패턴이 복잡해질수록 명시적으로 context를 넘기는 것보다 this로 암시적으로 넘기는게 더 깔끔하기 때문, 

- 이 부분은 다음에 배울 예정

 

사람들이 가장 많이 오해하는 것

 

1. this는 자기 자신이다(Java에서 처럼)

function foo(num) {
	console.log( "foo: " + num );

	// keep track of how many times `foo` is called
	this.count++;
}

foo.count = 0;

var i;

for (i=0; i<10; i++) {
	if (i > 5) {
		foo( i );
	}
}
// foo: 6
// foo: 7
// foo: 8
// foo: 9

// how many times was `foo` called?
console.log( foo.count ); // 0 -- WTF?

여기서 this.count는 함수 내부가 아닌 전역변수 count를 가리킴

하지만 전역변수 count도 그렇다고 4는 아니고 NaN을 호출함

 

렉시컬 스코프로 편하게 하는법 (추천하지 않음)

function foo(num) {
	console.log( "foo: " + num );

	// keep track of how many times `foo` is called
	data.count++;
}

var data = {
	count: 0
};

var i;

for (i=0; i<10; i++) {
	if (i > 5) {
		foo( i );
	}
}
// foo: 6
// foo: 7
// foo: 8
// foo: 9

// how many times was `foo` called?
console.log( data.count ); // 4

이런 방법은 추천하지 않음, 렉시컬 스코프로 꿀빠는 것이기 때문이다.

 

렉시컬 스코프(Lexiacl Scope)란?

- 스코프는 함수가 실행될 때가 아니라 선언 될 때 만들어 지는 것,

함수를 처음 선언하는 순간, 함수 내부의 변수는 자기 스코프로부터 가장 가까운 곳(상위 범위에서)에 있는 변수를 계속 참조하게 됩니다(https://www.zerocho.com/category/JavaScript/post/5740531574288ebc5f2ba97e)

 

예제

var name = 'zero';
function log() {
  console.log(name);
}

function wrapper() {
  var name = 'nero';
  log();
}
wrapper(); // zero

 

this를 피하지않고 그대로 적용하는 법

function foo(num) {
	console.log( "foo: " + num );

	// keep track of how many times `foo` is called
	// Note: `this` IS actually `foo` now, based on
	// how `foo` is called (see below)
	this.count++;
}

foo.count = 0;

var i;

for (i=0; i<10; i++) {
	if (i > 5) {
		// using `call(..)`, we ensure the `this`
		// points at the function object (`foo`) itself
		foo.call( foo, i );
	}
}
// foo: 6
// foo: 7
// foo: 8
// foo: 9

// how many times was `foo` called?
console.log( foo.count ); // 4

- foo 함수 객체에서 call 함수로 호출한다.

- 이게 그렇게 좋은 방법인가?

 

2. 자신의 스코프

this가 함수의 스코프를 가리킨다는 말은 어떤 면에선 맞지만 잘못 이해한 것!

this는 어떤 식으로도 함수의 렉시컬 스코프를 참조하지 않는다.

function foo() {
	var a = 2;
	this.bar();
}

function bar() {
	console.log( this.a );
}

foo(); //undefined

 

정리

this는 런타임 시점에 바인딩 되며, 함수 호출 당시 상황에 따라 콘텍스트가 결정된다.

this 바인딩은 함수 선언 위치와 상관 없음

오로지 어떻게 함수를 호출했느냐에 따라 정해짐

 

아지긍ㄴ this가 어렵지만, 조금 더 공부를 해보자!

댓글