1. 상황에 따라 달라지는 this

·this는 실행 컨텍스트가 생성될 때 결정됨

  -실행 컨텍스트는 함수가 호출될 때 생성되므로 this는 함수를 호출할 때 결정됨

 

 1) 전역 공간의 this

  -브라우저 환경일 때: this === window

 

  -Node.js 환경일 때: this === global

  -전역 변수를 선언하면 전역 변수를 전역 객체의 프로퍼티로 할당함

   →a를 1로 선언

  →선언한 a를 출력하면 1이 출력됨

  →this.a(객체 this의 프로퍼티 a)를 출력하면 마찬가지로 1이 출력됨

  →window.a(브라우저 환경에서 window === this이므로 this.a와 같음)

 

  →결과적으로 var a = 1;과 window.a = 1은 똑같이 전역 변수 a를 선언한 효과를 가짐

  →하지만, 삭제 명령에서 전역변수로의 선언과 전역 객체의 포로퍼티로의 선언은 다른 결과를 가짐

  →전역 변수로 선언한 a, b는 delete 명령어로 전역객체에서 삭제하는 명령이 false로 출력되며 다시 출력해도 정상적으로 출력됨

  →전역 객체의 프로퍼티로 선언한 c, d는 delete 명령어로 전역객체에서 삭제하는 명령이 true로 출력되며 다시 출력하면 이미 삭제된 상태이므로 에러가 남

 

 

 2) 메서드로서 호출할 때 메서드 내부의 this

  -함수: 함수는 그 자체로 독립적인 기능을 수행

  -메서드: 메서드 자신을 호출한 대상 객체에 관한 동작 수행

  -자바스크립트에서는 상황별로 this에 다른 값을 부여하며 이를 구별

// 함수
var func = function (x) {
  console.log(this, x);
};
func(1);

// 결과: Window{ ... } 1
// this에 전역객체 Window가 할당됨


// 메소드
var obj = {
  method: func // 객체 obj안에 method로 위에서 정의한 함수 func를 할당
};
obj.method(2);

// 결과: {method: f} 2
// this에 obj가 할당됨

 

  -함수는 함수 자체의 이름으로 호출 / 메서드는 어떤 객체의 메서드이므로 객체이름.메서드 또는 객체이름['메서드']로 호출

// 메서드로 함수 정의까지 한번에 하는 방법
var obj = {
  method: function(x) {console.log(this, x);}
};

obj.method(1);      // {method: f} 1
obj['method'](2);   // {method: f} 2

 

  -메서드 내부에서의 this: 메서드를 호출하는 주체는 메서드를 담고 있는 객체이므로 this === 객체가 됨

  -객체 내부에 객체를 생성하여 그 내부에 메서드를 정의할 경우, this === 마지막 객체(메서드 바로 윗단계의 객체)가 됨

var obj = {
  methodA: function() {console.log(this);},
  inner: {
    methodB: function() {console.log(this);}
  }
};

obj.methodA();         // {methodA: f, inner: {...}} => this에 객체 obj가 출력됨
obj.inner.methodB(); // {methodB: f} => this에 객체 obj.inner가 출력됨

 

 

 3) 함수로서 호출할 때 함수 내부의 this

  -this에는 호출한 주체에 대한 정보가 담기는 데 함수는 개발자가 직접 코드를 통해 호출하므로 호출 주체가 명확하지 않아 this에는 전역객체가 담김

  -메서드의 내부함수의 this

var obj1 = {
  outer: function(){
  
    console.log(this); // (2)
    
    var innerFunc = function(){ // (3)
      console.log(this); // (4)
    }
    
    innerFunc(); // (4)
    
    var obj2 = { // (5)
      innerMethod: innerFunc
    };
    
    obj2.innerMethod(); // (6)
    
  }
};

obj1.outer();

   (1) obj1이 선언된 뒤 obj1.outer()를 호출

   (2) outer 메서드는 obj1 객체 내부에서 정의된 메서드이므로 이때의 this는 메서드 바로 윗단계의 객체, obj1이 할당됨

   (3) innerFunc는 outer 메서드 내부에서 정의된 함수

   (4) innerFunc()를 통해 호출하면 메서드가 아닌 함수로써 호출한 것이므로 호출 주체가 명확하지 않아 this에 전역 객체(Window)가 할당됨

   (5) var obj2라는 객체를 하나 더 생성한 뒤 메서드로서 innerFunc를 정의

   (6) obj2.innerMethod()와 같이 메서드로써 호출하면 this에 메서드 호출의 객체 obj2가 할당됨

 

  -함수로 호출되었는지(this에전역객체 Window 할당) 메서드로 호출되었는지(this에 메서드의 객체 할당) 확인하면 this에 어떤 값이 할당되는 지 알 수 있음

 

  -메서드 내부 함수에서 this 우회하는 방법

  →변수를 통한 우회

var obj = {
  outer: function(){
    var self = this;
    var innerFunc = function(){
      console.log(self); // obj
    };
    innerFunc();
  }
};
obj.outer();

  →obj.outer에서 this는 outer메서드를 호출한 객체 obj이므로 innerFunc로 들어가기전 임의의 변수(self)에 obj로 할당된 this를 저장하면

        함수인 innerFunc에 들어가서도 this를 obj로 쓸 수 있음

 

  →화살표 함수를 통한 우회

var obj = {
  outer: function(){
    var innerFunc = () => {
      console.log(this); // obj
    };
    innerFunc();
  }
};
obj.outer();

   →화살표 함수를 사용하면 실행 컨텍스트 생성 시 this 바인딩 과장이 빠져 상위 스코프의 this를 그대로 활용 가능

 

 

 4) 콜백함수 내부의 this

  -콜백함수: 함수 A의 제어권을 다른 함수(또는 메서드) B에게 넘겨주는 경우, 함수 A를 콜백함수라고 함

  -콜백함수도 함수이므로 기본적으로는 this에 전역객체 할당하지만 콜백함수에 별도의 대상을 지정할 수 있음

// 01. 300ms(0.3초) 뒤에 console에 this를 출력
setTimeout(function() {console.log(this);}, 300};
// 일반 함수와 마찬가지로 this에 전역객체가 할당되고 0.3초뒤에 전역 객체가 출력됨

// 02
[1, 2, 3, 4, 5].forEach(function (x) {
  console.log(this, x);
});
// 전역객체 + 리스트의 숫자가 각각 한번씩 출력(전역객체가 총 5번 출력되고 끝에 숫자는 리스트내 숫자가 바뀌며 출력됨)

// 03. 브라우저 마지막에 '클릭'이 쓰인 버튼을 추가하고, 버튼에 'a'라는 id 부여
document.body.innerHTML += '<button id = "a".클릭</button>';
document.body.querySelector('#a')
    .addEventListener('click', function(e) {
      console.log(this, e);
    });
// 클릭을 할 때마다 이벤트 정보를 콜백함수의 첫번째 인자로 삼아 함수를 실행
// addEventListener 메서드는 콜백 함수 호출 시 자신의 this를 상속하도록 정의되어 addEventListener의 .앞부분은 this가 됨
// 따라서 console에 앞서 지정한 엘리먼트와 클릭 이벤트에 대한 정보가 출력됨

 

 

 5) 생성자 함수 내부의 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);

/* 결과
Cat {bark: '야옹', name: '초코', age: 7}
Cat {bark: '야옹', name: '나비', age: 5}
*/

   →생성자 함수 Cat에 이름과 나이는 변수로 받아 적용하고 bark는 '야옹'으로 통일

   →new 명령어와 함께 이름과 나이를 인자로 주면 새로운 Cat객체가 생성

   →이때 생성자 함수 내부의 this는 새로 생성되는 인스턴스 자신이 됨(choco, nabi)

   →따라서, choco를 생성할 때 넘겨준 인자 '초코'와 7은 각각 name과 age에 대입되어 choco.name, choco.age가 됨

  →console에 choco를 출력하게 되면 choco.bark('야옹'), choco.name('초코'), choco.age(7)이 각각 잘 대입되어 출력됨 

+ Recent posts