This
자바스크립트의 this 키워드는 거의 모든 상황에서 객체이며 문법적으로는 '나'와 비슷합니다. 그리고 다른 언어들과 비교해서 조금 다르게 동작합니다.
this의 값은 this를 사용하는 해당 함수를 어떻게 실행(함수를 호출하는 방법)하느냐에 따라 값이 바뀝니다.
this를 실행하는 방식
this는 크게 4가지 방식으로 실행을 하며 각각의 방식에 따라 가르키는 주체가 달라집니다. this의 값이 어떻게 변화하는지 어떤 값과 연결되는 지는 this의 바인딩을 통해서 확인해 볼 수 있는데요. 바인딩이랑 호출 방식에 따라서 this가 특정 '객체'에 연결되는 것 입니다.
- 일반 함수 내부에서 this는 글로벌 객체(window)와 바인딩이 됩니다.
- 메소드 내부에서 this는 메소드를 호출한 객체와 바인딩이 됩니다.
- 생성자 함수 내부에서 this는 생성자 함수가 생성할 인스턴스와 바인딩이 됩니다.
- Call, Apply, Bind 메소드 사용시 메소드에 첫 번째 인수로 전달하는 객체에 바인딩이 됩니다.
살펴보기
1. 일반 함수 실행 방식
1.1 strict mode가 아닌 경우
일반 함수 방식이란 아래와 같이 이론적으로 함수를 실행하는 가장 기본적인 방식입니다. 이 방식에서 this는 global object(브라우저 상에서는 window 객채)를 가르키고 있습니다.
function foo() {
console.log(this.name); // 'this' === global object (브라우저상에선 window 객체)
}
foo();
1.2 strict mode인 경우
strict mode에서 "this"는 undefined입니다. (window를 가르키려고 this를 쓰는 경우가 없기 때문입니다.)
'use strict';
var name = 'Barbie';
function foo() {
console.log
1.3 일반 함수 실행 방식 예제
아래 함수에서 99가 실행이 될 것 같지만 bar()라는 함수가 실행되는 부분에서 일반함수 실행방식으로 실행시켰기 때문에 this는 window가 되었고, window.age는 100이기 때문에 100이 실행되었습니다.
var age = 100;
function foo() {
var age = 99;
bar(age);
}
function bar(age) {
console.log(this.age); // 100
}
foo();
2. 점 방식 Dot Notation
오브젝트 메소드 형식으로 실행시키는 방식
2.1 Dot Notation 예제
this 함수를 호출할 때 함수 앞에 .를 사용하여 메소드를 실행시킬 경우, this는 .앞의 객체가 this의 값으로 설정이 되어집니다.
var age = 100;
var Barbie = {
age: 21,
foo: functin foo() {
console.log(this.age); // 21
}
};
ken.foo();
2.2 Dot Notation 예제
그냥 foo()를 실행하게 되면 100이 출력되겠지만 dot notation 방식으로 실행을 하기 때문에 this가 가르키는 값이 .앞의 객체로 바뀌게 됩니다.
function foo() {
console.log(this.age);
}
var age = 100;
var Barbie = {
age: 21,
foo: foo
};
var Ken = {
age: 23,
foo: foo
};
Ken.foo(); // 23
Barbie.foo(); // 21
2.3 Dot Notation 예제
Barbie.foo: Barbie이라는 객체안의 메소드지만 결국 bar라는 함수이다. 객체안의 메소드지만 this의 방식에 따라 각각 다르게 호출이 되어집니다.
var age = 100;
var Barbie = {
age: 21,
foo: function bar() {
console.log(this.age);
}
};
var Ken = {
age: 23,
foo: Barbie.foo
};
var foo = Barbie.foo;
Barbie.foo(); // 21
Ken.foo(); // 23
foo();
3. 명시적 바인딩 Explicit Binding - Function.prototype.call, Function.prototype.bind, Function.prototype.apply
call, bind, apply와 같은 메소드들을 사용해서 함수를 실행하는 명시적 바인딩 방법. call과 apply 메소드는 기본적으로 함수를 호출하는 역할을 합니다. 기존 함수 호출과의 차이점은 무엇일가요? 그것은 해당 메소드를 사용하여 함수를 실행하면, 함수의 첫 번째 인자로 전달하는 객체에 this를 바인딩 할 수 있다는 것입니다. 이를 통해 유사 배열 arguments 객체에 배열 메소드를 사용할 수 있습니다. 반면, bind는 첫 번째 인자를 this에 바인딩하지만 함수를 실행하지 않고, 새로운 함수를 반환합니다.
3.1 Explicit binding 예제
foo.apply(Barbie): foo() 라는 함수가 실행이 되고 Barbie이라는 인자값이 this의 값으로 설정이 되어 실행이 된다.
일반함수 실행 방식, Dot Notation 방식과 다르게 this의 값이 어떤 객체가 되어야 하는지 개발자가 직접 정하고 명령을 내릴 수 있습니다.
var age = 100;
function foo() {
console.log(this.age);
}
var Barbie = {
age: 21,
log: foo
};
// foo function gets invoked
// `this` refers to first argument
foo.call(Barbie);
var barbieLog = Barbie.log;
barbieLog();
foo.call(Barbie); // ?
foo.apply(Barbie); // ?
3.2 Explicit binding 예제
foo.call(Barbie, 1, 2, 3, 4, 5); : 21, 1, 2, 3, 4, 5 가 담겨있는 유사배열 출력이 됩니다. 인자가 여러개 인 경우, 첫번째 인자가 this 값으로 설정이 되어 실행되게 됩니다. 두번째 인자부터는 나머지는 foo라는 함수의 인자값으로 넘어가게 됩니다.
foo.apply(): call은 인자의 수가 정해져있지 않고 그냥 보내주면 됩니다. apply는 항상 인자를 두 개만 받으며, 두 번째 인자는 무조건 배열이 되어야 하며, foo라는 함수 안에 인자로 각각 들어가게 됩니다.
var age = 100;
function foo(a, b, c) {
console.log(this.age);
console.log(arguments);
}
var Barbie = {
age: 21
};
foo.call(Barbie, 1, 2, 3, 4, 5);
foo.apply(Barbie, [1, 2, 3, 4, 5]);
3.3 Explicit binding 예제
Barbie이라는 인자값을 넘겨주고 bind라는 메소드를 실행한 결과값을 bar이라는 변수에 담는다.
bind라는 메소드는 모든 함수에 사용이 가능하며, 첫번째 인자로 받는 Barbie은 this 값으로 설정됩니다. call과 bind와는 다르게 해당 함수(foo)를 바로 실행시키지 않습니다. 하지만 foo라는 함수 안의 this 값을 Barbie으로 설정해놓은 함수를 반환해줍니다.
var age = 100;
function foo() {
console.log(this.age);
}
var Barbie = {
age: 21,
log: foo
};
var bar = foo.bind(Barbie);
var baz = foo;
bar(); // 이때 함수가 실행된다.
baz();
4. 'new' keyword 방식
this의 값을 판별하기 위해서는 foo라는 함수가 어떻게 실행되느냐를 찾아야 합니다. new라는 단어를 앞에 넣어 실행을 했습니다. 이럴 경우, this의 값은 빈 객체가 생성이 된다고 생각하면 됩니다. 빈 객체가 새롭게 생성되서 함수 속의 this 값으로 할당되어 함수가 실행됩니다. (새로운 객체가 this 값으로 들어가게 됩니다.)
function Person() {
console.log(this);
this.age = 3333;
}
new Person();
4.2 'new' keyword 예제
new Person() 하면 this 는 새로운 객체가 됩니다. Person 함수 내부에는 빈 객체의 name 이라는 key에 Barbie이라는 이름을 할당해줍니다. Person 안에는 return 값이 없지만 new 라는 단어를 사용하면 리턴을 시키지 않았지만 new 를 사용하여 함수를 실행하게 되면 사용자가 명시하지 않아도 자동으로 return this;가 자동으로 쓰여집니다. 그러므로 보통 new 라는 키워드를 쓸 경우, return은 잘 쓰이지 않습니다.
function Person() {
// this = {};
this.name = 'Barbie';
// {
// name: 'Barbie';
// }
// return this;
}
var ken = new Person();
console.log(Barbie); // Person? {name: "Barbie"}
4.3 'new' keyword 예제
함수이기 때문에 마찬가지로 인자를 넣을 수 있습니다.
function Person(name) {
this.name = name;
console.log(this);
}
var ken = new Person('Barbie');
console.log(Barbie); // Person {name: 'Barbie'};
4.4 'new' keyword 예제: Constructor function (생성자 함수)
생성자 함수는 보통 맨 앞을 대문자로 바꿔줍니다. new를 써서 함수를 실행시킬때마다 this에는 새로운 객체가 할당되어 실행이 됩니다. 새로 만들어진 객체들은 instance 라고 불려집니다.
function Person(name, age) {
this.name = name;
this.age = age;
}
// instance 라고 한다.
var Barbie = new Person('Barbie Doll', 21);
var Ken = new Person('Ken Doll', 23);
console.log(Barbie); // Person?
console.log(Ken); // Person?{name: "Ken Doll", age: 23}
// 새로운 객체가 선택이 됩니다.
마치며
자바스크립트의 this에 대해서 공부를 해보았는데요. 이 4가지 상황을 생각해보며 연습을 해본다면 this 개념에 대하여 조금 더 확실히 알 수 있을 것 같습니다.
어디까지나 this에도 나름의 규칙이 있으니까요(!)
참고사이트
'Front End' 카테고리의 다른 글
[Vue.js] 간단한 Vue 기본 상식 시리즈 -2 Vue 3 프로젝트 시작하기 (0) | 2023.01.12 |
---|---|
[Vue.js] 간단한 Vue 기본 상식 시리즈 -1 IDE 고르기 (0) | 2023.01.07 |
[JavaScript] ECMAScript 6부터 추가된 데이터 타입 - 심벌(Symbol)과 템플릿 리터럴(Template Literal) (0) | 2022.08.07 |
자주 나오는 프론트엔드 개발자 취업 면접 질문 및 답변 정리-2 (0) | 2022.06.24 |
자주 나오는 프론트엔드 개발자 취업 면접 질문 및 답변 정리-1 (0) | 2022.06.22 |