- 단독 함수 실행할 경우
- 호출부 == 전역공간
- 코드
function foo() { console.log(this.a); } var a =2; foo();
- this 가 가리키는 호출부:
엄격 모드 - undefined / 비엄격모드 - 전역객체
- 호출부에 콘텍스트 객체가 있을 경우
- 호출부 == 콘텍스트 객체
- 코드1: 암시적 바인딩
- this 가 가리키는 호출부: obj
function foo() { console.log(this.a); } var obj={ a:2, foo: foo } obj.foo(); //2
- 코드2: 체이닝된 형태
- this는 최상위 /최하위 수준의 정보만 호출부와 연관된다(obj1.a의 값은 무시)
function foo() { console.log(this.a); } var obj2={ a:42, foo: foo } var obj1={ a:2, obj2: obj2 } obj1.obj2.foo();//42 obj.foo(); //2
- 코드3: 암시적 소실
- 콜백 함수를 사용할 경우 내부에서 어떻게 this가 바인딩될지 모르므로 this 바인딩이 소실될 수 있다.
function foo() { console.log(this.a); } var obj = { a:2, foo }; var a = "엥 전역이네!"; setTimeout(obj.foo, 100); // "엥, 전역이네!"
- call(), apply(), bind() 메서드의 첫째 인자로 this를 지정할 수 있다.
- 코드1: call()의 첫째 인자에 obj를 넘김으로써 this를 obj로 지정함
function foo() { console.log(this.a); } var obj = { a:2 }; foo.call(obj); //2
- 코드2: 하드바인딩(꼼수)
- 인자를 넘기고 반환 값을 돌려받을 때, 헬퍼 함수 등에 사용
function foo() { console.log(this.a); } var obj={ a:2 }; var bar = function() { foo.call(obj); }; bar(); //2 setTimeout(bar, 100); //2 bar.call(window); //2
- 코드3: bind()를 사용한 하드 바인딩
- bind()는 주어진 this 콘텍스트로 하드코딩된 새 함수를 반환
- 새로 생성된 객체는 해당 함수 호출 시 this로 바인딩된다
- 코드1: this로 바인딩된 bar 함수
- this는 bar함수
function foo(a) { this.a=a; } var bar = new foo(2); console.log(bar.a); //2
- 코드2: bind로 지정된 this가 new로 오버라이딩 될 때, 어차피 오버라이딩 되니 첫 인자를 null로 지정할 수 있다.
function foo(p1, p2) { this.val = p1 + p2; } var bar = foo.bind(null, "p1"); var baz = new bar("p2"); baz.val;
this는 bind의 첫번째 인자다
var bar = new foo();
// this는 새로 생성된 객체다
var bar = foo.call(obj2);
// this는 call / apply / bind 의 첫 번째 인자다
var bar = obj1.foo();
// this는 점 앞의 객체다
var bar=foo()
// this는 전역객체다
- this가 무시됨:
- 현상: call, apply, bind 메서드에 첫 번째 인자로 null 또는 undefined를 넘가면 this 바인딩이 무시되고 기본 바인딩 규칙이 적용된다
- 문제점: null이 헷갈릴 수 있다.
해결방법: null 대신 공집합 기호 ∅를 사용하자
- 간접 레퍼런스
- 현상: 함수 할당문 사용시 결과값은 원 함수 객체의 레퍼런스다
- 코드
function foo() { console.log(this.a); } var a = 2; var o = {a:3, foo: foo}; var p = {a: 4}; o.foo(); (p.foo = o.foo)(); // 2 (전역)
- 소프트 바인딩
- 하드 바인딩의 경직성 해결방법: this 가 전역 객체나 undefined인 경우 미리 준비한 대체 기본 객체(obj)로 세팅함
- 명시적 바인딩(call, apply, bind 등등)의 장점 + 전역 객체, undefined 가 아닌 다른 기본 바인딩 값 세팅 가능하다는 장점
- 코드
function foo() { console.log("name: " + this.name); } var obj = { name: "obj" }, obj2 = { name: "obj2" }, obj3 = { name: "obj3" }; var fooOBJ = foo.softBind( obj ); fooOBJ(); // name: obj obj2.foo = foo.softbind( obj ); obj2.foo(); // name: obj2 fooOBJ.call(obj3); // name: obj3 setTimeout(obj.foo, 10); //name: obj
- 화살표 함수
- 한 번 결정되면 끝: 4가지 규칙 중 어느 것으로도 오버라이드할 수 없다.
- 코드: 화살표 함수는 this가 고정된다
function foo() { setTimeout(()=>{ // 여기서 'this'는 어휘적으로 'foo()'에서 상속된다. console.log(this.a); }, 100); } var obj = { a:2 }; foo.call( obj ); //2
- self
- 한 번 결정되면 끝: 4가지 규칙 중 어느 것으로도 오버라이드할 수 없다 (화살표 함수와 동일 )
- 코드: self는 this를 고정시킨다
function foo() { var self = this; //this를 어휘적으로 표시한다 setTimeout(function(){ console.log(self.a); }, 100); } var obj = { a:2 }; foo.call( obj ); //2
둘 중 하나만 택하자
- 오직 렉시컬 스코프만 사용하던가(화살표 함수, var self =this 등)
- 완전한 this 스타일(전통적인 4개 방법) 구사하던가.