[MJS] Javascript - this (2)
Javascript 개념
모던 자바스크립트 딥 다이브 정리
this
this
this란?
자신이 속한 객체 또는 자신이 생성할 인스턴스를 가리키는 자기 참조 변수(self-referencing variable)이다.
이를 이용해 자신이 속한 객체/인스턴스의 메서드, 프로퍼티를 참조할 수 있다.
객체 리터럴 방식으로 객체를 생성하면 이미 객체 이름이 메모리에 있는 것 이기 때문에, 메서드 안에서 객체를 재귀적으로 참조할 수 있다.
하지만, 이것 또한 바람직하지 않다.
또한, 생성자 함수 방식으로 인스턴스를 생성하면 생성자 함수를 정의할 때에는 인스턴스가 아직 없기 때문에 인스턴스를 가리킬 수 있는 식별자가 없다.
이를 위해 자바스크립트에서는 this를 제공한다.
- this 용법
this는 사용 시 호출한 방법에 따라 결정되는 것
자바스크립트에서 this는 호출하는 방법에 따라 결정되며 strict mode 에 따라 달라지기도 한다.
- 함수 호출 방식에 따른 this 바인딩
this 바인딩은 함수 호출 방식에 따라, strict mode에 따라 동적으로 결정된다.
-
일반 함수 호출
기본적으로 this에는 전역 객체(global object)가 바인딩된다.
따라서, 함수 안에 this를 사용하고 일반 함수로 호출했을 때 전역 객체가 바인딩된다.(browser → window/ nodeJS → global)
함수의 내부 함수(중첩 함수) 혹은 콜백 함수 안의 this 또한 전역 객체가 바인딩된다.
strict mode가 적용되면 일반 함수 내부에서 this는 undefined가 바인딩된다.
-
메서드 호출
메서드를 호출할 때 메서드 (./마침표) 연산자 앞에 기술한 객체가 바인딩된다.
이 때 this는 메서드를 소유한 객체가 아닌 메서드를 호출한 객체에 바인딩된다.
-
생성자 함수 호출
생성자 함수가 생성할 인스턴스가 바인딩된다.
생성자 함수는 객체(인스턴스)를 생성하는 함수이다. new와 함께 호출하면 생성자 함수로 호출이 되는데,
이 때 this는 생성하게 될 인스턴스가 바인딩된다.
-
화살표 함수(arrow function)에서 사용하는 this
화살표 함수에서 this는 자신을 감싼 정적 범위이다. 전역에 있다면 전역 객체를 가리키게 되는 것.
let globalObject = this // 전역이니까 window(브라우저에서) let foo = () => this // 전역이니까 자신을 감싼 범위 => window console.log(foo() === globalObject) // true // 객체로서 메서드 호출 var obj = { func: foo } console.log(obj.func() === globalObject) // true // call을 사용한 this 설정 시도 console.log(foo.call(obj) === globalObject) // true // bind를 사용한 this 설정 시도 foo = foo.bind(obj) console.log(foo() === globalObject) // true
위 처럼 어떤 메소드를 사용해서 this 값을 호출하더라도 무시한다.
-
클래스 (생성자)에서의 this
생성하게 될 인스턴스를 this에 바인딩한다.
-
DOM 이벤트 처리기에서의 this
함수를 이벤트 처리기로 사용하면 this는 이벤트를 발사한 요소로 설정한다.
function curF(e) { // 언제나 true console.log(this === e.currentTarget); // currentTarget 지금 이벤트를 발생시킨 요소 // currentTarget과 target이 같은 객체일 경우에만 true console.log(this === e.target); }
-
메서드에 의한 간접 호출
Call, Apply, Bind 메서드를 통해 this를 바인딩한다.
-
-
Call, Apply, Bind 메서드 this에 특정값을 지정해주는 메서드
-
Call call 메서드는 모든 함수에서 사용할 수 있으며 this를 특정값을 지정할 수 있다.
const mike = { name: "mike", }; const tom = { name: "tom", }; function showThisName() { console.log(this.name); // 해당 객체의 name 값을 console로 띄워라. } showThisName(); // 이렇게 아무 매개변수 없이 호출하면 // 저기서 this가 가리키는 것은 여기서 window 이므로 // window.name은 정의되어 있지 않으니 undefined 출력하지 않는다. showThisName.call(mike); // mike 나옴 // 함수를 사용하면서 call을 하고 this로 사용할 객체를 넘기면 // 해당 함수가 주어진 객체의 메서드인 것처럼 사용할 수 있다.
그냥 함수 호출한 경우와 call하여 mike를 객체로 전달한 것과의 차이로 call을 이해할 수 있다. call을 이용해서 mike를 this로 사용할 수 있도록 해주면 mike.name을 나타낼 수 있는 것이다. 위의 코드에 이어서, update라는 생성자를 만들어 call을 통해 객체를 업데이트할 수 있다.
function update(birthYear, occupation) { this.birthYear = birthYear; this.occupation = occupation; } update.call(mike, 1999, "singer"); console.log(mike); // { name: 'mike', birthYear: 1999, occupation: 'singer' } // update를 call하고 나머지 객체를 전달해주니까 // update에서는 전달받은 객체를 this로 사용하고, 그 객체의 birthYear, ocuupation을 각각의 값으로 지정한다.
this를 mike로 사용할 수 있도록 mike를 전달해주고, 나머지 객체들을 전달해주니 원래의 객체에 속성이 추가된 것을 확인할 수 있다.
-
Apply call과 거의 같지만, 매개변수를 배열로 받는다. 함수 매개변수를 배열로 사용할 때 유용하다.
const tom = { name: "tom", }; function update(birthYear, occupation) { this.birthYear = birthYear; this.occupation = occupation; } update.apply(tom, [2002, "teacher"]); console.log(tom); // { name: 'tom', birthYear: 2002, occupation: 'teacher' }
-
Bind
const mike = { name: "mike", }; function update(birthYear, occupation) { this.birthYear = birthYear; this.occupation = occupation; } const updateMike = update.bind(mike); updateMike(1980, "police"); console.log(mike); // { name: 'mike', birthYear: 1980, occupation: 'police' }
bind는 항상 mike를 this로 받겠다고 하는 것. (사실 bind는 지정된 this를 가지는 함수를 반환해준다.) 따라서, updateMike에 첫번째 인자로 굳이 mike 객체라고 명시해주지 않아도 this는 mike로 이미 영구히 지정되어있다.
-
댓글남기기