Chapter 2: this All Makes Sense Now! - hochan222/Everything-in-JavaScript GitHub Wiki

์ด์ œ ์šฐ๋ฆฌ๋Š” this๊ฐ€ ์ „์ ์œผ๋กœ call-site์— ๊ธฐ๋ฐ˜ํ•ด์„œ ๋ฐ”์ธ๋”ฉ ๋œ๋‹ค๋Š” ์‚ฌ์‹ค์„ ์•Œ์•˜๋‹ค.

Call-site

this์˜ ๋ฐ”์ธ๋”ฉ์„ ์ดํ•ดํ•˜๋ ค๋ฉด call-site(ํ•จ์ˆ˜๊ฐ€ ํ˜ธ์ถœ๋˜๋Š” ์ฝ”๋“œ์˜ ์œ„์น˜)๋ฅผ ์ดํ•ดํ•ด์•ผํ•œ๋‹ค. call-site๋Š” this๊ฐ€ ๋ฌด์—‡์„ ์ฐธ์กฐํ•˜๊ณ  ์žˆ๋Š”๊ฐ€์— ๋Œ€ํ•œ ๋‹ต์„ ํ•ด์ค„ ์ˆ˜ ์žˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์—์„œ ํŠน์ • ํ˜ธ์ถœ ํŒจํ„ด์ด call-site๋ฅผ ์ˆจ๊ธธ ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์œ ์‹ฌํžˆ ๋ด์•ผํ•œ๋‹ค.

function baz() {
    // call-stack is: `baz`
    // so, our call-site is in the global scope

    console.log( "baz" );
    bar(); // <-- call-site for `bar`
}

function bar() {
    // call-stack is: `baz` -> `bar`
    // so, our call-site is in `baz`

    console.log( "bar" );
    foo(); // <-- call-site for `foo`
}

function foo() {
    // call-stack is: `baz` -> `bar` -> `foo`
    // so, our call-site is in `bar`

    console.log( "foo" );
}

baz(); // <-- call-site for `baz`

Nothing But Rules

call-site๊ฐ€ ํ•จ์ˆ˜ ์‹คํ–‰์ค‘์— this๊ฐ€ ์–ด๋””๋ฅผ ๊ฐ€๋ฅดํ‚ค๋Š”๊ฐ€๋ฅผ ์–ด๋–ป๊ฒŒ ๊ฒฐ์ •ํ•˜๋Š”๊ฐ€๋ฅผ ์•Œ์•„๋ณด์ž.
4๊ฐ€์ง€ ๊ทœ์น™๊ณผ ๊ฐ๊ฐ ๊ฒฝ์šฐ์— ์ ์šฉ๋˜๋Š” ์šฐ์„ ์ˆœ์œ„๊ฐ€ ์žˆ๋‹ค.

Default Binding

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

var a = 2;

foo(); // 2

์šฐ์„  var a = 2;๊ฐ™์ด ์ „์—ญ์„ ์–ธ๋œ๊ฒƒ์€ global-object properties์— ๊ฐ™์€ ์ด๋ฆ„์œผ๋กœ ์กด์žฌํ•˜๋Š” ๊ฒƒ๊ณผ ์ •ํ™•ํžˆ ๋™์น˜์ด๋‹ค. ๊ฐ๊ฐ์˜ ๋ณต์‚ฌ๋ณธ์ด์•„๋‹ˆ๊ณ  ํ•˜๋‚˜๋‹ค.

๊ธฐ๋ณธ ๋ฐ”์ธ๋”ฉ์ด ํ•จ์ˆ˜ ํ˜ธ์ถœ์— ์ ์šฉ๋˜๋ฏ€๋กœ foo()ํ•จ์ˆ˜ ์•ˆ์˜ this๋Š” (global-object) ์ „์—ญ ๊ฐ์ฒด๋ฅผ ๊ฐ€๋ฅดํ‚จ๋‹ค.

strict mode์ผ ๊ฒฝ์šฐ ์ „์—ญ ๊ฐ์ฒด๋Š” ์ ํ•ฉํ•˜์ง€ ์•Š์•„ undefined๋กœ ์„ค์ •๋œ๋‹ค.

function foo() {
	"use strict";

	console.log( this.a );
}

var a = 2;

foo(); // TypeError: `this` is `undefined`

Implicit Binding

callsite๊ฐ€ context object๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์„ ๋•Œ๋‹ค.(object์™€ ๊ด€๋ จ๋  ๋•Œ)

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

var obj = {
	a: 2,
	foo: foo
};

obj.foo(); // 2

call-site๋Š” obj context๋ฅผ ํ•จ์ˆ˜ ์ฐธ์กฐ๋ฅผ ๊ฒฐ์ •ํ•˜๋Š”๋ฐ ์‚ฌ์šฉํ•œ๋‹ค. ๊ทธ๋ฆฌ๊ณ  call-site๋Š” ์˜ค์ง ๊ฐ€์žฅ ์ƒ๋‹จ/๋งˆ์ง€๋ง‰์—์žˆ๋Š” ๊ฐ์ฒด ์†์„ฑ์ฐธ์กฐ ์ฒด์ธ๋งŒ ์ค‘์š”ํ•˜๋‹ค.

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

var obj2 = {
	a: 42,
	foo: foo
};

var obj1 = {
	a: 2,
	obj2: obj2
};

obj1.obj2.foo(); // 42

Implicitly Lost

๊ฐ€์žฅ ํ˜ผ๋ž€์Šค๋Ÿฌ์šธ ๋•Œ๋Š” implicitly ๋ฐ”์ธ๋”ฉ์ด ๋ฐ”์ธ๋”ฉ์„ ์žƒ์„ ๊ฒฝ์šฐ์ด๋‹ค.

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

var obj = {
	a: 2,
	foo: foo
};

var bar = obj.foo; // function reference/alias!

var a = "oops, global"; // `a` also property on global object

bar(); // "oops, global"

์‚ฌ์‹ค bar๊ฐ€ obj.foo๋ฅผ ์ฐธ์กฐํ•˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋ณด์ด์ง€๋งŒ, ๊ทธ์ € foo์˜ ๋‹ค๋ฅธ ์ฐธ์กฐ์ผ ๋ฟ์ด๋‹ค. ๋˜ํ•œ, call-site๊ฐ€ bar()์ด๊ธฐ ๋–„๋ฌธ์— ๊ธฐ๋ณธ ๋ฐ”์ธ๋”ฉ์ด ์ ์šฉ๋œ๋‹ค.

์ด๋Ÿฐ ์˜ˆ์™ธ๋Š” ์ฝœ๋ฐฑํ•จ์ˆ˜๋ฅผ ์ „๋‹ฌํ• ๋•Œ ๋˜ํ•œ ๋ฐœ์ƒํ•œ๋‹ค.

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

function doFoo(fn) {
	// `fn` is just another reference to `foo`

	fn(); // <-- call-site!
}

var obj = {
	a: 2,
	foo: foo
};

var a = "oops, global"; // `a` also property on global object

doFoo( obj.foo ); // "oops, global"

์ฝœ๋ฐฑ์œผ๋กœ ์ „๋‹ฌํ•˜๋Š” ํ•จ์ˆ˜๊ฐ€ builtin ์ด๋ผ๊ณ ํ•ด๋„ ๊ฒฐ๊ณผ๋Š” ๋˜‘๊ฐ™๋‹ค.

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

var obj = {
	a: 2,
	foo: foo
};

var a = "oops, global"; // `a` also property on global object

setTimeout( obj.foo, 100 ); // "oops, global"

๋ณดํ†ต ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋“ค์€ ์ด ์ฝœ๋ฐฑ์˜ ๋ฐ”์ธ๋”ฉ์„ ๊ฐ•์ œํ•˜๋Š” ๊ฒƒ์„ ์ข‹์•„ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์šฐ๋ฆฌ์˜ ํ˜ผ๋ž€์€ ๊ฐ€์ค‘๋œ๋‹ค.

Explicit Binding

์šฐ๋ฆฌ๋Š” ๋˜ํ•œ ๋ช…์‹œ์ ์œผ๋กœ call()๊ณผ apply()๋“ฑ์„ ํ†ตํ•ด ๋ฐ”์ธ๋”ฉ ํ•  ์ˆ˜ ์žˆ๋‹ค.
๋ช‡๋ช‡ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ํ™˜๊ฒฝ์—์„œ๋Š” ์ œ๊ณต๋˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ๋Š”๋ฐ ๋Œ€๋ถ€๋ถ„ ์ œ๊ณต๋œ๋‹ค.

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

var obj = {
	a: 2
};

foo.call( obj ); // 2

๋งŒ์•ฝ call()์•ˆ์— primitive value๊ฐ€ ์˜ค๋ฉด ๊ทธ๊ฒƒ์˜ object-form(new String(), new Boolean() ...)๋“ฑ์„ ๋ฐ”์ธ๋”ฉํ•œ๋‹ค. ์šฐ๋ฆฌ๋Š” ์ด๊ฑธ ํ”ํžˆ "boxing"์ด๋ผ๊ณ  ํ•œ๋‹ค.

์•„์‰ฝ๊ฒŒ๋„ ๋ช…์‹œ์  ๋ฐ”์ธ๋”ฉ์ด ์•ž์˜ ๋ฌธ์ œ๋“ค์„ ํ•ด๊ฒฐํ•ด์ฃผ์ง€๋Š” ๋ชปํ•œ๋‹ค.

Hard Binding

์šฐ๋ฆฌ๋Š” ๋ช‡๊ฐ€์ง€ ํŠธ๋ฆญ์œผ๋กœ ์•ž์˜ ๋ฌธ์ œ๋“ค์„ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ๋‹ค.

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

var obj = {
	a: 2
};

var bar = function() {
	foo.call( obj );
};

bar(); // 2
setTimeout( bar, 100 ); // 2

// `bar` hard binds `foo`'s `this` to `obj`
// so that it cannot be overriden
bar.call( window ); // 2

๋‹ค๋ฅธ ์˜ˆ์ œ

function foo(something) {
	console.log( this.a, something );
	return this.a + something;
}

var obj = {
	a: 2
};

var bar = function() {
	return foo.apply( obj, arguments );
};

var b = bar( 3 ); // 2 3
console.log( b ); // 5

์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅ ํ•จ์ˆ˜๋ฅผ ๋งŒ๋“ค์–ด์„œ ์กฐ๊ธˆ ๋” ๊น”๋”ํ•˜๊ฒŒ ์งœ๋ณด์ž.

function foo(something) {
	console.log( this.a, something );
	return this.a + something;
}

// simple `bind` helper
function bind(fn, obj) {
	return function() {
		return fn.apply( obj, arguments );
	};
}

var obj = {
	a: 2
};

var bar = bind( foo, obj );

var b = bar( 3 ); // 2 3
console.log( b ); // 5

ํ•˜๋“œ๋ฐ”์ธ๋”ฉ์€ ๋งค์šฐ ์ผ๋ฐ˜์ ์ธ ํŒจํ„ด์ด๋ฏ€๋กœ ES5์— Function.prototype.bind๋กœ ์ œ๊ณต๋œ๋‹ค.

function foo(something) {
	console.log( this.a, something );
	return this.a + something;
}

var obj = {
	a: 2
};

var bar = foo.bind( obj );

var b = bar( 3 ); // 2 3
console.log( b ); // 5

๋‹จ, ES6๋ถ€ํ„ฐ bind()ํ•จ์ˆ˜์— stack ์ถ”์ ์„ ์œ„ํ•ด bar.name ์†์„ฑ์„ ์ถ”๊ฐ€๋กœ ๊ฐ–๋Š”๋‹ค.

API Call "Contexts"

๋งŽ์€ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ๋‚ด์žฅ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋“ค์ด "context" ๋ผ๋Š” ์„ ํƒ์  ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ์ œ๊ณตํ•œ๋‹ค.

function foo(el) {
	console.log( el, this.id );
}

var obj = {
	id: "awesome"
};

// use `obj` as `this` for `foo(..)` calls
[1, 2, 3].forEach( foo, obj ); // 1 awesome  2 awesome  3 awesome

new Binding

๋„ค๋ฒˆ์งธ์ด์ž ๋งˆ์ง€๋ง‰ this ๋ฐ”์ธ๋”ฉ ๊ทœ์น™์€ ํ•จ์ˆ˜์™€ ๊ฐ์ฒด๋“ค์˜ ๋Œ€ํ•œ ์˜คํ•ด๋ฅผ ๋‹ค์‹œ ์ƒ๊ฐํ•˜๊ฒŒ ๋งŒ๋“ ๋‹ค.
์ „ํ†ต์ ์ธ ํด๋ž˜์Šค ์ง€ํ–ฅ ์–ธ์–ด์—์„œ ์ƒ์„ฑ์ž๋Š” ํด๋ž˜์Šค์— ์—ฐ๊ฒฐ๋œ ํŠน์ˆ˜ ๋ฉ”์„œ๋“œ๋กœ, ํด๋ž˜์Šค๊ฐ€ ์ƒˆ ์—ฐ์‚ฐ์ž๋กœ ์ธ์Šคํ„ด์Šคํ™” ๋  ๋•Œ ํ•ด๋‹น ํด๋ž˜์Šค์˜ ์ƒ์„ฑ์ž๊ฐ€ ํ˜ธ์ถœ๋œ๋‹ค.

something = new MyClass(..);

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์˜ new๋ฅผ ๊ฐ™์€ ๋™์ž‘์œผ๋กœ ์˜คํ•ดํ•˜๋Š”๋ฐ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์—์„œ ์ด์—๋Œ€ํ•œ class ์ง€ํ–ฅ์  ๊ธฐ๋Šฅ์€ ์—†๋‹ค.

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์—์„œ ์ƒ์„ฑ์ž๋Š” new ์—ฐ์‚ฐ์ž๋ฅผ ์•ž์—๋‘๊ณ  ํ˜ธ์ถœ๋˜๋Š” ํ•จ์ˆ˜์ผ ๋ฟ์ด๋‹ค. ์•„๋ฌด ์—ญํ• ๋„ ์—†๋‹ค.

์˜ˆ๋ฅผ๋“ค์–ด Number()์˜ ์ƒ์„ฑ์žํ•จ์ˆ˜๋Š” ES5.1 spec์„ ์ธ์šฉํ•˜๋ฉด

15.7.2 The Number Constructor

When Number is called as part of a new expression it is a constructor: it initialises the newly created object.

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์—์„œ ์ƒ์„ฑ์ž๋Š” ๊ทธ์ € ๋จผ์ € ๋ถˆ๋ ค์ง€๋Š” ํ•จ์ˆ˜์ผ ๋ฟ์ด๋‹ค.

new ์—ฐ์‚ฐ์ด ์ด๋ค„์ง€๋ฉด ๋‹ค์Œ ๊ณผ์ •์ด ์ž๋™์ ์œผ๋กœ ์‹คํ–‰๋œ๋‹ค.

  1. ์ƒˆ๋กœ ๊ตฌ์„ฑ๋œ ๊ฐ์ฒด๊ฐ€ ์ƒ์„ฑ๋œ๋‹ค.
  2. ์ƒˆ๋กœ ๊ตฌ์„ฑ๋œ ๊ฐ์ฒด์ธ Prototype์— ๋งํฌ๋œ๋‹ค.
  3. ์ƒˆ๋กœ ๊ตฌ์„ฑ๋œ ๊ฐ์ฒด๊ฐ€ ํ•จ์ˆ˜ ํ˜ธ์ถœ์ž์˜ this ๋ฐ”์ธ๋”ฉ์„ ์„ค์ •ํ•œ๋‹ค.
  4. ๋ฐ˜ํ™˜๋  ๋‹ค๋ฅธ ๋Œ€์ฒด ๊ฐ์ฒด๊ฐ€์—†์œผ๋ฉด ์ƒˆ๋กœ ๊ตฌ์„ฑ๋œ ๊ฐ์ฒด๊ฐ€ ๋ฐ˜ํ™˜๋œ๋‹ค.

2๋‹จ๊ณ„๋Š” ๋‚˜์ค‘์— 5 Chapter์—์„œ ๋‹ค๋ฃฐ๊ฒƒ์ด๋‹ค.

function foo(a) {
	this.a = a;
}

var bar = new foo( 2 );
console.log( bar.a ); // 2

Everything In Order

์ด์ œ ์šฐ์„ ์ˆœ์œ„์— ๋Œ€ํ•ด ์•Œ์•„๋ณด์ž. ์ฐจ๋ก€๋Œ€๋กœ default binding์˜ ์šฐ์„ ์ˆœ์œ„๊ฐ€ ๊ฐ€์žฅ ๋‚ฎ๋‹ค.

๋จผ์ € ๋ช…์‹œ์  ๋ฐ”์ธ๋”ฉ์ด ์•”์‹œ์  ๋ฐ”์ธ๋”ฉ๋ณด๋‹ค ์šฐ์„ ์ˆœ์œ„๊ฐ€ ๋†’๋‹ค.

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

var obj1 = {
	a: 2,
	foo: foo
};

var obj2 = {
	a: 3,
	foo: foo
};

obj1.foo(); // 2
obj2.foo(); // 3

obj1.foo.call( obj2 ); // 3
obj2.foo.call( obj1 ); // 2

์ „์ฒด๋ฅผ ๋น„๊ตํ•ด๋ณด์ž.

function foo(something) {
	this.a = something;
}

var obj1 = {
	foo: foo
};

var obj2 = {};

obj1.foo( 2 );
console.log( obj1.a ); // 2

obj1.foo.call( obj2, 3 );
console.log( obj2.a ); // 3

var bar = new obj1.foo( 4 );
console.log( obj1.a ); // 2
console.log( bar.a ); // 4
function foo(something) {
	this.a = something;
}

var obj1 = {};

var bar = foo.bind( obj1 );
bar( 2 );
console.log( obj1.a ); // 2

var baz = new bar( 3 );
console.log( obj1.a ); // 2
console.log( baz.a ); // 3

์šฐ๋ฆฌ๊ฐ€ ์•„๊นŒ ์œ„์— ๋งŒ๋“  ๊ฐ€์งœ ๋ฐ”์ธ๋”ฉ์œผ๋กœ ๋Œ์•„๊ฐ€๋ฉด ๋†€๋ผ์šด ๊นจ๋‹ฌ์Œ์„ ์–ป์„ ์ˆ˜ ์žˆ๋‹ค.

function bind(fn, obj) {
	return function() {
		fn.apply( obj, arguments );
	};
}

์šฐ๋ฆฌ๊ฐ€ ๋ฐฉ๊ธˆ ์œ„์—์„œํ•œ๊ฒƒ์ฒ˜๋Ÿผ ํ•˜๋“œ๋ฐ”์ธ๋”ฉ์„ ์žฌ์ •์˜ํ•  ๋ฐฉ๋ฒ•์ด์—†๋‹ค. ์‚ฌ์‹ค ES5์˜ bind()๋Š” ์ƒ๊ฐ๋ณด๋‹ค ๋งค์šฐ ๋ณต์žกํ•˜๋‹ค. ์•„๋ž˜๋Š” bind()์˜ pollyfill์ด๋‹ค.

if (!Function.prototype.bind) {
	Function.prototype.bind = function(oThis) {
		if (typeof this !== "function") {
			// closest thing possible to the ECMAScript 5
			// internal IsCallable function
			throw new TypeError( "Function.prototype.bind - what " +
				"is trying to be bound is not callable"
			);
		}

		var aArgs = Array.prototype.slice.call( arguments, 1 ),
			fToBind = this,
			fNOP = function(){},
			fBound = function(){
				return fToBind.apply(
					(
						this instanceof fNOP &&
						oThis ? this : oThis
					),
					aArgs.concat( Array.prototype.slice.call( arguments ) )
				);
			}
		;

		fNOP.prototype = this.prototype;
		fBound.prototype = new fNOP();

		return fBound;
	};
}
function foo(p1,p2) {
	this.val = p1 + p2;
}

// using `null` here because we don't care about
// the `this` hard-binding in this scenario, and
// it will be overridden by the `new` call anyway!
var bar = foo.bind( null, "p1" );

var baz = new bar( "p2" );

baz.val; // p1p2

Determining this

  1. new ๋กœ ์ƒˆ๋กœ์šด ๊ฐ์ฒด๊ฐ€ ์ƒ์„ฑ๋๋Š”์ง€?
  2. call, apply๋กœ ๋ช…์‹œ์  ๋ฐ”์ธ๋”ฉ์ด ๋๋Š”์ง€?
  3. ์•”์‹œ์  ๋ฐ”์ธ๋”ฉ์ด ๋๋Š”์ง€?
  4. default binding ๊ณ ๋ ค (strict mode)์ธ์ง€ ์•„๋‹Œ์ง€.

Binding Exceptions

Ignored this

apply, call, bind์˜ this ๋ฐ”์ธ๋”ฉ ๋งค๊ฐœ๋ณ€์ˆ˜์— null์ด๋‚˜ undefined๋ฅผ ์ „๋‹ฌํ•˜๋ฉด default binding์ด ๋œ๋‹ค.

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

var a = 2;

foo.call( null ); // 2

๋˜ํ•œ, curry๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋งค์šฐ ์œ ์šฉํ• ์ˆ˜์žˆ๋‹ค.

function foo(a,b) {
	console.log( "a:" + a + ", b:" + b );
}

// spreading out array as parameters
foo.apply( null, [2, 3] ); // a:2, b:3

// currying with `bind(..)`
var bar = foo.bind( null, 2 );
bar( 3 ); // a:2, b:3

Safer this

Object.create(null)๋Š” {}์™€ ๋น„์Šทํ•˜๊ฒŒ ๋นˆ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜์ง€๋งŒ, Object.prototype์— ๋Œ€ํ•œ ์œ„์ž„(delegation)์ด ์—†์œผ๋ฏ€๋กœ ๋” ๋น„์–ด์žˆ๋‹ค๊ณ  ํ•  ์ˆ˜ ์žˆ๋‹ค.

function foo(a,b) {
	console.log( "a:" + a + ", b:" + b );
}

// our DMZ empty object
var รธ = Object.create( null );

// spreading out array as parameters
foo.apply( รธ, [2, 3] ); // a:2, b:3

// currying with `bind(..)`
var bar = foo.bind( รธ, 2 );
bar( 3 ); // a:2, b:3

Indirection

์ฃผ์˜ํ•ด์•ผํ•  ๋˜ ๋‹ค๋ฅธ ์‚ฌํ•ญ์€ ํ•จ์ˆ˜์—๋Œ€ํ•œ ๊ฐ„์ ‘์ฐธ์กฐ๋ฅผ ๋งŒ๋“œ๋Š” ๊ฒฝ์šฐ์ด๋‹ค. ์ด๋Ÿฐ ๊ฒฝ์šฐ ํ•จ์ˆ˜๊ฐ€ ํ˜ธ์ถœ๋˜๋ฉด default binding์ด ์ ์šฉ๋œ๋‹ค.

๊ฐ„์ ‘ ์ฐธ์กฐ๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ ํ• ๋‹น์—์„œ ๋นˆ๋ฒˆํžˆ ๋ฐœ์ƒํ•œ๋‹ค.

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

var a = 2;
var o = { a: 3, foo: foo };
var p = { a: 4 };

o.foo(); // 3
(p.foo = o.foo)(); // 2

Lexical this

์ผ๋ฐ˜์ ์ธ ํ•จ์ˆ˜๋Š” ์œ„์—์„œ ์–ธ๊ธ‰ํ•œ 4๊ฐ€์ง€ ๊ทœ์น™์ด ์ ์šฉ๋œ๋‹ค. ํ•˜์ง€๋งŒ ES6์—์„œ ์†Œ๊ฐœํ•˜๋Š” ํ™”์‚ดํ‘œํ•จ์ˆ˜๋Š” ์ด๋Ÿฐ ๊ทœ์น™์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š”๋‹ค.

ํ™”์‚ดํ‘œํ•จ์ˆ˜๋Š” ๋‘˜๋Ÿฌ์‹ธ๋Š” ๋ฒ”์œ„์—์„œ this๋ฅผ ๋ฐ”์ธ๋”ฉํ•œ๋‹ค.

function foo() {
	// return an arrow function
	return (a) => {
		// `this` here is lexically adopted from `foo()`
		console.log( this.a );
	};
}

var obj1 = {
	a: 2
};

var obj2 = {
	a: 3
};

var bar = foo.call( obj1 );
bar.call( obj2 ); // 2, not 3!

์ผ๋ฐ˜์  ์‚ฌ๋ก€๋Š” ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ๋‚˜ ์ฝœ๋ฐฑ์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ์ด๋‹ค.

function foo() {
	setTimeout(() => {
		// `this` here is lexically adopted from `foo()`
		console.log( this.a );
	},100);
}

var obj = {
	a: 2
};

foo.call( obj ); // 2

๋Š” ์•„๋ž˜์™€ ๋™์น˜

function foo() {
	var self = this; // lexical capture of `this`
	setTimeout( function(){
		console.log( self.a );
	}, 100 );
}

var obj = {
	a: 2
};

foo.call( obj ); // 2

Review (TL;DR)

๋ฐ”์ธ๋”ฉ ๊ทœ์น™ 4๊ฐ€์ง€.
์•ˆ์ „ํ•˜๊ฒŒ this binding์„ํ•˜๋ ค๋ฉด รธ = Object.create(null)๋กœ ์ƒ์„ฑํ•˜์ž.
ES6์˜ ํ™”์‚ดํ‘œํ•จ์ˆ˜๋Š” ์ด์ „ ๋ ˆ๊ฑฐ์‹œ ์ฝ”๋“œ์˜ ํ™•์‹คํ•œ ๋Œ€์ฒด๋ฌผ์ด๋‹ค.