Javascript this

L·2021년 4월 20일
0

Javascript

목록 보기
1/5

Javascript에서 this란?

일반적인 객체지향 언어에서의 this는 자신을 가리키는 참조변수이지만, Javascript의 this는 어디에서 호출하는 방법 에 따라 달라집니다. 이번 포스팅에서는 this를 호출을 하느냐에 따라 값들이 어떻게 달라지는지 알아보겠습니다.

1.window

  • 기본적으로 전역에서 this는 엄격 모드 여부에 관계 없이 전역 객체(window)를 참조합니다.
console.log(window===this); //true
  • 전역으로 선언되어진 함수 안의 함수에서도 this는 값이 호출에 의해 설정되지 않았으므로, window 객체를 가리킵니다.
function func(){
	console.log(this); // window
    function inner(){
    	console.log(this);//window
    }
    inner();
}
func();
  • 하지만 use strict모드에서는 this는 undefined를 return 합니다.
'use strict';
console.log(this); // undefined

2.객체에서의 This

지금부터는 this가 window객체가 아닌 경우를 알아보겠습니다.

var name='nodejs';
   function func() {
  let obj = {
    name : 'javascript',
    sayName: function(){
      console.log(this);
      console.log(`window is this?? ${window===this}`);
      console.log(this.name);
    }
  };
  
  console.log(this);
  console.log(`window is this?? ${window===this}`);
  console.log(this.name);
  console.log('===================');
  obj.sayName();
 }
func();

위와같이 작성한 소스 코드에서 로그에서는 어떻게 내용들을 불러올까요?
이럴때는 함수를 어디에서 호출을 했느냐? 를 바탕으로 이해를 하시면 빠를꺼 같습니다.

  1. func함수는 window에서 호출을 했습니다. 그러니까 첫번째 콘솔에서 this는 window객체를 가리키고, 두번째 로그의 결과는 true로 나올것이고, 마지막으로, 이름은 func 함수 위에 선언해둔 "nodejs"가 나오게 되는겁니다.

2.그다음에는 obj.sayName함수를 호출합니다. 위에서 말했다시피, 함수를 누가 호출을 했나? 를 바탕으로 접근하면 obj라는 객체에서 함수를 호출했다는것을 확인할수 있습니다. 그래서 sayName 함수 안의 this는 obj객체를 가리키고, 아래의 로그인 window is this??는 false를 , this.name은 jasvascript를 출력합니다.

3.call,apply,bind의 명시적 binding

call,apply,bind은 명시적으로 this를 넘겨주는 함수 메소드 입니다. 이때 값을 어떻게 넣어주냐에 따라 this의 값이 달라집니다.

var name='iron man';
function a(){
  console.log(this.name);
}
a(); //iron man(아무것도 넘기지않았기 떄문에 window객체가 자동적으로 넘어감);
a.call({'name':'captain'}); //window 대신 {'name':'captain'}객체가 넘어감., captain
a.apply({'name':'black widow'}); //black widow
a.bind({'name':'thor'}).call(); // thor

4.객체 생성자

function Hero(name,skill){
	this.name = name;
    this.skill = skill;
}
Hero.prototype.useSkill = function(){
	console.log(`${this.name} use skill ${this.skill}`);
}
Hero('iron man','mark1');
console.log(window.name,window.skill);//iron man mark 1
console.log(this.name,this.skill); // iron man, mark1

let captain=new Hero('captain america','shield');
console.log(captain.useSkill()); //captain america use skill shield

위에 Hero라는 생성자 함수를 선언합니다. 그런데 아래와 같이 Hero를 선언 후에, 로그로 name과 skill값을 찍어내면, 일반 함수에서는 this를 window객체로 간주하기 떄문에 window.name, window.skill과 똑같이 나옵니다.

이를 막기 위해서 new 생성자 키워드를 이용하여, this가 가리키는 대상을 인스턴스 생성자 자체가 됩니다.

5.Arrow Function

function Obj(){
    this.age=0; //this는 Obj의 인스턴스.
    setInterval(function(){
        this.age++;
        console.log(this.age);  // NaN??
    },1000);
}
let obj=new Obj();

Obj라는 클래스(객체) 정의한 후에, obj이름을 가진 인스턴스를 생성하였습니다. obj 인스턴스는 1초마다, age를 +1씩 해주는 작업을 수행합니다. 과연 로그는 어떻게 나올까요? 결과는 NaN이 나옵니다. 왜냐하면 setInterval에서 실행 된 코드는 호출 된 함수가 아닌 별도의 실행 컨텍스트에서 실행됩니다. 즉, 생성자 객체에서 실행된것이 아니기 때문에, 이때 this는 window객체와 똑같다는 결론이 나옵니다.

function Obj(){
    this.age=0; //this는 Obj의 인스턴스.
    let that = this;
    setInterval(function(){
        that.age++;
        console.log(that.age);
    },1000);
}
let obj=new Obj();

위의 소스코드는 setInterval안에서 Object 객체에 접근을 하기위해서 블록변수 that을선언하여, Obj객체 생성자 값을 할당하여 접근하고있는것을 알 수 있습니다.

화살표 함수가 등장하기 전에는 변수하나를 선언해서, 생성자 함수 this에 할당한후, setInterval에서 할당한 that에 age를 증분을 시켜주고 있습니다. 하지만, 화살표 함수로 아래와 같이 해결할 수가 있습니다.

function Obj(){
    this.age=0; //this는 Obj의 인스턴스.
    setInterval(()=>{
        this.age++;
        console.log(this.age);
    },1000);
}
let obj=new Obj();

화살표 함수는 자기자신의 고유한 this값을 가지고 있지 않고, 둘러싸는 렉시컬 범위(lexical scope)의 this가 사용됩니다. 즉, 화살표함수 바깥 범위의 this값을 자연스럽게 가지고 들어옵니다.

5.참고자료

0개의 댓글