this 질문 리스트
해당하는 질문들을 대답할 수 있도록, 본인이 공부한 흐름에 맞게 정리하여 올려주세요.
자바스크립트에서 this는 다른 언어와 어떤 차이점이 있나요?
호출 방식에 따라 어떤 값을 가질 수 있나요?
call/apply/bind의 역할은 무엇인가요?
화살표 함수를 통한 정적 바인딩이 좋은 방법인가요? 상황별로 다르다면, 어떤 상황에서 화살표 함수를 통해 this를 정적 바인딩 하는 것이 좋고, 어떤 상황에서 좋지 않을까요?
인수 this
수경 this
함수 실행에서의 this
함수 실행에서의 this는 전역 객체다
전역 객체는 실행하는 환경마다 다릅니다. 웹 브라우저에서는
window
객체가 전역 객체가 된다.function sum(a, b) { console.log(this === window); // => true this.myNumber = 20; // 전역 객체에 'myNumber'라는 속성을 추가 return a + b; } // sum()은 함수 호출이다. // sum()에서의 this는 전역 객체다. (window) sum(15, 16); // => 31 window.myNumber; // => 20
또한 this가 함수 스코프 밖(최상단: 전역 실행 문맥)에서 사용되었을 경우, 여기서의 this 역시 전역 객체를 참조하게 된다.
console.log(this === window); // => true this.myString = 'Hello World!'; console.log(window.myString); // => 'Hello World!'
엄격 모드 함수 실행에서의 this
엄격 모드에서 함수 실행에서의 this는 undefined이다.
자바스크립트의 엄격 모드는 ES5에서 등장하였으며, 코드 안정성과 더 나은 오류 검증을 제공하기 위해 등장하였다.
use strict
를 사용하여 엄격 모드를 적용시킬 수 있다.function multiply(a, b) { 'use strict'; // 엄격 모드 console.log(this === undefined); // => true return a * b; } // multiply() 함수는 엄격 모드로 실행됨 // multiply()에서의 this는 undefined multiply(2, 5); // => 10
엄격 모드에서는 this의 값이 window 전역 객체를 참조하지 않고
undefined
로 만든다.엄격 모드는 현재 스코프 뿐만 아니라 내부 스코프에서도 적용됩니다.
function execute() { 'use strict'; // 엄격 모드 function concat(str1, str2) { // 이곳에서도 마찬가지로 엄격 모드 console.log(this === undefined); // => true return str1 + str2; } // concat() 함수는 엄격 모드 // concat() 함수 안에서의 this는 undefined concat('Hello', ' World!'); // => "Hello World!" } execute();
내부 함수에서의 this를 사용할 때
내부 함수의 문맥은 외부 함수의 문맥에 의존하는 것이 아니라 오직 실행 환경에 좌우된다.
var numbers = { numberA: 5, numberB: 10, sum: function() { console.log(this === numbers); // => true function calculate() { // this는 window, 엄격 모드였으면 undefined console.log(this === numbers); // => false return this.numberA + this.numberB; } return calculate(); } }; numbers.sum(); // NaN, 엄격 모드였으면 TypeError
numbers.sum()
은 객체 내에 있는 메소드를 실행하는 것이다. 따라서 this는 numbers
를 가리킨다.하지만
calculate()
는 메소드 실행이 아닌 함수 실행이다. 이 함수에서의 this는 window
를 가리킨다.(엄격모드라면 undfined)이 문제의 해결책 중 하나로
.call
메소드를 사용하는 방법이 있다.var numbers = { numberA: 5, numberB: 10, sum: function() { console.log(this === numbers); // => true function calculate() { console.log(this === numbers); // => true return this.numberA + this.numberB; } // 문맥을 수정하기 위해 .call() 메소드를 적용 return calculate.call(this); } }; numbers.sum(); // => 15
메소드 실행에서의 this
함수 실행과 메소드 실행은 서로 다르다. 가장 큰 차이점은 메소드 실행은 속성 접근자를 사용하여 호출한다.
this는 메소드 실행에서 메소드를 소유하고 있는 객체이다.
var myDog = Object.create({ sayName: function() { console.log(this === myDog); // => true return this.name; } }); myDog.name = 'Milo'; // 메소드 실행. 여기서의 this는 myDog. myDog.sayName(); // => 'Milo'
ES6의 class 예약어에서의 this는 인스턴스 자신을 가리킨다.
class Planet { constructor(name) { this.name = name; } getName() { console.log(this === earth); // => true return this.name; } } var earth = new Planet('Earth'); // 메소드 실행. 여기서의 this는 earth. earth.getName(); // => 'Earth'
생성자 함수에서의 this
생성자 실행에서의 this는 새롭게 만들어진 객체이다.
function Foo () { console.log(this instanceof Foo); // => true this.property = 'Default Value'; } // 생성자 실행 var fooInstance = new Foo(); fooInstance.property; // => 'Default Value'
여기서 잠깐, 만약
new
를 사용하지 않는다면 함수 실행이 되므로 this는 window객체를 가리키게 된다. function Vehicle(type, wheelsCount) { this.type = type; this.wheelsCount = wheelsCount; return this; } // Function invocation var car = Vehicle('Car', 4); car.type; // => 'Car' car.wheelsCount // => 4 car === window // => true
call(), apply()와 bind()
[ call과 apply]
간접 실행인.call()
과.apply()
메소드에서는 첫 번째 매개 변수로 this를 받는다.
두 메서드는 넘겨받는 인자의 형식만 다를 뿐, this를 특정 객체에 바인딩하여 함수를 호출하는 역할을 한다.
call과 apply의 가장 큰 차이점은 call메서드는 인수를 그대로 넘길 수 있지만 apply메서드는 함수에 전달할 인자들을 배열 형태로 전달해야한다는 것이다.
[bind]
비인딩 함수는 일반 함수에.bind()
메서드가 적용된 것을 의미한다. bind 메서드의 첫 번째 인자로는 바인딩 함수에 적용할 this를 받는다. 그리고 함수를 호출하는 것이 아니라 새로운 함수를 반환한다.
function multiply(number) { 'use strict'; return this * number; } // 문맥을 지정해서 바인딩 함수를 생성 var double = multiply.bind(2); // 바인딩 함수를 실행 double(3); // => 6 double(10); // => 20
화살표 함수에서의 this
화살표 함수는 함수가 어떻게 호출되었는지에 따라 this에 바인딩할 객체가 동적으로 결정된다. 화살표 함수의 this 언제나 상위 스코프의 this를 가리킨다
class Point { constructor(x, y) { this.x = x; this.y = y; } log() { console.log(this === myPoint); // => true setTimeout(()=> { console.log(this === myPoint); // => true console.log(this.x + ':' + this.y); // => '95:165' }, 1000); } } var myPoint = new Point(95, 165); myPoint.log();
[자주하는 실수] - 화살표 함수를 사용해서는 안되는 경우
- prototype
function Period (hours, minutes) { this.hours = hours; this.minutes = minutes; } Period.prototype.format = () => { console.log(this === window); // => true return this.hours + ' hours and ' + this.minutes + ' minutes'; }; var walkPeriod = new Period(2, 30); walkPeriod.format(); // => 'undefined hours and undefined minutes'
format은 화살표 함수고, 전역에 정의 되었기 때문에 여기서의 this는 상위 컨텍스트인 전역 객체 window를 가리키게 된다.
- 메소드
// Bad const person = { name: 'Lee', }; Object.prototype.sayHi = () => console.log(`Hi ${this.name}`); person.sayHi(); // Hi undefined
- 생성자 함수
const Foo = () => {}; // 화살표 함수는 prototype 프로퍼티가 없다 console.log(Foo.hasOwnProperty('prototype')); // false const foo = new Foo(); // TypeError: Foo is not a constructor
화살표 함수는 생성자 함수가 가지고 있어야 할 prototype 프로퍼티가 없다.
- addEventListener 함수의 콜백 함수
// Bad var button = document.getElementById('myButton'); button.addEventListener('click', () => { console.log(this === window); // => true this.innerHTML = 'Clicked button'; }); button.addEventListener('click', function(){ console.log(this); // button 객체에 바인딩 됨 this.innerHTML = 'Clicked button'; });
addEventListener 함수의 콜백 함수를 화살표 함수로 정의하면 this가 상위 컨택스트인 전역 객체 window를 가리킨다. 일반 함수를 addEventListener() 함수의 콜백으로 넘긴 경우 this는 event.currentTarget 프로퍼티와 동일한 값을 가진다.
창민 this
자바스크립트에서 this는 다른 언어와 어떤 차이점이 있나요?
답변
함수가 호출되는 방식에 따라 this에 바인딩되는 값이 동적으로 결정된다
호출 방식에 따라 어떤 값을 가질 수 있나요?
답변
일반 함수 ⇒ 전역 객체
생성자 함수 ⇒ 함수가 생성할 인스턴스
메서드 ⇒ 메서드를 호출한 객체
call/apply/bind
메서드에 의한 간접 호출 ⇒ 첫 번째 인수로 전달한 특정 객체call/apply/bind
의 역할은 무엇인가요?답변
call
apply
는 첫 번째 인수로 전달한 특정 객체를 this에 바인딩하고 함수를 호출한다bind
또한 바인딩할 객체를 전달하지만 앞서 말한 두 가지와 다른 점은 호출을 하지 않는다화살표 함수를 통한 정적 바인딩이 좋은 방법인가요? 상황별로 다르다면, 어떤 상황에서 화살표 함수를 통해 this를 정적 바인딩 하는 것이 좋고, 어떤 상황에서 좋지 않을까요?
답변
메서드로 화살표 함수를 사용하면 상위 스코프의 this가 바인딩되기 때문에 유의해서 사용해야 한다