Multi Developer SuHo

자바스크립트 this 키워드, apply, call, bind 함수 본문

JavaScript

자바스크립트 this 키워드, apply, call, bind 함수

Dreaming Developer Student 2024. 1. 9. 17:57
SMALL

 글을 쓰기 앞서 모든  내용과 소스들은 다음과 같은 강의 플랫폼에서 응용하여  작성하였습니다.
출처: https://inf.run/xNcEg

 

[지금 무료] [코드팩토리] [입문] 9시간만에 끝내는 코드팩토리의 Javascript 무료 풀코스 강의 - 인

이 강의 하나만으로 인기 Javascript 프레임워크들과 Typescript를 배울 수 있는 기본을 다질 수 있습니다., 자바스크립트 문법 마스터,9시간 만에 무료로 할 수 있어요! ✨ 자바스크립트 문법,한 강의

www.inflearn.com

 

우선 자바스크립트에서 this 키워드란? ->  현재 실행 컨텍스트(context)를 가리키는 키워드, 다른 말로, this는 현재 작업 중인 객체를 참조하는 의미


자세한 설명은 주석에 구문 하나하나 있습니다. 

 

/**
 * this - 자바스크립트에서 this는 현재 실행 컨텍스트(context)를 가리키는 키워드,  다른 말로, this는 현재 작업 중인 객체를 참조하는 의미
 *
 * JS는 Lexical Scope를 사용하기 때문에 함수의 상위 스코프가 
 * 정의 시점에 평가된다. 
 * 
 * *******하지만 this 키워드는 바인딩이 객체가 생성되는 시점에 결졍된다.
 */
const myFunction = function(){
    return this;
}
console.log('-----------------------------------');
console.log(myFunction()); // global Object랑 맵핑이 된거를 볼 수 있다.
console.log('-----------------------------------'); 
console.log(myFunction() === global); // 실제 this는 global이랑 맵핑이 되는 것을 알 수 있다.
console.log('-----------------------------------');
const winter = {
    name: '윈터',
    year: 2001,
    sayHi: function(){
        return `안녕하세요 저는 ${this.name}입니다.`; // 여기서 this.name은 현재 객체를 의미합니다.
    },
}

console.log(winter.sayHi()); // this가 현재 (winter)윈터 객체의 매핑이 되는 것을 볼 수 있다.
console.log('-----------------------------------');
function People(name, year){
    this.name = name;
    this.year = year;

    this.sayHi = function(){ // 가장 상위 레벨
        return `안녕하세요 저는 ${this.name}입니다.`; // this.name도 실제 객체 맵핑이 된다.
    }
}
 
//만약에 객체를 이 함수로 생성한다고 한다면
const winter2 = new People('윈터', 2001); // winter2는 프로토가 people.prototype이기 때문에 people.prototype에다가 dance() 함수를 추가하면 dance를 실행할 수 있다. 
console.log(winter2.sayHi()); // this가 현재 이 winter2 객체에 맵핑되는 것을 볼 수 있다.
// 프로토타입(prototype)에다가 함수를 정의를 해도 this 키워드는 실행하는 대상의 객체로 맵핑이 된다.
People.prototype.dance = function(){ // People의 프로토타입에다 dance라는 함수를 정의
    function dance2(){
        return `${this.name}가 춤을 춥니다.`;
    }
   
    return dance2();
}
console.log('-----------------------------------');
console.log(winter2.dance());
// 객체의 메서드로 가장 상위 레벨에다가 함수를 선언을 하면은 this가 자동으로 실행하는 대상 객체로 맵핑이 된다.
// undefined 값이 나오는 이유 -> 만약 그 외의 위치에다가 함수를 선언을 하게 되면 함수의 this는 무조건 글로벌 오브젝트에 맵핑이 된다. 
console.log('-----------------------------------');

/**
 * this 키워드가 무엇을 가르키는  세가지만 기억하면 된다.
 * 
 * 1) 일반 함수 호출할땐 this가 최상위 객체 (global 또는 window)를 가리킨다.
 * 2) 메서드로 호출할땐 호출된 객체를 가리킨다.
 * 3) new 키워드를 사용해서 객체를 생성했을땐 객체를 가리킨다.
 *  2번과 3번의 경우가 아닌 경우에는 모두 this가 글로벌 또는 윈도우를 가리킨다고 생각하면 된다.
 */
 
/** 
 * 원하는 this 값으로 this를 맵핑하는 방법 세가지
 * 1) apply()
 * 2) call()
 * 3) bind()
 */
function returnName(){ //returnName() 함수 선언
    return this.name; // this.name을 반환하는데 this는 글로벌에 맵핑이 된다.
}

console.log(returnName()); // 글로벌로 맵핑이 되기 때문에 글로벌.name은 존재하지 않음 -> undefined가 나옴
console.log('-----------------------------------');
const winter3 = {
    name : '윈터',
}
// returnName() this 키워드가 winter3에 맵핑되게 하고 싶을 때

console.log(returnName.call(winter3)); // returnName()을 winter3에 바인딩해서 call하는 의미
// 그래서 this 키워드가 winter3에 바인딩 됐기 때문에 winter3의 name의 value인 "윈터"가 출력된다.

console.log('-----------------------------------');
console.log(returnName.apply(winter3)); // call() 함수와 같은 값을 가져오는 것처럼 보이는데 약간 다르다
console.log('-----------------------------------');
/**
 * 1) call -> 콤마를 기반으로 argument(아규먼트)를 순서대로 넘겨주고
 * 2) apply -> parametor(매개변수)를 리스트로 입력해야한다.
 */
function  testply(x, y, z){
    return `${this.name} / 결과값 : ${x * y * z}`;
}

console.log(testply.call(winter3, 5,10,20)); // x, y, z 라는 파라미터(매개변수)를 콤마 기준으로 배분하면 된다.
console.log('-----------------------------------');
console.log(testply.apply(winter3, [5,10,20])); // array로 하나만 받는다.
console.log('-----------------------------------');
/**
 * bind()
 * this를 바인딩만 해놓고서 나중에 실행할 수 있다. 
 */
const finishFunc = testply.bind(winter3, 5, 10, 15); // winter3에다가 바인딩을 한다는 의미
console.log(finishFunc); 
console.log('-----------------------------------');
console.log(finishFunc());

console.log('-----------------------------------');
// call, apply, bind 모두 원하는 함수에다가 원하는 객체를 바인딩할 수 있는 방법 -> this 키워드를 지정해줄 수 있다.(어떤 객체가 this의 해당이 될지)
// call 이랑 apply 함수는 실행을 하는 순간에 바로 함수가 실행이 된다.
// call에서는 콤마 기준으로 parametor(매개변수)를 배분하면 된다.
// apply는 Array로 순서대로  parametor(매개변수)를 입력해주면 된다.
// bind 같은 경우에는 바인드(bind)를 한 다음에 바로 함수가 실행되지 않고, 바인드(bind)가 된 함수를 반환을 또 해준다.
// 나중에 바인드만 해놓고 나중에 실행할 수 있는 기능이 bind() 라는 함수다.

 

myFunction 이라는 함수를 정의하고 this를 반환하는데 여기서 출력된 결과를 보시면  Object [global] 이라는 객체가 보이시나요?  -> global Object 랑 맵핑(다른구조나, 다른형식으로 변환이나 연결되는 과정)이 되는 것을 보실 수 있습니다. 

const myFunction = function(){
    return this;
}
console.log('-----------------------------------');
console.log(myFunction()); // global Object랑 맵핑이 된거를 볼 수 있다.

 


다음은 비교하는 구문입니다. 

console.log(myFunction() === global);  // myFunction이란 함수를 호출하고 그 결과값이 전역 객체(global)와 동일한지 비교 -> 실제 this는 global이랑 맵핑이 되는 것을 알 수 있다.

 

출력되는 값은 true입니다. 

이 부분은 같은 값이 나와서 하나로 묶어서 보겠습니다.

두개의 구문에서 다른점을 발견하셨나요?  ->   sayHi() 함수에 this 키워드 사용과 각 프로퍼티에 대한 this 키워드 사용 입니다. 

const winter = {
    name: '윈터',
    year: 2001,
    sayHi: function(){
        return `안녕하세요 저는 ${this.name}입니다.`; // 여기서 this.name은 현재 객체를 의미합니다.
    },
}

console.log(winter.sayHi()); // this가 현재 (winter)윈터 객체의 매핑이 되는 것을 볼 수 있다.
console.log('-----------------------------------');
function People(name, year){
    this.name = name;
    this.year = year;

    this.sayHi = function(){ // 가장 상위 레벨
        return `안녕하세요 저는 ${this.name}입니다.`; // this.name도 실제 객체 맵핑이 된다.
    }
}
 
//만약에 객체를 이 함수로 생성한다고 한다면
const winter2 = new People('윈터', 2001); // winter2는 프로토가 people.prototype이기 때문에 people.prototype에다가 dance() 함수를 추가하면 dance를 실행할 수 있다. 
console.log(winter2.sayHi()); // this가 현재 이 winter2 객체에 맵핑되는 것을 볼 수 있다.

 

 


여기서 부터는 어려운 내용보다 주석으로 설명한 부분을 참고하시면 되겠습니다!!

//만약에 객체를 이 함수로 생성한다고 한다면
const winter2 = new People('윈터', 2001); // winter2는 프로토가 people.prototype이기 때문에 people.prototype에다가 dance() 함수를 추가하면 dance를 실행할 수 있다. 
console.log(winter2.sayHi()); // this가 현재 이 winter2 객체에 맵핑되는 것을 볼 수 있다.
// 프로토타입(prototype)에다가 함수를 정의를 해도 this 키워드는 실행하는 대상의 객체로 맵핑이 된다.
People.prototype.dance = function(){ // People의 프로토타입에다 dance라는 함수를 정의
    function dance2(){
        return `${this.name}가 춤을 춥니다.`;
    }
   
    return dance2();
}
console.log('-----------------------------------');
console.log(winter2.dance());
// 객체의 메서드로 가장 상위 레벨에다가 함수를 선언을 하면은 this가 자동으로 실행하는 대상 객체로 맵핑이 된다.
// undefined 값이 나오는 이유 -> 만약 그 외의 위치에다가 함수를 선언을 하게 되면 함수의 this는 무조건 글로벌 오브젝트에 맵핑이 된다. 
console.log('-----------------------------------');

/**
 * this 키워드가 무엇을 가르키는  세가지만 기억하면 된다.
 * 
 * 1) 일반 함수 호출할땐 this가 최상위 객체 (global 또는 window)를 가리킨다.
 * 2) 메서드로 호출할땐 호출된 객체를 가리킨다.
 * 3) new 키워드를 사용해서 객체를 생성했을땐 객체를 가리킨다.
 *  2번과 3번의 경우가 아닌 경우에는 모두 this가 글로벌 또는 윈도우를 가리킨다고 생각하면 된다.
 */
 
/** 
 * 원하는 this 값으로 this를 맵핑하는 방법 세가지
 * 1) apply()
 * 2) call()
 * 3) bind()
 */
function returnName(){ //returnName() 함수 선언
    return this.name; // this.name을 반환하는데 this는 글로벌에 맵핑이 된다.
}

console.log(returnName()); // 글로벌로 맵핑이 되기 때문에 글로벌.name은 존재하지 않음 -> undefined가 나옴
console.log('-----------------------------------');
const winter3 = {
    name : '윈터',
}
// returnName() this 키워드가 winter3에 맵핑되게 하고 싶을 때

console.log(returnName.call(winter3)); // returnName()을 winter3에 바인딩해서 call하는 의미
// 그래서 this 키워드가 winter3에 바인딩 됐기 때문에 winter3의 name의 value인 "윈터"가 출력된다.

console.log('-----------------------------------');
console.log(returnName.apply(winter3)); // call() 함수와 같은 값을 가져오는 것처럼 보이는데 약간 다르다
console.log('-----------------------------------');
/**
 * 1) call -> 콤마를 기반으로 argument(아규먼트)를 순서대로 넘겨주고
 * 2) apply -> parametor(매개변수)를 리스트로 입력해야한다.
 */
function  testply(x, y, z){
    return `${this.name} / 결과값 : ${x * y * z}`;
}

console.log(testply.call(winter3, 5,10,20)); // x, y, z 라는 파라미터(매개변수)를 콤마 기준으로 배분하면 된다.
console.log('-----------------------------------');
console.log(testply.apply(winter3, [5,10,20])); // array로 하나만 받는다.
console.log('-----------------------------------');
/**
 * bind()
 * this를 바인딩만 해놓고서 나중에 실행할 수 있다. 
 */
const finishFunc = testply.bind(winter3, 5, 10, 15); // winter3에다가 바인딩을 한다는 의미
console.log(finishFunc); 
console.log('-----------------------------------');
console.log(finishFunc());

console.log('-----------------------------------');
// call, apply, bind 모두 원하는 함수에다가 원하는 객체를 바인딩할 수 있는 방법 -> this 키워드를 지정해줄 수 있다.(어떤 객체가 this의 해당이 될지)
// call 이랑 apply 함수는 실행을 하는 순간에 바로 함수가 실행이 된다.
// call에서는 콤마 기준으로 parametor(매개변수)를 배분하면 된다.
// apply는 Array로 순서대로  parametor(매개변수)를 입력해주면 된다.
// bind 같은 경우에는 바인드(bind)를 한 다음에 바로 함수가 실행되지 않고, 바인드(bind)가 된 함수를 반환을 또 해준다.
// 나중에 바인드만 해놓고 나중에 실행할 수 있는 기능이 bind() 라는 함수다.

 

 


감사합니다. 출력결과가 다른신 분들은 말씀해주시면 되겠습니다!  댓글에 간단한 인사나 하고싶은 말 있으시면 달아주세요!! 

LIST