JavaScript(this, Arrow function)

박정호·2022년 3월 29일
0

JS

목록 보기
1/24
post-thumbnail

this 키워드

1. 그냥 사용하거나 함수 안에서 사용하면 window를 뜻.

this라는 키워드 또는 함수호출을 통해 콘솔창에 출력하면 다음과 같이 window에 대한 정보가 출력된다.

 console.log(this)
또는
function 함수(){
  console.log(this)
}
함수();

window

window는 모든 전역변수, 함수, DO을 보관하고 관리하는 전역객체이다.
가장 큰 오브젝트라고 생각하면 된다. 만약 이미 만들어진 객체 속에 존재하는 this라면 this가 존재하고 있는 객체를 가리키고, 그 객체에 대한 정보가 출력된다. (2번을 참고)
하지만, 위의 코드들과 같은 경우는 window라는 큰 객체 안에 존재하는 것이라고 생각하면 된다. 따라서, 그렇다면 당연히 this는 자신이 존재하는 window객체에 대한 정보를 출력하는 것이다.

밑의 두 코드는 같은 의미
console.log(this)
-------------------
window:{
console.log(this)
}

잠깐) strict mode일 경우 함수 안에서 사용하면 this는 undefined를 출력한다.
IE 10버전 이상에선 'use strict'라는 키워드를 페이지 최상단에 추가하면 strict mode로 자바스크립트를 작성가능하다. strict mode에선 var 키워드 없이 변수를 선언하거나,
변수를 arguments라는 이상한 키워드로 선언하는 등의 실수들을 방지한다.
따라서, strict mode에선 this 키워드를 일반함수 안에서 불렀을 때 undefined라는 값으로 강제로 지정해준다. 알고만 넘어가자.

<script>
  'use strict';
  function 함수(){
    console.log(this) //undefined
  }
  함수();
</script>

2. object자료형 내의 함수 속 this 값은 해당 object를 뜻.

객체 안에 선언된 함수인 메서드 속에 this값을 사용하면 메소드를 가지고 있는 오브젝트를 뜻한다.

var 오브젝트 = {
  data : 'Kim',
  함수 : function(){ console.log(this) } 
}
오브젝트1.함수();

즉, 함수라는 메서드가 존재하고 그 안에 this는 해당 오브젝트의 정보를 출력하는 것이다. 따라서, data(키)값과 함수(키(메서드))값을 출력한다.

만약 다음과 같이 오브젝트라는 객체 속 data라는 객체 속에 존재하는 this는 무엇을 가리킬까?

var 오브젝트 = {
  data : {
    함수 : function(){ console.log(this) }
  }
}
오브젝트.data.함수();

자신을 가지고 있는 메서드를 가지는 오브젝트, 즉 data객체에 대한 정보를 출력한다.

3. constructor 안에서 사용하면 constructor로 새로생성 되는 오브젝트를 뜻.

자바스크립트에서 오브젝트를 여러개 만들고 싶으면 오브젝트를 갯수만큼 복사하는 것이 아니라 constructor라는 것을 만들어서 사용한다. 즉, constructor는 오브젝트를 복사해서 생성해주는 기계와 같은 개념이다.

다음과 같은 코드의 경우, this는 기계로부터 새로 생성될 오브젝트를 뜻한다.
this.이름 = 'kim'은 새로생성된 오브젝트의 이름(key)값에 'Kim'이라는 value값을 저장해달라는 뜻이다.

function 기계(){
  this.이름 = 'Kim';
}

만약 새로운 오브젝트를 꺼내고 싶으면 new키워드를 사용하자. 그렇다면 {이름:'Kim'}을 사용할 수 있다.

function 기계(){
  this.이름 = 'Kim'
}
var 오브젝트 = new 기계();

4. eventlistener 안에서 사용하면 this는 e.currentTarget을 뜻.

다음과 같은 코드는 아이디값이 버튼인 요소에 대해 click 이벤트가 발생하면 함수 내부의 코드를 실행한다라는 뜻이다.

<button id="버튼">버튼</button>
document.getElementById('버튼').addEventListener('click', function(){
  console.log(this)
});

여기서 this 값은 e.currentTarget이라는 뜻과 같은 의미이다.
e.currentTarget은 현재 이벤트가 동작하는 곳을 뜻한다.
따라서, button태그를 가리킨다.

document.getElementById('버튼').addEventListener('click', function(e){
  console.log(e.currentTarget); //this와 같은 뜻
});

즉, e.currentTarget, this, document.getElementById('버튼') 이 세개의 경우 같은 것을 의미한다.(button 태그)

case1

만약 다음과 같은 코드의 경우 this는 무엇을 가리킬까?

document.getElementById('버튼').addEventListener('click', function(e){
  var 어레이 = [1,2,3];
  어레이.forEach(function(){
    console.log(this)
  });
});

위의 코드를 해석하면, 이벤트리스너 안에서 forEach() 반복문을 사용하고 있다. forEach()반복문의 경우 콜백함수를 집어넣어서 사용하게 되어있고, 콜백함수는 일반 함수 안에 파라미터 역할로 들어가는 함수를 뜻한다. 따라서 함수 안에 함수가 존재하는 모습을 볼 수 있다.

결론은 window가 출력된다. 위에서 본 경우 중 1번의 경우와 같다. 콜백함수는 일반함수랑 똑같기 때문에 가장 큰 오브젝트인 window에 대한 정보를 가리킨다.
this에 대한 경우들을 뜯어보면, constructor 속 새로은 오브젝트는 아니고, 이벤트리스너의 직접적인 내부에 존재하는 것도 아니다. 따라서, 1번과 같은 상황이라고 생각하면 되겠다.

case2

만약 오브젝트 안에 콜백함수가 사용하면?

var 오브젝트 = {
  이름들 : ['김', '이', '박'];
  함수 : function(){
  		console.log(this) //1번
      오브젝트.이름들.forEach(function(){
        console.log(this)// 2번
      });
  }
}

앞서 살펴본 case1과 같이 forEach()에는 function()이라는 일반함수가 존재한다. 따라서 일반함수 속 this(2번)는 window를 가리킨다.
반면 1번의 경우는 자신의 메서드가 존재하는 오브젝트라는 객체를 가리킨다.

이러한 경우 this값은 function을 만날때마다 값이 변경되어 사용이 힘들다. 이를 해결하기 위해 ES6 신문법으로 나온 것이 arrow function이다.

function(){} 대신 ()=>{}를 사용
var 오브젝트 = {
  이름들 : ['김', '이', '박'];
  함수 : function(){
  		console.log(this) //1번
      오브젝트.이름들.forEach(() => {
        console.log(this) //2번
      });
  }
}

arrow function의 특징은 내부의 this값을 변화시키지 않고, 외부 this값 그대로를 재사용이 가능하다는 것이다.
따라서, 2번의 this는 1번의 this와 같이 오브젝트라는 객체를 가리킨다.

자바스크립트에서의 함수 식

  • 여러가지 기능을 하는 코드를 한 단어로 묶고 싶을 때(그리고 재사용할 때)
  • 입출력기능을 만들 때
(1)
function 함수(){}
(2)
var 함수 = function(){}
(3)
var 함수 = () => {}

arrow function

  • 입출력 기능을 직관적으로 표현해준다.
var 두배만들기 = (x) => { return x * 2 }
  • 소괄호 생략이 가능
var 두배만들기 = x => { return x * 2 }
  • 중괄호 생략이 가능
var 두배만들기 = x => x * 2 ;

앞서 보았던 함수 안에 존재하는 콜백함수는 일반함수를 나타내어 window객체를 가리켰고, window객체가 아닌 자신의 함수를 가지고 있는 객체를 가리킨다.

이를 통해 알수 있는 arrow function의 기능

  • 외부에 있던 this를 그대로 내부로 가져와서 사용하는 함수

주의) 그대로 가지고 오는 기능이 장점이자 단점이 될 수도 있다.

아래의 코드는 이제 this가 오브젝트1이라는 객체를 가리킨다는 것을 알 수 있다.

var 오브젝트1 = {
  함수 : function(){ console.log(this) }
}
오브젝트1.함수()

그렇다면 일반함수를 arrowfunction으로 나타낸 아래의 코드에서 this는 어디를 가리킬까?
바로, window객체이다. 말 그대로 외부에 있는 this값을 가져오는 것이니, 오브젝트1의 외부에 있는 this는 window를 가리키기 때문이다.

var 오브젝트1 = {
  함수 : () => { console.log(this) }
}
오브젝트1.함수()

따라서, function과의 용도가 완전이 일치하는 것은 아니니, 상황에 따른 적합한 함수식을 사용해야 할 것이다.

응용

  1. 간단한 메소드 만들기

만약 '안녕 나는 손흥민'을 출력하고 싶다면?

var 사람 = {
  name: '손흥민',
}
사람.sayHi(); //안녕 나는 손흥민

마지막 줄에서 sayHi()를 호출하는 것을 보고, sayHi()라는 메서드가 필요하다는 것을 알 수 있고, 사람 객체 안에 함수를 생성한다. 그 함수를 호출했을 때 '안녕 나는'까지는 일반적으로 출력이 가능하고, '손흥민'은 name의 value값에서 가져올 수 있다. 따라서, this.name을 이용하면 된다. 여기서의 this는 자신의 함수를 포함한 '사람'이라는 객체를 가리키고 .name을 통해 '손흥민'이라는 value값을 불러올 수 있는 것이다.

var 사람 = {
  name: '손흥민',
  sayHi : function(){
    console.log('안녕 나는 ' + this.name)
  }
}
사람.sayHi(); //안녕 나는 손흥민
  1. 오브젝트 내의 데이터를 전부 더해주는 메소드 만들기

만약 다음과 같은 객체가 생성되어 있고, data 속 숫자들을 전부 합하는 '전부더하기'메소드를 생성하려 한다. 단, 자료 객체 안에 생성하는 것이 아닌 따로 생성하는 것이 조건이다.

var 자료 = { 
  data : [1,2,3,4,5] 
};
자료.전부더하기();

일반적으로는 다음 코드와 같이 숫자를 더하는 함수를 객체 안의 메서드로 저장할 수 있다.

var 자료 = { 
  data : [1,2,3,4,5],
  전부더하기 : function(){~~~}
};

하지만, 바깥에 존재시키기 위해서는 아래 코드와 같이 자료.전부더하기 = function()처럼 만들어주자. 이에 대한 뜻은 자료라는 객체에 전부더하기라는 것이 함수를 저장해주는 것이다.
그리고 forEach문을 통해 자료객체 속 data 배열을 반복출력하면 되는데, this.data를 앞에 붙여주면 된다. 여기서 this는 '자료'라는 객체를 가리킨다.

var 자료 = { 
  data : [1,2,3,4,5] 
};
자료.전부더하기 = function(){
  var 합 = 0;
  this.data.forEach(function(a){
    합 = 합 + a;
  });
  console.log(합);
}
자료.전부더하기();
  1. setTimeout 이용해보기

아래의 setTimeout함수를 사용해보자.

setTimeout(콜백함수, ms단위의 시간)

만약 다음과 같이 버튼 클릭 내용이 출력되는 코드가 있다.
이때 setTimeout을 이용하여 주어진 시간 이후에 코드가 출력하게 하고 싶다면?

<button id="버튼">버튼이에요</button>
<script>
  document.getElementById('버튼').addEventListener('click', function(){
    setTimeout(()=>{ console.log(this.innerHTML) }, 1000); 
  });
</script>

setTimout안에 콜백함수를 주어야 하는데, 이때 일반함수를 줄지, arrow함수를 줄지 고민일 수 있다. 하지만, 두 함수의 동작을 파악하면 알 수 있다. 만약 일반함수를 콜백함수로 주었다면 일반함수 속의 this는 window객체를 가리키므로 탈락. 반면 arrow함수 속의 this는 외부 this를 그대로 가져온다. 외부에서의 this는 현재 이벤트가 실행하는 곳을 가리킨다. 따라서, arrow함수를 사용하면 원하는 이벤트가 동작할 수 있다.

<button id="버튼">버튼이에요</button>
<script>
  document.getElementById('버튼').addEventListener('click', function(){
    setTimeout(()=>{ console.log(this.innerHTML) }, 1000); 
  });
</script>

만약, 일반함수를 사용하고 싶다면?
외부에 존재하는 this 값을 변수에 저장하여, 그 변수값을 그대로 사용하는 것이다.

<button id="버튼">버튼이에요</button>
<script>
  document.getElementById('버튼').addEventListener('click', function(){
    var 버튼 = this;
    setTimeout(function(){ console.log(버튼.innerHTML) }, 1000); 
  });
</script>
profile
기록하여 기억하고, 계획하여 실천하자. will be a FE developer (HOME버튼을 클릭하여 Notion으로 놀러오세요!)

0개의 댓글