Chapter 1: this Or That? - hochan222/Everything-in-JavaScript GitHub Wiki

ํ,,์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์—์„œ ๋‘๋ ต๊ณ  ๋‘๋ ค์šด this ํ‚ค์›Œ๋“œ๋‹ค.
์šฐ๋ฆฌ ๋ชจ๋‘ ์ด๋ฒˆ ๊ธฐํšŒ์— ๋‘๋ ค์›€์„ ๋‚ ๋ ค๋ฒ„๋ ค๋ณด์ž.

this ์ •๋ฆฌ

Why this?

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

์œ„์˜ code snippet์„ ์‚ฌ์šฉํ•˜๋ฉด ๊ฐ๊ฐ ๊ฐ์ฒด์— ๋”ฐ๋ฅธ ๋ณ„๋„์˜ ํ•จ์ˆ˜๋ฅผ ๋งŒ๋“ค์ง€ ์•Š๋”๋ผ๋„ ์žฌ์‚ฌ์šฉํ•ด์„œ ์“ธ ์ˆ˜ ์žˆ๋‹ค. ๋งŒ์•ฝ this๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š”๋‹ค๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค.

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

์‚ฌ์šฉ ํŒจํ„ด์ด ๋ณต์žกํ• ์ˆ˜๋ก ์žฌ์‚ฌ์šฉํ•˜๊ธฐ ์‰ฝ๊ณ , API ๋””์ž์ธ์„ ๊น”๋”ํ•˜๊ฒŒ ์ด๋ˆ๋‹ค.

Confusions

this์˜ ์ •ํ™•ํ•œ ์ž‘๋™ ๋ฐฉ์‹์„ ์•Œ์•„๋ณด๊ธฐ์ „์— ์ •ํ™•ํ•œ ์˜๋ฏธ๋ฅผ ์•Œ์•„๋ณด์ž. ์ข…์ข… ๊ฐœ๋ฐœ์ž๋“ค์€ this๋ฅผ 2๊ฐ€์ง€๋กœ ๋ถ„๋ฅ˜ํ•ด์„œ ์ƒ๊ฐํ•˜๋Š”๋ฐ ๋‘๊ฐœ ๋‹ค ์˜ณ์ง€ ๋ชปํ•˜๋‹ค.

Itself

this๊ฐ€ ํ•จ์ˆ˜์—์„œ ๋ฌธ๋ฒ•์ ์œผ๋กœ ์ž๊ธฐ ์ž์‹ ์„ ์ฐธ์กฐํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•œ๋‹ค.
์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์˜ ๋ฉ”์ปค๋‹ˆ์ฆ˜์„ ์ฒ˜์Œ ์ ‘ํ•˜๋Š” ๊ฐœ๋ฐœ์ž๋Š” ํ•จ์ˆ˜๋ฅผ ๊ฐ์ฒด(JavaScript์˜ ๋ชจ๋“  ํ•จ์ˆ˜๊ฐ€ ๊ฐ์ฒด์ด๋‹ค.)๋กœ ์ฐธ์กฐํ•˜๋ฉด ํ•จ์ˆ˜ ํ˜ธ์ถœ ์‚ฌ์ด์— ์ƒํƒœ (์†์„ฑ ๊ฐ’)๋ฅผ ์ €์žฅํ•  ์ˆ˜ ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•œ๋‹ค.
(์ด๊ฒƒ๋„ ๋‚˜์˜์ง€ ์•Š์€ ๋ฐฉ๋ฒ•์ด์ง€๋งŒ ๋’ท์žฅ์—์„œ ๋” ์ข‹์€ ๋ฐฉ๋ฒ•์„ ์•Œ๋ ค์ค„ ๊ฒƒ์ด๋‹ค.)

์˜ˆ์ œ๋ฅผ ๋ณด์ž.

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?

์˜ค.. ๋Œ€๋ฐ•... foo.count = 0๊ฐ€ ์‹คํ–‰ ๋ ๋•Œ, ์‚ฌ์‹ค foo ํ•จ์ˆ˜ ๊ฐ์ฒด์— count๊ฐ€ ์ถ”๊ฐ€๋œ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ this.count๋Š” ํ•จ์ˆ˜ ๊ฐ์ฒด๋ฅผ ๊ฐ€๋ฅดํ‚ค์ง€ ์•Š๋Š”๋‹ค.

๋”ฐ๋ผ์˜ค๋Š” ๋‹น์—ฐํ•œ ์งˆ๋ฌธ์€ ์šฐ๋ฆฌ๋Š” this.count๋กœ ์ „์—ญ ๋ณ€์ˆ˜๋ฅผ ๋งŒ๋“ค์—ˆ๊ณ , NAN์ด ๋“ค์–ด๊ฐ€ ์žˆ์„๊ฒƒ์ด๋‹ค. ์™œ๋ƒ๋ฉด undefined๋ฅผ ++ ํ•ด์ฃผ์—ˆ์œผ๋‹ˆ๊นŒ. (2์žฅ์—์„œ ๋ฐฐ์›€)

๋‚ด๋ถ€์—์„œ ํ•จ์ˆ˜ ๊ฐ์ฒด๋ฅผ ์ฐธ์กฐํ•˜๋ ค๋ฉด lexical identifier ๊ฐ€ ํ•„์š”ํ•˜๋‹ค.

function foo() {
	foo.count = 4; // `foo` refers to itself
}

setTimeout( function(){
	// anonymous function (no name), cannot
	// refer to itself
}, 10 );

์ฒซ๋ฒˆ์งธ ํ•จ์ˆ˜๋Š” name identifier ๊ฐ€ ์žˆ์œผ๋ฏ€๋กœ ์ž๊ธฐ ์ž์‹ ์— ์ฐธ์กฐ ๊ฐ€๋Šฅํ•˜๋‹ค.
๋‘๋ฒˆ์งธ ํ•จ์ˆ˜๋Š” ์ต๋ช…ํ•จ์ˆ˜๋กœ ์ฐธ์กฐ ํ•  ์ ์ ˆํ•œ ๋ฐฉ๋ฒ•์ด ์—†๋‹ค.

arguments.callee๋Š” ์ต๋ช…ํ•จ์ˆ˜์—์„œ ์ž๊ธฐ ์ž์‹ ์„ ์ฐธ์กฐํ•  ์œ ์ผํ•œ ๋ฐฉ๋ฒ•์ด์—ˆ์ง€๋งŒ deprecated๋˜์—ˆ๋‹ค.

๋‹ค์Œ์€ ๊ฐœ์„ ๋œ ์†”๋ฃจ์…˜์ด๋‹ค.

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

	// keep track of how many times `foo` is called
	foo.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 ); // 4

๊ทธ๋Ÿฌ๋‚˜ 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

this๋ฅผ ํ”ผํ•˜์ง€๋ง๊ณ  ํฌ์šฉํ•˜์ž!

Its Scope

๊ทธ ๋‹ค์Œ ๊ฐ€์žฅ ์ผ๋ฐ˜์ ์ธ ์ž˜๋ชป๋œ ์ƒ๊ฐ์€ this๊ฐ€ ์–ด๋–ป๊ฒŒ๋“  ํ•จ์ˆ˜ ๋ฒ”์œ„๋ฅผ ์ฐธ์กฐํ•œ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค. this๋Š” ์–ด๋–ป๊ฒŒ๋“  ํ•จ์ˆ˜์˜ lexical scope๋ฅผ ์ฐธ์กฐ ํ•  ์ˆ˜ ์—†๋‹ค. object์˜ scope๋Š” ์—”์ง„์˜ ๋‚ด๋ถ€ ๊ตฌํ˜„์ค‘ ํ•˜๋‚˜์ด๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

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

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

foo(); //undefined

์‹ค์ œ JS forum์—์„œ ๋‚˜์˜จ ์งˆ๋ฌธ ์˜ˆ์ œ๋‹ค. ์ด snippet์—๋Š” ๋” ๋งŽ์ด ์ž˜๋ชป๋œ๊ฒŒ ์žˆ๋‹ค.

์šฐ์„  bar๋ฅผ this๋กœ ์ฐธ์กฐํ•˜๋Š”๊ฒŒ ์ž˜๋ชป๋๋‹ค. ์กฐ๊ธˆ ๋” ์ผ๋ฐ˜์ ์ธ ๋ฐฉ๋ฒ•์€ ์‹๋ณ„์ž๋กœ lexical ์ฐธ์กฐ๋ฅผ ํ•˜๋Š”๊ฒƒ์ด๋‹ค. ๋‘๋ฒˆ์งธ๋กœ ๋ญ”๊ฐ€ fooํ•จ์ˆ˜ ๋‚ด๋ถ€์— barํ•จ์ˆ˜์˜ lexical ์‹๋ณ„์ž๋ฅผ ๋‘ ์œผ๋กœ์จ ์ฐธ์กฐํ•˜๋Š”๋ฐ this๋ฅผ ํ†ตํ•œ ์–ด๋–คํ•œ ์—ฐ๊ฒฐ๊ณ ๋ฆฌ๊ณ  ์ƒ๊ธธ ์ˆ˜ ์—†๋‹ค.

What's this?

์šฐ์„  this๋Š” ๋Ÿฐํƒ€์ž„ ๋ฐ”์ธ๋”ฉ์ด๊ณ , ํ•จ์ˆ˜ ์„ ์–ธ ์œ„์น˜์™€๋Š” ๊ด€๋ จ์—†์ง€๋งŒ ํ•จ์ˆ˜ ํ˜ธ์ถœ ๋ฐฉ์‹๊ณผ๋Š” ๊ด€๋ จ์ด ์žˆ๋‹ค.

ํ•จ์ˆ˜๊ฐ€ ํ˜ธ์ถœ๋˜๋ฉด ์‹คํ–‰ ์ปจํ…์ŠคํŠธ(execution context)๋กœ ์•Œ๋ ค์ ธ ์žˆ๋Š” activation record๊ฐ€ ๋งŒ๋“ค์–ด์ง„๋‹ค. ์ด ๋ ˆ์ฝ”๋“œ์—๋Š” ํ•จ์ˆ˜๊ฐ€ ํ˜ธ์ถœ ๋œ ์œ„์น˜ (ํ˜ธ์ถœ ์Šคํƒ), ํ•จ์ˆ˜๊ฐ€ ํ˜ธ์ถœ ๋œ ๋ฐฉ๋ฒ•, ์ „๋‹ฌ ๋œ ๋งค๊ฐœ ๋ณ€์ˆ˜ ๋“ฑ์— ๋Œ€ํ•œ ์ •๋ณด๊ฐ€ ํฌํ•จ๋œ๋‹ค. ๋ ˆ์ฝ”๋“œ ์š”์†Œ ์ค‘ ํ•จ์ˆ˜ ์‹คํ–‰ ์ค‘ ์‚ฌ์šฉ๋  this ์ฐธ์กฐ์— ๊ด€ํ•œ ์š”์†Œ๋„ ์žˆ๋‹ค.

๋‹ค์Œ ์žฅ์—์„œ๋Š” ํ•จ์ˆ˜์˜ call-site๋ฅผ ํ†ตํ•ด ์–ด๋–ป๊ฒŒ this๊ฐ€ ๋ฐ”์ธ๋”ฉํ•˜๋Š”์ง€ ๋ฐฉ๋ฒ•์„ ๊ฒฐ์ •ํ•  ๊ฒƒ์ด๋‹ค.

Review (TL;DR)

์šฐ๋ฆฌ๋Š” this์˜ ์›๋ฆฌ๋ฅผ ์ •ํ™•ํžˆ ์•Œ๋ คํ•˜๋Š”๋ฐ ์‹œ๊ฐ„์„ ํˆฌ์žํ•˜์ง€์•Š๊ณ  ๊ธฐํƒ€ ์‚ฌ์ดํŠธ๋“ค์—์„œ ํŠธ๋ฆญ๋งŒ ๋ฐฐ์›Œ์„œ ์—ฌ๋Ÿฌ ํ˜ผ๋ž€๋“ค์„ ์œ ๋ฐœํ–ˆ๋‹ค.

์šฐ๋ฆฌ๋Š” this๋ฅผ ๋ฐฐ์›Œ์•ผํ•œ๋‹ค. ํ•จ์ˆ˜ ์ž์ฒด๋„์•„๋‹ˆ๊ณ  ํ•จ์ˆ˜์˜ lexical scope๋„ ์•„๋‹ˆ๋‹ค.

this๋Š” ์‹ค์ œ๋กœ ํ•จ์ˆ˜๊ฐ€ ํ˜ธ์ถœ๋  ๋•Œ ๋งŒ๋“ค์–ด์ง€๋Š” ๋ฐ”์ธ๋”ฉ์ด๋ฉฐ this๊ฐ€ ์ฐธ์กฐํ•˜๋Š” ๊ฒƒ์€ ์ „์ ์œผ๋กœ call-site์— ์˜์กดํ•œ๋‹ค.