자바스크립트에서 this 키워드는 좀 특별합니다. ES5에서는 bind 메소드를 사용해서 this 키워드를 설정 할 수 있으며, ES2015에서는 arrow functions 을 사용해서 고유의 this 키워드를바인딩 할 수 있습니다. (렉시컬 컨텍스트 안에 this를 유지)
Global context
함수 밖, 글로벌 실행 컨텍스트에서 this는 글로벌 객체를 가르킵니다(strict mode or not)
call, apply 메소드를 사용해서 this 값을 다른 컨텍스트로 전달 할 수 있습니다.
1 2 3 4 5 6 7 8
var obj = {a: 'Custom'}; var a = 'Global'; functionwhatsThis(arg) { returnthis.a; } whatsThis(); // 'Global' whatsThis.call(obj); // 'Custom' whatsThis.apply(obj); // 'Custom'
call과 apply의 차이점은 두 번째 파라미터에 배열값을 전달 할 수 있는가 없는가 입니다. 첫 번째로 전달되는 this는 객체로, 숫자나 문자열이 전달 되어도 ToObject로 인해 객체로 변환됩니다.
1 2 3 4 5 6
functionadd(c, d) { returnthis.a + this.b + c + d; } var o = {a: 1, b: 3}; add.call(o, 5, 7); // 16 add.apply(o, [10, 20]); // 34
f.bind(someObject)은 f와 같은 바디와 스코프를 가진 새로운 함수를 생성합니다. 하지만. this는 본래 함수에서 발생합니다. bind는 중복 설정되지 않고 한 번만 가능합니다.
1 2 3 4 5 6 7 8 9
functionf() { returnthis.a; } var g = f.bind({a: 'azerty'}); console.log(g()); // azerty var h = g.bind({a: 'yoo'}); // bind only works once! console.log(h()); // azerty var o = {a: 37, f: f, g: g, h: h}; console.log(o.f(), o.g(), o.h()); // 37, azerty, azerty
arrow 함수에서 this 는 렉시컬 컨텍스트와 연결됩니다. 글로벌 코드에서는 글로벌 객체와 연결됩니다. obj.bar 의 익명함수1 안에 arrow 함수로 선언된 익명함수2의 this는 익명함수1의 this와 연결되어 있고, 이 this는 다시 obj 객체와 연결되어 있습니다.
1 2 3 4 5 6 7 8 9 10 11 12
// 예시 1 var globalObject = this; var foo = (() =>this); console.log(foo() === globalObject); // true // 예시 2 var obj = {bar: function() { var x = (() =>this); return x; } }; var fn = obj.bar(); console.log(fn() === obj); // true
함수가 객체의 메소드로 호출되면, 이것의 this는 메소드를 호출한 객체와 연결됩니다. o.f()가 호출되면, 함수 내부의 this는 o 객체가 된다.
1 2 3 4 5 6 7
var o = { prop: 37, f: function() { returnthis.prop; } }; console.log(o.f()); // 37
프로토타입 체인에서도 this는 함수가 호출된 객체에 지정이 됩니다.
1 2 3 4 5
var o = {f: function() { returnthis.a + this.b; }}; var p = Object.create(o); p.a = 1; p.b = 4; console.log(p.f()); // 5
수정된 프로그램의 영향이 전체 소스에 퍼지지 않도록 getter, setter 사용합니다. 예를들어
1 2 3 4 5 6
//기존방법 var o = {}; o.num = 10; // 개선방법 var o = {}; Object.defineProperty(o, 'num', {value:10});
defineProperty 함수에서 가장 중요한 것은 세번째 옵션으로 들어가는 인자입니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
value : 속성값 writable : 속성값 변경 여부 configurabl e: 속성의 옵션값 변경 여부 enumerable : forin 반복만 사용 가능 여부 get : value, writable 과 함꼐 사용 못함 set : value, writable 과 함꼐 사용 못함
var 원 = {}; 원._반지름 = 0; // 겟터 셋터 대상 및 초기값 지정 Object.defineProperty( 원, '반지름', { get : function() { returnthis._반지름; }, set : function(값) { this._반지름 = 값; } }); // 사용예 원.반지름 = 5; document.write('원.반지름 = ', 원.반지름);
defineProperty없이 getter, setter 함수에 대해 알아보도록 하겠습니다. 아래처럼 person 객체에 get, set 함수를 정의해서 사용가능합니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
var person = { firstName: 'Jimmy', lastName: 'Smith', get fullName() { returnthis.firstName + ' ' + this.lastName; }, set fullName (name) { var words = name.toString().split(' '); this.firstName = words[0] || ''; this.lastName = words[1] || ''; } } person.fullName = 'Jack Franklin'; console.log(person.firstName); // Jack console.log(person.lastName) // Franklin
defineProperty에 의해 생성된 sum은 호출시 this가 o 객체를 향하고 있습니다.