자바스크립트 입문_this (여러가지 상황에 따른)

자바스크립트 2021. 5. 4. 17:43

(본 포스팅은 위키북스의 '코어자바스크립트' 책을 공부하면서 작성되었습니다_내돈내산)

 

<전역공간에서의 this>

  • 전역공간에서 this는 전역 객체를 가리킴. 전역 객체는 자바스크립트 런타임 환경에 따라 다른 이름과 정보를 가짐.
  • 브라우저 환경에서 전역객체는 window이고 Node.js환경에서는 global임.
// 브라우저 환경에서 this
console.log(this); 		// {alert: f(), atob: f(), blur: f() ....}
console.log(window); 		// {alert: f(), atob: f(), blur: f() ....}
console.log(this === window);	// true

// Node.js환경에서 this
console.log(this);		// { process : {title: 'node', version: ....}
console.log(global);		// { process : {title: 'node', version: ....}
console.log(this === windows);	// true

 

  • 전역변수를 선언하면 자바스크립트 엔진은 이를 전역객체의 프로퍼티로 할당함
var a = 1;
console.log(a);		// 1 (스코프체인에서 검색한 a)
console.log(window.a);	// 1 (전역객체의 프로퍼티 a)
console.log(this.a);	// 1 (this의 프로퍼티의 a)

 

  • 삭제명령을 할때 전역객체의 프로퍼티 할당
/*--------------------------------------------------------------------------*/
var a = 1;
delete window.a;			//false
console.log(a, window.a, this.a);	// 1 1 1
/*--------------------------------------------------------------------------*/
var b = 2;
delete b;					// false
console.log(b, window.a, this.a);	//2 2 2
/*--------------------------------------------------------------------------*/
window.c = 3;
delete window.c;	// true
console.log(c, window.c, this.c) // Uncaught ReferenceError: c is not defined
/*--------------------------------------------------------------------------*/
window.d = 4;
delete d;		// false
console.log(d, window.d, this.d); // Uncaught ReferenceError: c is not defined

처음부터 전역객체의 프로퍼티로 할당한 경우에는 삭제가 되지만, 전역변수로 처음부터 선언한 경우에는 삭제가 되지 않음. 전역변수를 선언하면 자바스크립트 엔진이 자동으로 전역객체의 프로퍼티로 할당시킴.


<메서드로서 호출할때 그 메서드 내부에서의 this>

  • 어떤 함수를 메서드로서 호출하는 경우 호출주체는 바로 함수명(프로퍼티명)앞의 객체가 됨.
var obj = {
    methodA : function() {console.log(this);},
    inner :{
    	methodB : function() {console.log(this);}
    }
};

obj.methodA();			// { methodA: f, inner : {....}} (===obj)
obj['methodA']();		// { methodA: f, inner : {....}} (===obj)

obj.inner.methodB();		// { methodB: f } (===obj.inner)
obj.inner['methodB']();		// { methodB: f } (===obj.inner)
obj['inner'].methodB(); 	// { methodB: f } (===obj.inner)
obj['inner']['methodB'](); 	// { methodB: f } (===obj.inner)

<함수로서 호출할때 그 함수 내부에서의 this>

  • 함수를 함수로서 호출하는 경우는 this가 지정되지 않음. 함수에서의 this는 전역 객체(window, global 등)를 가리
  • 메서드 내부 함수에서의 this
obj1 = {
    outer: function() {						(1)
    	console.log(this);					(3)(4)
        var innerFunc = function() {				(5)
        		console.log(this);			(7)(8)(12)
        	}
            innerFunc();					(6)
            
            var obj2 = {					(9)
            	innerMethod: innerFunc				(11)
            };
            obj2.innerMethod();					(10)
       }
};
obj1.outer();							(2)
            	
  1. obj1 객체 생성. 객체내부에는 outer라는 프로퍼티가 있으며 이에는 익명함수가 연결됨.
  2. obj1.outer 호출
  3. obj1.outer 실행컨텍스트가 생성되며 호이스팅, 스코프체인수집, this바인딩 등이 수행됨. 이때 this에는 outer를 감싸는 객체인 obj1이 바인딩됨.
  4. obj1의 객체정보가 console.log명령어에 의해 출력됨.
  5. 호이스팅된 변수 innerFunc는 outer 스코프 내에서만 접근할 수 있는 지역변수임. 여기에 익명함수를 할당함.
  6. innerFunc()를 호출
  7. innerFunc()의 실행컨텍스트가 생성되면서 호이스팅, 스코프체인 수집, this바인딩 등이 수행됨. 이 함수를 호출할때 함수명앞에 점(.)이 없었음 즉 함수로서의 호출이 이루어졌으므로, this는 지정되지 않고 자동으로 전역객체가 바인딩 됨.
  8. Window 객체 정보가 출력됨.
  9. 호이스팅된 obj2역시 outer 내부에서만 접근가능한 지역변수임. 여기서는 객체를 재할당하는데, innerMethod라는 프로퍼티에 innerFunc()가 할당되어 있음.(정확히는 innerFunc()에 할당된 익명함수가 할당됨)
  10. obj2.innerMethod()를 호출함.
  11. obj2.innerMethod()함수의 실행컨텍스트가 생성되며 이 함수는 메서드로써 호출된 것이기 때문에 this에는 점(.) 앞의 객체인 obj2가 바인딩 되게 됨.
  12. innerFunc()에 할당된 익명함수에 의해 obj2의 객체 정보가 출력됨.

  • 메서드의 내부함수에서의 this를 우회하는 법 : 변수를 활용함, 상위 스코프의 this를 저장해서 내부함수에서 활용할려는 수단. 
var obj = {
  outer: function () {
    console.log(this); // - obj
    var innerFunc1 = function () {
      console.log(this); // Window
    }
    innerFunc1();

    var self = this; // outer 스코프에서 self라는 변수에 this를 저장함.
    var innerFunc2 = function () {
      console.log(self); // obj
    }
    innerFunc2();
  }
};
obj.outer();

  • this를 바인딩하지 않는 함수(화살표함수; arrow function)
  • 화살표 함수의 경우 실행컨텍스트를 생성할때 this바인딩 과정이 없음. 상위 스코프의 this를 그대로 가져다가 활용이 가능함. 우회법을 사용하지 않아도 됨.
var obj = {
  outer: function () {
    console.log(this); // obj
    var innerFunc = () => {
      console.log(this); // obj
    };
    innerFunc();
  }
};
obj.outer();

<콜백함수 호출 시 그 함수 내부에서의 this>

  • 함수의 제어권을 다른 함수에게 넘겨주는 경우 함수 A를 콜백함수라고 함.
  • 콜백함수의 경우 this를 상속하는 함수도 있지만, 그렇지 않은 경우가 있어서 반드시 이렇다 할 답이 있는 것은 아님. 콜백함수의 제어권을 가지는 함수가 this를 무엇으로 할지 결정하기 때문에 특별히 정의하지 않는 경우에는 기본적으로 함수와 마찬가지로 전역객체를 바라보게 됨.
[1, 2, 3, 4, 5].forEach(function (x) {
  console.log(this, x); // Window 1, Window 2, Window 3, Window 4, Window 5
});

document.body.innerHTML += '<button id="a">클릭</button>';
document.body.querySelector('#a')
  .addEventListener('click', function (e) {
    console.log(this, e); // button object
  });

<생성자 함수 내부에서의 this> 

var Cat = function (name, age) {
  this.bark = '야옹';
  this.name = name;
  this.age = age;
};
var choco = new Cat('초코', 7);
var nabi = new Cat('나비', 5);
console.log(choco, nabi);
  • 자바스크립트는 함수에 생성자로서의 역할을 함께 부여
  • new 명령어와 함께 함수 호출 시 생성자로서 동작
  • 함수가 생성자 함수로서 호출 된 경우 내부에서의 this는 곧 새로 만들 인스턴스 자신을 가리킴
  • 인스턴스 생성 과정
    • 생성자 함수 호출
    • 생성자의 prototype 프로퍼티를 참조하는 __proto__ 라는 프로퍼티가 있는 객체 생성
    • 미리 준비 된 공통 속성 및 개성을 해당 객체(this)에 부여
admin