본문 바로가기
javaScript

javaScript - context 문법

by sinabeuro 2021. 7. 27.
728x90

최근에 알게된 context 문법에 관해서 간략하게 다루보겠습니다. 

흔히 자바스크립트의 this를 많이 사용하고는 했는데, 이것이 무엇을 지칭하는지는 그때 그때 달라져서 좀 더 자세히 알아볼 필요가 있습니다. 

그래서 이번 기회에 this 개념을 알아볼까 합니다.

 

기본적으로 this가 가르키는 것은 window입니다. 

전역 변수 개념으로 this는 window인 셈이죠.

반면 매서드 내부에서 this는 매서드를 지칭하게 됩니다.

new 연산자로 인스턴스 객체 생성 시에는 this는 생성 대상 객체가 됩니다.

 

객체 내에서 문맥(context)가 달라지면 this를 어떻게 인식하는지 살펴봅시다.

const person = {
  name: "hong gil dong",
  age : 30,
  getAge() {
    return this.age;
  }
}

const age = person.getAge;
console.log(age());   // this 를 인식 못해서 에러가 난다.

함수를 변수로 받아서 실행시키면, 함수 내부에 있는 this 값이 undefined가 됩니다.

함수를 변수로 받으면서 문맥의 변화가 일어난 것이죠. 

그래서 this가 가르키는 대상을 찾지 못하게 됩니다.

 

자바스크립트에 문맥의 변화를 잡아주는 메소드가 있습니다.

바로 call()과 apply() 메소드입니다.

 

const person = {
  name: "hong gil dong",
  age : 30,
  getAge() {
    return this.age;
  }
}

const age = person.getAge;
console.log(age.call(person));	// 30
console.log(age.apply(person));	// 30

call과 apply 첫인자로 새로운 문맥에 this가 될 객체를 넣어주시면 해결됩니다.

 

...
const age = person.getAge;

let test = { age: 50 };
console.log(age.call(test));	// 50
console.log(age.apply(test));	// 50

이렇게 새롭게 객체를 만들어서 call과 apply의 첫인자로 넘겨 주시면 됩니다. 

call과 apply 메소드의 차이점은 이전에 포스트했던 글을 참고해주세요.

https://getthismoment.tistory.com/27

 

 

ES5에서는 bind 함수를 제공합니다. 

 

  • bind 함수

func.bind(thisArg[, arg1[, arg2[, ...]]])

바인딩 함수가 대상 함수(target function)의 this에 전달하는 값입니다.

바인딩 함수를 new 연산자로 생성한 경우 무시됩니다.
bind를 사용하여 setTimeout 내에 콜백 함수를 만들 때, thisArg로 전달된 원시 값은 객체로 변환됩니다.
bind할 인수(argument)가 제공되지 않으면 실행 스코프 내의 this는 새로운 함수의 thisArg로 처리됩니다.

const person = {
  name: "hong gil dong",
  age : 30,
  getAge() {
    return this.age;
  }
}

let age = person.getAge;
//console.log(age());
let test = age.bind(person);
console.log(test());	// 30
test = age.bind({name: 'hong gil dong' age: 200});
console.log(test());	// 200

 

함수에 bind 메소드를 걸어서 문맥을 this를 바꿔줄 수도 있지만, class를 활용한 방법도 있습니다.

class Person {
  name: string;
  age: number;
  constructor(name: string, age: number) {
    this.name = name;
    this.age = age;
    this.getAge = this.getAge.bind(this);
  }

  getAge() {
    return this.age;
  }
}

const p1 = new Person('hong gil dong', 30);
console.log(p1.getAge());
const myAge = p1.getAge;
console.log(myAge());	// 30

this.getAge = this.getAge.bind(this) 구문 처럼.

생성자에 bind를 걸어서 메소드의 this를 고정시켜줄 수 있습니다.

이렇게 하면 console.log(myAge()) 코드가 에러가 나지않습니다.

myAge 변수로 함수를 받아도 myAge()가 정상적으로 호출됩니다. 

 

 

bind 함수 외에도 context를 고정시키는 방법이 있습니다.

ES5에 추가된 에로우함수를 사용하여 lexical context 방식으로 this를 고정시키면 됩니다.

class Person {
  name: string;
  age: number;
  constructor(name: string, age: number) {
    this.name = name;
    this.age = age;
    this.getAge = this.getAge.bind(this);
  }

  getAge() {
    return this.age;
  }
  
  // 렉시컬 컨텍스트 처음 만들 때 this를 고정시킴. 에로우 함수로 컨텍스트를 고정 시킴
  // this가 고정되어 다른 객체로 바꿀 수 없다.
  getName = () => this.name; 
}

const p1 = new Person('hong gil dong', 30);
console.log(p1.getAge());
const myAge = p1.getAge;
console.log(myAge());

const myName = p1.getName;
console.log(myName())

 

getName 메소드를 에로우함수로 컨텍스트를 고정시켰습니다. 

인스턴스 객체 생성 시 this는 생성 시점에 해당 인스턴스 객체로 고정됩니다.

 

참고: 화살표 함수를 call(), bind(), apply()를 사용해 호출할 때 this의 값을 정해주더라도 무시합니다. 

사용할 매개변수를 정해주는 건 문제 없지만, 첫 번째 매개변수(thisArg)는 null을 지정해야 합니다.

 

에로우함수를 사용한 lexical 컨텍스트 방식은 bind 메소드보다 더 편리한 방법이긴합니다. 

하지만 생선된 인스턴스 객체에 this가 고정된다는 점에서 차이점이 있습니다.

bind 메소드는 함수의 this를 유동적으로 변경할 수 있습니다.

 

https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Operators/this

 

this - JavaScript | MDN

JavaScript에서 함수의 this 키워드는 다른 언어와 조금 다르게 동작합니다. 또한 엄격 모드와 비엄격 모드에서도 일부 차이가 있습니다.

developer.mozilla.org

 

728x90

댓글