이 글은 [JS/this] 자바스크립트, this의 4가지 역할 :: Code Playground (tistory.com)를 참조해서 작성하였습니다.
JS에는 this 라는 키워드가 있다. this는 코드에 따라 다양한 값을 가지는데 this가 쓰이는 함수를 어떤 방식으로 실행하느냐에 따라서 그 역할이 구분된다.
1. 일반 함수 실행 방식
일반함수 실행 방식이란 함수를 선언한 후, 실행할 때 흔히 사용되는 방식이다.
일반함수 실행 방식으로 함수를 실행했을 때, this의 값은 Global Object를 가리킨다. 즉, 브라우저 상에서는 window객체를 말한다.
function foo () {
console.log(this);
}
foo();
//Window {0: Window, window: Window, self: Window, document: document, name: '', location: Location, …}
출처: https://im-developer.tistory.com/96 [Code Playground]
위 코드에서 foo함수를 선언하고 foo();로 실행하였다. 여기서 foo(); 이렇게 함수를 호출하는 방식을 일반함수 실행방식이라고 한다.
var name = 'Julia';
function foo () {
console.log(this.name); // 'Julia'
}
foo();
출처: https://im-developer.tistory.com/96 [Code Playground]
이 코드에서 전역변수로 name 변수를 만들고 'Julia'값을 할당하였다. 이 변수는 전역변수이기 때문에 전역 객체인 window에 속성으로 추가한다. 즉, var name = 'Julia';라는 코드를 쓰면 window 객체에 name이라는 key와 'Julia'라는 value가 추가된다.
또한 foo함수를 선언하고 일반함수 실행 방식으로 실행하였다. 이 떄의 this는 window객체를 가리키므로 위 코드의 console.log(this.name);은 console.log(window.name);과 같다.
var age = 100;
function foo () {
var age = 99;
bar(age)
}
function bar () {
console.log(this.age);
}
foo();
//결과 : 100
출처: https://im-developer.tistory.com/96 [Code Playground]
이 코드에서 foo() 내에서 bar() 함수가 실행되고 있다. 이 때 var함수는 foo함수 내부에서 일반함수 실행되고 있다. 따라서 bar함수에 매개변수로 무엇을 넘겨주던 bar함수 내부의 this.age는 window.age를 가리키고 이는 전역 변수로 선언된 age변수의 값이다. 그러므로 위의 코드의 결과는 100이 나온다.
** Strict mode에서 일반함수 실행 방식
Strice mode에서 실행되는 코드들은 좀 더 엄격한 규칙들을 적용받게 된다. Strice mode를 사용하는 이유는 비엄격 모드에서 자주 일어나는 실수들을 방지하여 각종 에러를 감소시키는데 있다.
Strict mode - JavaScript | MDN (mozilla.org)
'use strict';
var name = 'Julia';
function foo () {
console.log(this.name); // error
}
foo();
출처: https://im-developer.tistory.com/96 [Code Playground]
보통 일반함수 실행박식에서 this는 window객체를 가리킨다. 그러나 strict mode에서 this는 무조건 undefined이다. 따라서 위 코드에서 this.name을 출력하면 foo함수가 일반함수 실행방식으로 실행되었다 하더라도 strict mode이기 때문에 this는 undefined가 된다. undefined는 어떤 속성도 없으므로 this.neame은 실행될수가 없으므로 에러가 발생한다.
2. 도트 표기법(Dot Notation)
Dot notation이란 객체를 만들고 그 객체의 key와 value를 부여한 후 도트(.)로 값에 접근하는 방식이다.
var age = 100;
var ken = {
age: 35,
foo: function () {
console.log(this.age); // 35
}
}
ken.foo();
출처: https://im-developer.tistory.com/96 [Code Playground]
ken이라는 변수에 객체를 할당하였다. ken에 foo메서드를 만들었고 this.age를 출력하도록 하였다. 이후에 ken.foo();라고 함수를 실행하고 있는데, 이렇게 도트를 사용하여 객체 속성의 값에 접근하는 방식을 Dot Notation이라고 한다.
이렇게 Dot Notation으로 함수가 실행되면, this는 도트 앞에 써 있는 개체 자체를 가리킨다. 즉, 위 코드에서 this.age의 this는 ken을 가리킨다. 그러므로 this.age는 ken.age와 같이 때문에 35가 출력된다.
function foo() {
console.log(this.age);
}
var age = 100;
var ken = {
age: 36,
foo: foo
}
var wan = {
age: 32,
foo: foo
}
ken.foo(); // 36
wan.foo(); // 32
var fn = ken.foo;
fn(); // 100
출처: https://im-developer.tistory.com/96 [Code Playground]
함수 foo는 this.age를 출력한다. 그리고 전역변수 age가 선언되어 100이라는 값이 할당되었다. 그리고 ken 이라는 객체가 선언되어 age와 foo라는 key를 부여하였다. foo의 value는 함수 foo의 이름이다.
ken.foo()는 Dot Notation으로 실행되었으므로 this는 ken객체를 가리키게 된다. 따라서 36이라는 결과가 나오게 된다.
그러나 fn변수에는 ken.foo를 할당하였고 fn();로 실행하였다. 이는 일반함수 실행방식으로 실행 한 것이다.
따라서 이때의 this는 Global Objece를 가리키게 되고 전역 변수 age의 값인 100이 출력된다.
3. 명백한 바인딩(Explicit BIndine) / call, bind, apply
this의 역할을 직접 명확하게 지정해주는 것이다. 이는 function.prototype.call, function.prototype.bind, function.ptorotype.apply와 같은 메서드를 사용하여 할 수 있다.
var age = 100;
function foo() {
console.log(this.age);
}
var ken = {
age: 35,
log: foo
}
foo.call(ken, 1, 2, 3);
출처: https://im-developer.tistory.com/96 [Code Playground]
위 코드에서 foo 함수에 call메서드를 사용하여 호출하였는데 인자로 각각 ken, 1, 2, 3을 주었다. 이 인자들 중에서 첫번째로 쓴 ken이 this의 값으로 지정된다. 1, 2, 3은 this의 값과는 상관없이 순서대로 foo 함수가 된다. 까라서 위 코드에서 this.age는 ken.age가 되어 35가 출력된다.
Function.prototype.call() - JavaScript | MDN (mozilla.org)
var age = 100;
function foo() {
console.log(this.age);
}
var ken = {
age: 35,
log: foo
}
foo.apply(ken, [1, 2, 3, 4, 5]);
출처: https://im-developer.tistory.com/96 [Code Playground]
apply또한 같은 역할을 한다. apply는 this의 값을 지정해주는 인자 외에도 배열을 인자로 넣을 수 있는데, 이 배열의 값이 순차적을 foo함수의 인자가 된다.
Function.prototype.apply() - JavaScript | MDN (mozilla.org)
4. new키워드를 사용한 함수 실행
new키워드를 사용한 생성자 함수에서 this는 빈 객체가 된다.
function Person () {
console.log(this);
}
new Person();
출처: https://im-developer.tistory.com/96 [Code Playground]
위 코드에서 Person이라는 함수를 선언하였고 new 키워드를 사용해서 Person함수를 생성자 함수로 사용하였다.
이 때 this는 빈 객체를 가리키며 위의 생성자 함수는 this라는 빈 객체를 return 한다.(return 문이 없더라도! 이는 생성자 함수의 특징이다!)
function Foo () {
console.log(this.age); // undefined
this.age = 100; // 빈 객체에 속성 추가
console.log(this.age); // 100
}
new Foo();
출처: https://im-developer.tistory.com/96 [Code Playground]
위 코드에서 Foo함수가 new키워드와 함께 생성자 함수로 사용되는 즉시 함수 내부의 this는 빈 객체가 되며 this.age=100;을 통해 프로퍼티를 추가한다. 따라서 console.log(this.age);에서 100을 출력하고 Foo함수는 {age:100} 객체를 리턴한다!
function Person () {
this.name = 'ken';
console.log(this);
}
var ken = new Person();
console.log(ken);
출처: https://im-developer.tistory.com/96 [Code Playground]
위 코드에서 변수 ken에는 Person()이라는 함수가 new키워드를 사용해서 생성자함수로 생성되었다. 따라서 this는 빈 객체를 생성하여 this.name = 'ken'을 통해 빈 객체에 값을 입력시킨다. 그리고 생성자 함수로 생성된 함수이므로 return문이 없음에도 이 객체가 리턴된다. 따라서 ken이라는 변수에는 {name: 'ken'}이라는 객체가 할당되어 console.log에는 그 객체가 반환된다.
만약 위 코드가 일반함수 실행방식으로 실행되었다면 this는 window를 가리키게 될 것이고 window객체에 name이란 속성과 'ken'이라는 값이 추가되었을 것이다. 또한 return문이 없기 떄문에 어떠한 값도 리턴하지 않는다.(생성자 함수가 아니므로) 따라서 console창에는 undefined가 출력된다.
function foo () {
this.age = 100;
return 3;
}
var a = new foo();
console.log(a);
출처: https://im-developer.tistory.com/96 [Code Playground]
생성자 함수는 return문이 함수내에 있음에도 불구하고 그 return문을 무시하고 this객체를 return하는 특징이 있다.
위의 코드에서 일반함수였다면 3이 리턴되어서 3이 출력되어야 하는데 생성자 함수로 생성되었기 때문에 {age:100}이 리턴된다.
function foo () {
this.age = 100;
return { haha: 23232 };
}
var a = new foo();
console.log(a);
출처: https://im-developer.tistory.com/96 [Code Playground]
그러나 생성자 함수도 리턴되는 대상이 객체라면 this객체 대신 해당 객체가 리턴된다.
위의 코드에서 a는 {age:100}이 아닌 {haha:23232}가 리턴된다.
참조)
[JS/this] 자바스크립트, this의 4가지 역할 :: Code Playground (tistory.com)
'바닐라코딩 사전학습 > JS' 카테고리의 다른 글
Prototype 객체 (0) | 2021.12.28 |
---|---|
Windows 객체 (0) | 2021.12.28 |
new 예약어 (0) | 2021.12.27 |
객체 생성자 함수 (0) | 2021.12.27 |
Call by value / Call by reference (0) | 2021.12.27 |