상세 컨텐츠

본문 제목

시베리안 허숙희의 자바스크립트 비기닝 19 (this 키워드)

자바스크립트

by e7e 2023. 6. 15. 16:38

본문

자스(크립트)뿐만 아니라, 다른 객체지향언어도 레벨업 하려면 this 키워드

지금 무얼 참조하고 있는지?가 누네 보이고 안 보이고는 큰 차이라 하겠당!

this를 diss 해봐야 남는 게 없다는 단정은 성급하당.  단지 개발자라면 불편함을

느꼈다면 개선의 의지를 히미할지라도 히밌게 겹겹이 쌓아 선명하게 하장.

 

먼저 아래 코드 실행해 보고 결과를 확인하장!

<!DOCTYPE html>
<meta charset="UTF-8">
<script>
// this는 누궁?
console.log("this1",this); // window

const thisCheck=function(){
    console.log("this2",this);
}

thisCheck(); // window
window.thisCheck(); // 위와 동일 이게 무신 의미?


var aaa = "ppp";
alert("aaa1: " + aaa)
alert("aaa2: " + window.aaa); // 위와 동일 이게 무신 의미?

</script>

전역(Global)상태의 thiswindow객체를 가리킨당.

(당연하다 브라우져[정확하겐 탭]를 가리키는  window는 최상위객체당)

전역함수 속에서도 this는 window를 가리킨당.(당연하당 전역함수는 window객체의 메소드당)

위 코드에서 이미 느꼈겠지만, 전역변수는 window객체의 속성이 된당.(let은 저장영역이 다르당)

함수지향 프로그램 같았지만, 그 아래 객체지향이 숨어있었당(함수는 메소드, 변수는 속성이었당)

 

코드가 쪼메 맛나게 변경을 가해보장

<!DOCTYPE html>
<meta charset="UTF-8">
<script>
const thisCheck=function(){
    console.log("this는",this);
}

thisCheck(); // this => window

const myRoze = {
    name:"로제짱",
    myCheck:thisCheck  // myCheck가 thisCheck를 참조(가리킴)
}

myRoze.myCheck();  // this => myRoze
</script>

찰나의 방심은 헷깔림을 부를 수 있당. 정신 바짝 차리고 코드를 보장!

myCheck는 thisCheck를 참조하는 myRoze객체의 메소드당.

메소드안에서 this는 메소드가 속한 객체를 가리키니 당연히 myRoze당!

 

허억!  이해는 되지만 this가 가리키는 객체가 내가 의도하지 않은  객체로 상황에 따라 바뀔 수 있다면,

완존시롱 시롱이당!  반대로 내가 의도하는 대로 this가 가리키는 객체를 바꿀 수 있다면 어떨깡?

오호 그건 내 맘대로 한다는 절대권력의 의미이니 절대 반대할 이유가 없당!

그래서 나왔당, this 제어 메소드 call, apply, bind  듣기만 해도 중요함에 소름 돋는다.

 

먼저 call과 apply를 같이 보장. (같이 보는 건 기능은 같고, 매개변수 넘기는 법만 다르당)

아래 코드를 유심히  살펴보길 바란당.(누니 코드를 따라갈 수 있어야 이해 된거당)

<!DOCTYPE html>
<meta charset="UTF-8">
<script>
const thisCheck=function(...pArgs){
    console.log("=============== 함수 로그 시작 ==================");
    console.log("this =>",this);
    console.log(`${this.gasu} ${this.song}`);
    console.log(`${pArgs[0]} ${pArgs[1]} ==> ${[...pArgs]}`);
    console.log("                                                 ");
}

var gasu = "로제";  // window.gasu와 동일
var song = "Gone"   // window.song과 동일
thisCheck("야옹","멍멍"); // this => window


const myJenni = {
    gasu:"제니?",
    song:"Solo"
}

thisCheck.call(myJenni,"태권","브이");
thisCheck.apply(myJenni,["태권","브이"]); // 결과 위와 동일
</script>

누니 빠른 사람은 캡쳐 했을거시당. call과 apply 괄호안의 첫번째 꺼이 this가 가리키는 값이 된다는 걸

두번째 꺼이 부터는 함수의 매개변수에 넘겨진당. 여기서 call은 호출할 때 매개변수를 나열하고,

apply는 무조건 필요한 매개변수 값들을 배열에 담아서, 배열을 넘겨줘야 한당! 

꼬옥 다른 객체(object)를 맹글어서 직접 한번 연습해 보는 시간을 가져보장.(실타면 어떨수 없당)

 

이제 쪼메 더 누네 히미 필요한 bind당. (사용법은 call과 똑같지만 동작이 다르당)

아래 코드를 실행해 보고, 요기가 포인또라고 주석달린 부분에 집중해 보장!

CustomEvent 생성/등록/발생 사용한 건 미안하당.(요따우 것도 있네 하고 일단 바더들이장!)

<!DOCTYPE html>
<meta charset="UTF-8">
<body>
</body>
<script>
// 그냥 body에 모양 쪼메 넣깅
const myDiv = document.createElement("div");
myDiv.setAttribute("id","msg"); //myDiv.id="msg" 와 같음
myDiv.innerHTML=`<h1>난 최고의 프로그래머당</h1>`;
document.body.appendChild(myDiv);

// 이벤토 맹글깅
const myEvent = new CustomEvent("greeting");
const myMsg = document.querySelector("#msg");

//이벤트 발생시 실행할 함수
const message = function(pTime){
    //console.log(this);
    alert(`좋은 ${pTime.time} 이예용`);
    if(pTime.time == "아침") {
        pTime.time ="점심";
        return;
    }
    if(pTime.time == "점심") {
        pTime.time ="저녁";
        return;
    }
    if(pTime.time == "저녁") {
        pTime.time ="아침";
        return;
    }
}

//매개변수요 객체
var myTime = {
    time:"아침"
}

//요기가 포인또 임
myMsg.addEventListener("greeting",message(myTime));
alert("아직 이벤트 발생 전");
myMsg.dispatchEvent(myEvent);
alert("막 이벤트 발생 후");
</script>

이벤트가 발생하지 않았는데, message함수가 실행된당!, 당연하당

자스에선 함수명에 괄호() 를 붙이면 해당 함수가 호출이니깡!,  이것은

원치 않는 거시당 ,이벤트 발생시에만 실행시키려면, 아래처럼 수정이 필요하당.

//요기가 포인또
myMsg.addEventListener("greeting",message);

수정하게 되면,이벤트 발생시에만 실행은 되지만, 매개변수를 넘길 수 없당.ㅠㅠ

이때 bind를 이용, 해당 부분만 아래처럼 수정후 결과를 체크해 보장! (사용법이 call과 똑같음에 주목)

//요기가 포인또
myMsg.addEventListener("greeting",message.bind(this,myTime));
alert("아직 이벤트 발생 전");
myMsg.dispatchEvent(myEvent);
alert("막 이벤트 발생 후");


//괘니 이벤트 추가 발생! 결과 확인
myMsg.dispatchEvent(myEvent);
myMsg.dispatchEvent(myEvent);
myMsg.dispatchEvent(myEvent);

bind를 call로 바꾸어 보면, 이벤트 없이 바로 실행되는 차이의 꽤 다름을 느낄 것이당.

bind는 내부적으로 해당 매개변수값을 가진 함수를 새로 맹글어 함수포인터를 리턴해준당!

말이 어려울 수 있당. 함수 포인터는 함수를 가리키는 것이어야 하닝 보통은  함수이름이당.

함수이름에 ()를 붙이면 실행되니, 이벤트 등록에는 ()를 빼고 함수이름만 쓴당.(오켕?)

 

bind 사용 예를 구찌 억지롱  한개 더 보장!

document.write가 너무 길어서 짧게 print란 이름으로  짧게 쓰고 싶다고 그냥 하장!

그러면 아래처럼 코드를 짜는 사람이 있을 거시당.(괜찮당 좋은 생각이고 잘된당!)

<!DOCTYPE html>
<meta charset="UTF-8">
<script>
    const print = function(pMsg){
        document.write(`${pMsg}`);
    }

    for(let i=6; i>=1; i--){
        print(`<h${i}>난 최고의 프로그래머</h${i}>`);
    }
</script>

 

참조(Reference)를 잘 이해하고 있는 사람이라면 아마도 위 코드를 아래처럼 짤 것이당

<!DOCTYPE html>
<meta charset="UTF-8">
<script>
    const print = document.write;

    for(let i=6; i>=1; i--){
        print(`<h${i}>난 최고의 프로그래머</h${i}>`);
    }
</script>

당연히 될 거라 믿고 실행하면,  멍미! 아래와 같은 에러가 난당.(불법 호출이라닝..ㅠㅠ)

Uncaught TypeError: Illegal invocation

원인은 document.write 메소드 안에 this가 사용되고 있는데, document.write라고 썼을 땐

this가 가리키는 값이 document인데, print라고 쓰면 this가 window를 가리키게 된당!(오켕?)

아래 처럼 bind를 이용하여,this가 가리키는 값을 document로 바꾸어주면 된당!

<!DOCTYPE html>
<meta charset="UTF-8">
<script>
    const print = document.write.bind(document);

    for(let i=6; i>=1; i--){
        print(`<h${i}>난 최고의 프로그래머</h${i}>`);
    }
</script>

call을 쓰면 왜 안되나용? 답변 가능하지용!

한가지 더 함수이름에 점을 찍고 call, apply, bind를 사용했습니다. 그렇탐 function은 객체?

 

나이 40을 불혹이라고 했던가요,  혹 하는 게  없어진다는.... 다 거짓말!!

살아보니 젊은 시절 혹 했던 것에는 혹 하지 않는데,  다른 것에 혹하게 됩니다.

사람!  같이 웃으며 인생사 사람 사는 이야기 나누어 줄 사람 (일 이야기 말고용~~)

 

때론 우리 일 이야기 그런 거 말고,  사람 사는 이야기 속에 Stay 하게용

 

https://www.youtube.com/watch?v=XO92ZWK3j-s 

 

관련글 더보기