-
자바스크립트 thisfrontend/javascript&web 2022. 2. 18. 10:16
쉽게 이해하는 자바스크립트 this
this
- 자신이 속한 객체 또는 자신이 생성할 인스턴스를 가르키는 자기참조변수
자바스크립트의 this는 자바를 비롯한 여타 언어들과는 상이하게 동작합니다. 이 개념을 잘 이해하신다면 우리가 특정 변수나 객체에 접근할 때 발생할 수 있는 문제에 대하여 사전에 방지할 수 있는 효과를 가지게 될 것입니다.
this의 동작방식
this 값은 호출방법에 의해 결정됩니다. 실행중에 할당으로 설정할 수 없고 호출할 때마다 다르게 동작합니다. 우리는 이러한 this의 값 결정 방식을 5가지로 분류 해볼 수 있습니다.
- 전역공간
- 함수 호출
- 메소드 호출
- 생성자 함수 호출
- apply / call / bind 호출
함수와 메소드를 혼동하지 맙시다. 함수는 객체로 부터 독립적이지만, 메소드는 객체에 종속되어 있습니다. 함수는 메소드를 아우르는 포괄적인 용어지만 다른 말이니 헤깔리지 않도록 합시다.
예시
1. 전역공간
//Browser console.log(this); // window //NodeJS console.log(this); // global
전역공간에서 자바스크립트 this값은 Browser(ClientSide) NodeJS(ServerSIde)환경에서 다르게 동작합니다. 기본적으로 this는 전역객체에 바인딩되며 전역객체는 모든 객체의 유일한 최상위 객체를 의미합니다.
2. 함수 호출
비 엄격 모드
function outer(){ console.log("outer의 this",this);//window function inner(){ console.log("inner의 this",this);//window } inner(); } outer();
엄격 모드
"use strict" function outer(){ console.log("outer의 this",this);//undefined function inner(){ console.log("inner의 this",this);//undefined } inner(); } outer();
함수 호출 시에도 기본적인 동작은 전역에서와 동일합니다. 하지만 "use strict"를 사용하여 엄격모드에 들어가면 this는 window 객체를 가르키지 않습니다. 개발할 떄 window객체를 개발자도 모르게 건드려 발생하는 사이드 이펙트를 막기위해 적용되었다고 합니다.
3. 메소드 호출
var value = 10; var test = { value : 100, getValue:function() { console.log(this.value); // 100 function findValue() { console.log(this.value); // 10 } findValue(); } } test.getValue();
메소드 호출시에는 this는 메소드 호출의 주체가 됩니다. getValue의 주체인 test가 된다고 볼 수 있습니다. 하지만 그 내부의 findValue는 전역을 가르키는 것을 볼 수 있습니다. 이런 것을 해결하기 위해서는 아래와 같이 작업할 수 있습니다.
var value = 10; var test = { value : 100, getValue:function() { console.log(this.value); // 100 const findValue = () => { console.log(this.value); // 100 } findValue(); } } test.getValue();
화살표 함수를 활용하면 다시 전역의 value값을 들고 올 수 있습니다.
var value = 10; var test = { value : 100, getValue:function() { const self = this; console.log(this.value); // 100 function findValue() { console.log(self.value); // 100 } findValue(); } } test.getValue();
다른 방법으로는 전역 this의 값을 할당받아 놓는 방법도 있습니다. 콜백과의 복합적인 상황에서도 재밋게 동작합니다.
const person = { name : null, setName : function(name) { this.name = name; } }; function setPersonName(name, callback) { callback(name); } setPersonName("류호진",person.setName); console.log(person.name); // null console.log(window.name); // 류호진
메소드를 콜백 함수로 사용하게 되면 메소드가 함수로써 호출되면서 객체와의 연결성이 사라져 this가 employee가 아닌 window를 바라보게 되면서 위와 같은 현상이 발생하게 됩니다.
4. 생성자 함수 호출
function Person(name, age){ this.name = name; this.age = age; } let person1 = new Person("류호진", 100); console.log(person1) /** Person { name : '류호진', age : 100 } */
new 키워드를 통해 생성자 함수 호출을 하게 되면, this는 객체 자기자신을 가르키게 됩니다. 하지만 new 키워드 없이 함수를 호출하면 어떻게 될까요?
function Person(name, age){ this.name = name; this.age = age; } Person("류호진", 100); console.log(window) /** window { name : '류호진', age : 100 } */
아주 당연하게도 일반함수 처럼 전역에 올라가있는 것을 확인할 수 있습니다.
5. call / apply / bind 호출
마지막으로, call / apply / bind 에 대하여 알아 보겠습니다. 자바스크립트 함수는 일급 객체이기 떄문에 메소드를 사용할 수 있습니다. call, apply, bind 메소드를 사용해서 함수를 실행 시킬 수 있는데, 함수가 호출될 컨텍스트를 지정하여 함수를 호출할 수 있게 도와줍니다. 이를 통해 this키워드가 무엇을 참조할지 명시적으로 지정할 수 있는 명시적 바인딩을 할 수 있습니다.
일급객체란 다른객체에 일반적으로 적용가능한 연산을 모두 지원하는 객체를 말하는 것으로, 변수에 할당할 수 있어야 하고, 다른 삼수를 인자로 전달받을 수 있으며, 다른함수의 결과로써 리턴될 수 있는 객체를 말합니다.
call
Func.call(thisArg[, arg1[, arg2[...]]])
call은 함수를 즉시 호출하며 위와 같은 매개변수 구조를 가집니다
- thisArg : Func 호출에 제공되는 this의 값을 명시
- arg 1, 2... : Func이 호출되어야하는 인수
let person = { name : "호진" }; let employee = { name : "무개" hire : function(position) { console.log(`${position} 개발자 ${this.name}이 고용 되었습니다`); } } employee.hire.call(person,'Front-End'); // Front-End 개발자 호진이 고용 되었습니다
위의 코드를 보면 this의 값을 person으로 명시하였기 때문에 call을 이용하여 호출하면 호진이 고용되었다는 메소드를 보여주게 됩니다.
apply
Func.apply(thisArg,[argsArray])
apply는 함수를 즉시 호출하며 위와 같은 매개변수 구조를 가집니다
- thisArg : Func 호출에 제공되는 this의 값을 명시
- [argsArray] : Func이 호출되어야 하는 인수를 지정하는 유사배열 객체
let person = { name : "호진" }; let employee = { name : "무개" hire : function(position) { console.log(`${position} 개발자 ${this.name}이 고용 되었습니다`); } } employee.hire.apply(person,['Front-End']); // Front-End 개발자 호진이 고용 되었습니다
apply와 call의 차이점은 첫번째 인자를 제외하고 필요한 파라미터를 apply는 배열로 집어 넣어야 한다는 것입니다. call은 필요한 인자를 넣을때 (thisArgs, "0번값","1번값") 넣는다면 apply는 (thisArgs,["0번값","1번값"]) 이렇게 넣으셔야 됩니다.
bind
Func.bind(thisArg[, arg1[, arg2[...]]])
bind는 함수를 즉시 호출하지 않으며 원본 함수를 복제한 새로운 함수를 반환해주기만 합니다. 또한 반환된 함수를 실행해야지만 원본함수가 실행됩니다. 위와 같은 매개변수 구조를 가집니다
- thisArg : Func 호출에 제공되는 this의 값을 명시
- arg 1, 2... : Func이 호출되어야 하는 인수
let person = { name : "호진" }; let employee = { name : "무개" hire : function(position) { console.log(`${position} 개발자 ${this.name}이 고용 되었습니다`); } } let company = employee.hire.bind(person,'Front-End'); company(); // Front-End 개발자 호진이 고용 되었습니다
추가로 알고가는 Arguments에 대하여..
함수에 전달되는 인수에 해당하는 Array형태의 객체를 arguments객체를 통해서 받을 수 있습니다.
function position(x, y, z) { console.log(arguments); } position(1, 3, 2); // Arguments(3) [1, 3, 2, callee: ƒ, Symbol(Symbol.iterator): ƒ]
이렇게 유사배열인 arguments객체를 통해서 받을 수 있습니다. 하지만 이것은 유사배열이지 배열이 아니기 때문에 배열의 메소드를 사용할 수 없습니다. 배열의 메소드를 사용하기 위해서는 call과 apply를 활용하여 사용할 수 있습니다.
function position(x, y, z) { console.log(Array.prototype.join.call(arguments)); } position(1, 3, 2); // 1,3,2
오늘은 자바스크립트 this의 개념에 대해서 전반적으로 보았습니다. 헤깔릴 수 있는 개념이고 기업들의 면접질문에도 단골질문으로 나오는 개념이니 꼭 알고가셨으면 좋겠습니다. 항상 최대한 쉽게 알려드릴 수 있도록 해보겠습니다.
반응형'frontend > javascript&web' 카테고리의 다른 글
[웹 최적화] 이미지 로딩 최적화(Image loading Optimzation) (0) 2022.09.13 이벤트 위임 - 캡처링/버블링 (Event Delegation - Captruring / Bubbling) (0) 2022.02.21 브라우저 저장소( 로컬 스토리지, 세션 스토리지, 쿠키 ) (0) 2022.02.17 프로토타입(Prototype) (0) 2022.02.16 이벤트 루프(Event Loop) (1) 2022.02.15