코어자바스크립트(this)

L·2022년 11월 6일
0

코어자바스크립트

목록 보기
3/6
post-thumbnail

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

자바스크립트에서 this는 실행 컨텍스트가 생성될 때 함께 결정. 함수를 호출할 때 결정됨.

1-1.전역 공간에서의 this

전역 공간에서 this는 런타임 환경에 따라 다른데, 브라우져에서는 window는 nodeJS에서는 global객체를 말함.

var a = 1;
console.log(a);//1
console.log(window.a);//1
console.log(this.a);//1

전역 공간에 a변수를 할당했을 뿐인데, window,this객체에 1이 나오는 이유는 자바스크립트의 모든 변수는 특정 객체(window)의 프로퍼티로써 동작 하기 떄문. 즉, 전역 변수를 선언하면 자바스크립트 엔진은 이를 전역객체의 프로퍼티로 할당.

1-2. 메서드로서 호출할 때 메서드 내부에서의 this

함수 vs 메서드

  • 차이점은 독립성으로 함수는 그 자체에 독립적인 기능이 있지만, 메서드는 자신이 호출한 대상 객체에 관련된 동작을 수행한다는 차이점이 있음.
var func = function(x){
  console.log(this,x);
}
func(1);
var obj={
  method:func
};
obj.method(2);

1 .func 변수에 익명함수를 할당후 func 함수 실행시 결과는 window객체와 1이 나옴.
2 .obj 변수에 method프로퍼티에 func 함수를 할당 후 method호출시 obj객체와 2가 나옴.

즉, 함수를 어떻게 호출하느냐에 따라 this값이 달라짐.

메서드 내부에서의 this

var obj = {
  A:function(){
    console.log(this);
  },
  inner:{
	B:function(){
     console.log(this);
   }
  }
};
obj.A() // {inner:{...}, A:f}
obj.inner.B() // {B:f}

이전에 this에 대한 정의를 함수를 호출할 때 결정된다고했는데 이를 대입해보면 A 메서드를 호출하면 호출의 주체는 obj객체이기 때문에 thisobj 객체가 나오고 B메서드를 호출하면 호출의 주체는 obj객체의 inner객체에서 호출했기 때문에 inner객체가 나옴.

1-3. 함수로서 호출할 때 그 함수 내부에서의 this

함수 내부에서의 this

함수가 호출이 되는(=실행컨텍스트가 생성이 되는 순간) 순간에 this가 지정된다고했음. 그래서 함수에서의 this는 전역객체를 가리킴.

메서드의 내부함수에서의 this

var obj1 = {
  outer:function(){
    console.log(this);
    var innerFunc = function(){
      console.log(this);
    };
    innerFunc();
    
    var obj2 = {
      innerMethod: innerFunc
    };
    obj2.innerMethod();
  }
};
obj1.outer();

1 . obj1변수에 outer 프로퍼티를 할당하고 데이터는 익명함수를 할당하고 호출.
2 . obj1.outer의 실행 컨텍스트가 생성. 호이스팅으로 인해 innerFunc,obj2 변수가 맨위로 올라옴.
3 . 콘솔에 this 를 출력. this에 대한 정의를 대입하면 obj1 객체에서 호출했기때문에 obj1객체정보가 나옴.
4 . innerFunc 식별자에 익명함수 할당하고 호출.
5 . innerFunc 함수의 실행 컨텍스트가 생성. 이 때, 해당 함수를 단독으로 호출했기 때문에 콘솔에서 this는 전역객체가 나옴.(해당 함수 호출시 .이 없었기때문에 전역 객체가 나옴)
6 . obj2 변수에 innerMethod 프로퍼티에는 변수 innerFunc의 익명함수 할당하고 innerMethod함수 메서드 호출.
7 . 콘솔에 this 를 출력. this에 대한 정의를 대입하면 obj2 객체에서 호출했기때문에 obj2객체정보가 나옴.

즉, this 바인딩은 주변 환경이 중요한것이 아닌 누가 함수를 호출했느냐로 결정이 됨.

메서드의 내부 함수에서의 this 우회 방법.

  • 1) 상위 스코프에 this 객체 값을 할당받은 변수를 선언하는 방법
var obj = {
  outer : function(){
    console.log(this);
    var innerFunc1 = function(){
      console.log(this);
    }
    innerFunc1();
    var self = this;
    var innerFunc2 = function(){
      console.log(self);
    }
    innerFunc2();
  }
}
obj.outer();
  • 2) Arrow Function(화살표 함수)사용.(ES6)
var obj = {
  outer : function(){
    console.log(this);
    var innerFunc1 = function(){
      console.log(this);
    }
    innerFunc1();

    var innerFunc2 = ()=>{
      console.log(this);
    }
    
    innerFunc2();
  }
}
obj.outer();

화살표 함수는 실행 컨텍스트 생성시 this 바인딩 과정 자체가 빠지게 되어, 상위 스코프의 this를 그대로 활용.

1-4.콜백 함수 호출 시 그 함수 내부에서의 this

콜백함수를 매개변수로 받은 코드 내부에서 어떻게 처리 하느냐에 따라 this 가 달라짐.

function callback(){
 console.log(this);
}
var obj1 = {
 A:function(cb){
   cb();
   cb.call(this);
 }
}
obj1.A(callback);

1 .cb() 함수를 그냥 호출시 함수를 단독으로 호출했기 때문에 window객체가 나옴.
2 . call 함수를 통해 cb() this객체를 명시적으로 obj1객체로 바인딩 후 함수를 호출. 즉 obj1 객체가 나옴.

function callback(){
 console.log(this);
}
var obj1 = { NAME : 'HGD' }
setTimeout(callback,500);
setTimeout(callback.bind(obj1),500);
  1. setTimeout 함수 500ms이후에 콜백 함수를 호출시 나오는 this 객체를 임의로 변경할수 없기때문에, 첫번째는 window 객체가 나옴.
  2. 이번에는 callback함수에 this값을 obj1으로 바인딩 후, 500ms있다가 콜백함수를 호출하면, ob1객체가 나옴.
//document.body.innerHTML = `<a id="click">클릭</a>`
document.querySelector('#click').addEventListener('click',function(){ console.dir(this)});

id가 click인 태그에 클릭이벤트 추가. 클릭 시 두번쨰 인자에 있는 콜백함수를 실행. 함수 내용은 this객체를 출력하는데, 여기서는 id가 click인 태그에 관한 정보가 출력.
addEventListener 안의 소스 내용은 잘 모르지만, 콜백함수 실행시, 단독으로 호출이 아닌 명시적으로 태그정보를 바인딩하여 호출했음을 짐작할 수 있음.

1-5.생성자 함수 내부에서의 this

new명령어를 통한 인스턴스를 생성시, this는 해당 인스턴스 객체가 됨.

function Human (name,age){
	this.name=name;
	this.age = age
}
var HongGilDong = new Human('홍길동',30);
console.log(HongGilDong); // {name:'홍길동',age:30}

2.명시적으로 this를 바인딩하는 방법

2-1 call

Function.prototype.call(thisArg,[arg1,,,[arg2,,]])

함수를 즉시실행하는 메서드. 매개변수thisArg에서 this를 바인딩하고 호출할 함수의 매개변수를 넣어서 실행.

2-2 apply

Function.prototype.apply(thisArg,[argArray])

call메서드와 완전 동일. 차이점은 호출할 함수의 매개변수를 배열로 받는것이 차이.

2-3 bind

Function.prototype.bind(thisArg,[arg1,[arg2[,...]]])

call메서드와 비슷하지만, 즉시 호출하지않고 넘겨 받은 this 및 매개변수인자들을 바탕으로 새로운 함수를 반환하는 메서드.

2-4 call,apply,bind를 이용한 this를 내부함수나 콜백 함수에 전달하기

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

이전에 정리해뒀던 메서드의 내부 함수에서의 this 우회 방법.에서 우회 방법을 사용하지않고도 call,bind,apply메서드를 통해 깔끔하게 처리가능.

2-5 화살표 함수

ES6에서 새로 도입. 실행 컨텍스트 생성시 this를 바인딩하는 과정이 제외됨. 즉, 함수 내부에 this는 아예없기때문에 스코프체인상 가까운 this에 접근.

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

이 때 innerFunc함수에서의 this는 스코프체인상 가까운 obj객체가 나옴.


정리

  1. 전역 컨텍스트에서 this는 전역객체(브라우져에서 this, NodeJS는 global객체)
  2. 함수를 메서드로부터 호출한 경우에는 this는 메서드 호출 주체가 됨.
  3. 함수내에서 함수로 호출한 경우에는 this는 전역객체를 가리킴.
  4. 콜백 함수 내부에서의 this는 해당 함수에서 정의된 바에 따르며, 특별한 경우는 전역객체를 가리킴.
  5. new명령어를 통해 생성한 인스턴스 객체에서의 this는 인스턴스 객체를 가리킴.
  6. call,apply,bind 메서드를 통해 this를 바인딩할수있으며, call,apply는 바인딩과 동시에 함수를 실행.

0개의 댓글