[You don't know JS] this 란 무엇인가

리린·2021년 6월 4일
0

you don't know js

목록 보기
1/1

this는 호출부이다

  • 호출부: 현재 실행중인 함수 직전의 호출 코드 내부에 있음

기본 바인딩

  • 단독 함수 실행할 경우
  • 호출부 == 전역공간
  • 코드
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 콘텍스트로 하드코딩된 새 함수를 반환

new 바인딩

  • 새로 생성된 객체는 해당 함수 호출 시 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;

순서

  • 1순위: 함수 표현식으로 하드바인딩 되었는가

    this는 bind의 첫번째 인자다

  • 2순위: new로 함수를 호출하였는가

    var bar = new foo();
    // this는 새로 생성된 객체다

  • 3순위: call과 apply로 함수를 호출하거나 bind 하드바인딩 내부에 숨겨진 형태로 호출됐는가?

    var bar = foo.call(obj2);
    // this는 call / apply / bind 의 첫 번째 인자다

  • 4순위: 함수를 콘텍스트 형태로 호출했는가?

    var bar = obj1.foo();
    // this는 점 앞의 객체다

  • 5순위: 그 외

    var bar=foo()
    // this는 전역객체다

예외

  1. this가 무시됨:
  • 현상: call, apply, bind 메서드에 첫 번째 인자로 null 또는 undefined를 넘가면 this 바인딩이 무시되고 기본 바인딩 규칙이 적용된다
  • 문제점: null이 헷갈릴 수 있다.
    해결방법: null 대신 공집합 기호 ∅를 사용하자
  1. 간접 레퍼런스
  • 현상: 함수 할당문 사용시 결과값은 원 함수 객체의 레퍼런스다
  • 코드
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 (전역)
  1. 소프트 바인딩
  • 하드 바인딩의 경직성 해결방법: 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
  1. 화살표 함수
  • 한 번 결정되면 끝: 4가지 규칙 중 어느 것으로도 오버라이드할 수 없다.
  • 코드: 화살표 함수는 this가 고정된다
function foo() {
	setTimeout(()=>{
    		// 여기서 'this'는 어휘적으로 'foo()'에서 상속된다.
        	console.log(this.a);
       	}, 100);
}
var obj = {
	a:2
};
foo.call( obj ); //2
  1. 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

this 코딩 스타일 고정하기

둘 중 하나만 택하자

  1. 오직 렉시컬 스코프만 사용하던가(화살표 함수, var self =this 등)
  2. 완전한 this 스타일(전통적인 4개 방법) 구사하던가.
profile
개발자지망생

0개의 댓글