-
ES6 화살표 함수(arrow function)를 배우기 전 자바스크립트 this 이해하기CODING/JavaScript 2019. 3. 5. 18:41
ES6 arrow function 배우기 전 자바스크립트 this 이해하기
ES6 arrow function을 배우기 전 이해를 돕기 위해 자바스크립트의 this 에 대해서 간단하게 정리한다.
JAVA같은 언어에서 this는 클래스로부터 생성되는 인스턴스 객체를 의미한다.
다른 의미를 가질 염려가 없어서 혼란이 생기지 않는다.
자바스크립트에서는 this는 함수의 현재 실행 문맥(context)이다.
자바 스크립트에서는 4가지의 함수 실행 타입이 존재한다.
1. 함수 실행 alert('hello world');
2. 메소드 실행 console.log('hello world');
3. 생성자 실행 new Sample();
4. 간접 실행 alert.call(undefined, 'hello world');
각 타입은 서로 다른 각각의 문맥을 가진다. (+strict모드에서는 또 다르다......)
1. 함수 실행에서의 this
1234function sum(a,b){console.log(this === window); //truereturn a+b;}일반적인 함수 실행에서 this는 window객체다.
12345function sum(a,b){'use strict'; // strict모드console.log(this === undefined); //truereturn a+b;}strict모드로 실행되는 함수 실행에서 this는 undefined다.
* 실수 point
외부 함수에서의 this와 내부 함수에서의 this를 동일하게 생각하면 안된다.
내부 함수의 문맥은 오직 실행 환경에 따라 다르다.
1234567891011121314var numbers = {numberA: 5,numberB: 10,sum: function() {console.log(this === numbers); // => truefunction calculate() {// this는 window, 엄격 모드였으면 undefinedconsole.log(this === numbers); // => falsereturn this.numberA + this.numberB;}return calculate();}};numbers.sum(); // NaN, 엄격 모드였으면 TypeError내부의 calculate()는 외부 함수와 별개의 함수 실행으로 봐야 한다.
따라서 calculate()에서 this.numberA, this.numberB를 모르니까 계산할 수 없고 결과적으로 NaN이 나온다.
이 문제를 해결하려면 calculate()의 마지막에 return calculate.call(this); 라고 코딩해야 한다.
참고로 sum() 함수실행이 아니라 메소드 실행이다.
2. 메소드 실행에서의 this
this는 메소드 실행에서 메소드를 소유하고 있는 객체다.
12345678var numbers = {numberA: 5,numberB: 10,sum: function() {console.log(this === numbers); // => truereturn numberA+numberB;}};아까 예에서 알 수 있듯이 객체(numbers)안의 메소드를 실행한다면 그 때 this는 객체 자신이다.
ES6의 문법으로 클래스(class)를 정의할 때도 메소드의 실행 문맥은 인스턴스 객체 자신이다.
123456789101112class Planet {constructor(name) {this.name = name;}getName() {console.log(this === earth); // => truereturn this.name;}}var earth = new Planet('Earth');// 메소드 실행. 여기서의 this는 earth.earth.getName(); // => 'Earth'* 실수 point
객체 내에 있는 메소드는 별도의 변수로 분리가 가능하다.
이 변수를 통해 메소드를 호출할 때! this는 함수 호출에서의 문맥으로 바뀐다.
react 바인딩 관련 포스트에서도 다뤘듯 객체의 메서드를 다른 변수에 담을 수 있고
그 변수를 실행하는 방법으로 함수를 실행할 수 있지만 obj와의 관계가 상실되기 때문에 this가 달라진다.
123456789101112function Animal(type, legs) {this.type = type;this.legs = legs;this.logInfo = function() {console.log(this === myCat); // => falseconsole.log('The ' + this.type + ' has ' + this.legs + ' legs');}}var myCat = new Animal('Cat', 4);// "The undefined has undefined legs" 출력// 혹은 엄격모드라면 TypeError 출력setTimeout(myCat.logInfo, 1000);여기서도 setTimeout의 매개변수로 전달되었기 때문에 객체로부터 관계가 상실되면서 this는 myCat이 아니게 된다.
해결 방법은 react에서도 그랬듯 setTimeout(myCat.logInfo.bind(myCat),1000); 이런식으로 bind()함수를 사용해야 한다.
3. 생성자 실행에서의 this
말만 다를 뿐이지 사실 메소드 실행에서의 this와 같다.
즉, 생성자 함수를 실행에서 새롭게 만들어진 객체가 실행문맥이다.
1234567function Foo () {console.log(this instanceof Foo); // => truethis.property = 'Default Value';}// 생성자 실행var fooInstance = new Foo();fooInstance.property; // => 'Default Value'ES6에서의 class에서 생성자도 this는 새로 생긴 객체다.
123456789class Bar {constructor() {console.log(this instanceof Bar); // => truethis.property = 'Default Value';}}// Constructor invocationvar barInstance = new Bar();barInstance.property; // => 'Default Value'* 생성자 호출할 때 new를 빼먹는 실수만 하지 말자.
4. 간접 실행에서 this
간접 실행은 함수가 .call() 이나 .apply 메소드와 함께 호출될 때를 가리킨다.
.call(arg1,arg2,...) 메소드는 첫 번째 인자는 실행 문맥(this), 나머지 인자는 호출함수에 전달할 매개변수를 하나씩 받는다.
.aplly(arg1,[args]) 메소드는 첫 번째 인자는 실행 문맥(this), 나머지 인자는 호출 함수에 전달할 매개변수를 배열로 받는다.
12345678var rabbit = { name: 'White Rabbit' };function concatName(string) {console.log(this === rabbit); // => truereturn string + this.name;}// Indirect invocationsconcatName.call(rabbit, 'Hello '); // => 'Hello White Rabbit'concatName.apply(rabbit, ['Bye ']); // => 'Bye White Rabbit'간접 실행은 함수의 실행 문맥을 지정할 수 있기 때문에 유용하다.
위에서 함수 실행에서 this는 항상 window, strict모드에서는 undefined를 가리키는데 이 문제를 간접 실행으로 해결할 수 있다.
결국 간접 실행에서 this는 넘겨주기용 같다.(아직 명확하게 이해못했음.)
참고 사이트
https://github.com/FEDevelopers/tech.description/wiki/%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8%EC%97%90%EC%84%9C-%EC%82%AC%EC%9A%A9%EB%90%98%EB%8A%94-this%EC%97%90-%EB%8C%80%ED%95%9C-%EC%84%A4%EB%AA%85-1#1-this%EC%97%90-%EB%8C%80%ED%95%9C-%EB%AF%B8%EC%8A%A4%ED%84%B0%EB%A6%AC
출처: https://jeong-pro.tistory.com/109?category=799620 [기본기를 쌓는 정아마추어 코딩블로그]댓글