단독으로 쓴 this
기본적으로 this를 호출하는 경우엔 global object를 가리킨다.
브라우저에서 호출하는 경우 [object Window]가 된다.
이는 ES5에서 추가된 strict mode(엄격 모드)에서도 마찬가지이다.
'use strict';
var x = this;
console.log(x); // Window
함수 안에서 쓴 this
함수 안에서 this는 함수의 주인에게 바인딩된다.
함수의 주인은 window가 된다.
function thisTest() {
return this;
}
console.log(thisTest()); // Window
var num = 0;
function addNum() {
this.num = 100;
num++;
console.log(num); // 101
console.log(window.num); // 101
console.log(num === window.num); // true
}
addNum();
위 코드에서 this.num의 this는 window 객체를 가리킨다. 따라서 num은 전역 변수를 가리키게 된다.
다만, 엄격모드(Strict Mode)에서는 조금 다르다. 함수 내의 this 디폴트 바인딩이 없기 때문에 undefined가 된다.
"use strict";
function myFunction() {
return this;
}
console.log(myFunction()); // undefined
"use strict"
var num = 0;
function addNum() {
this.num = 100; // ERROR! Cannot set property 'num' of undefined;
num++;
}
addNum();
따라서 this.num을 호출하면 undefined.num을 호출하는 것과 마찬가지기 때문에 에러가 난다.
2번에서 의문점이 들었는데,
var 변수로 선언을 하면서 window랑 연결이 되고, let · const는 위의 코드처럼 동작하지 않는다.
전역 범위를 대표하는 객체는 분명 window이다.
Global Scope에서 선언된 함수, 그리고 var 키워드를 이용해 선언된 변수는 window 객체와 연결된다고 한다.
var 키워드로 선언된 변수는 window 라는 객체와 연결이 되지만, let 키워드는 window 객체에 저장이 되지 않는다.
그렇기 때문에 var 키워드 사용을 최대한 지양해야하며, 전역변수의 선언을 너무 많이 사용해버리면 코드의 이름이 중복되어 버그가 발생할 가능성이 있기 때문에, 우리는 let 키워드의 스코프를 통해 확실하게 구분을 시켜주어야한다.
선언 키워드(var, let ,const) 없이 변수를 초기화하게 되면, var 키워드로 자동 인식이 되어져 스코프 안에 있더라도 변수가 전역변수로 지정이 된다. 이러한 실수를 하지 않도록 let 또는 const 키워드를 선언해주자.
(키워드 없이 선언된 변수, 변수 명의 중복 등 버그를 발생하고자 'use strict' strict mode를 사용한다)
메서드 안에서 쓴 this
일반 함수가 아닌 메서드에서 메서드 호출 시 내부 코드에서 사용된 this는 해당 메서드를 호출한 객체로 바인딩 된다.
var person = {
firstName: 'John',
lastName: 'Doe',
fullName: function() {
return this.firstName + ' ' + this.lastName;
},
};
person.fullName(); // John Doe
var num = 0;
function showNum() {
console.log(this.num);
}
showNum(); // 0
var obj = {
num: 200,
func: showNum,
};
obj.func(); // 200
이벤트 핸들러 안에서 쓴 this
이벤트 핸들러에서 this는 이벤트를 받는 HTML 요소를 가리킨다.
var btn = document.querySelector("#btn");
btn.addEventListener("click", function() {
console.log(this); // #btn
});
생성자 안에서 쓴 this
생성자 함수가 생성하는 객체로 this가 바인딩 된다.
function Person(name) {
this.name = name;
}
var kim = new Person('kim');
var lee = new Person('lee');
console.log(kim.name); // kim
console.log(lee.name); // lee
new 키워드를 빼먹는 순간 일반함수 호출과 같아지기 때문에, 이 경우는 this가 window에 바인딩 된다.
var name = 'window';
function Person(name) {
this.name = name;
};
var kim = Person('kim');
console.log(window.name); // kim
명시적 바인딩을 한 this
명시적 바인딩은 짝을 지어주는 것이다. 쉽게 말해 어떤 함수를 통해 내가 원하는 인자를 this로 만들어주는 것이다.
Apply와 Call 메소드가 대표적이다.
function whoisThis() {
console.log(this);
};
whoisThis(); // window;
var obj = {
x: 123
};
whoisThis.call(obj) // {x : 123}
whoisThis.apply(obj) // {x : 123}
call과 apply 경우, 첫번째로 넣어준 인자가 this로 사용이 되어진다.
이 둘의 공통점은 첫 번째 인자로 넣어준 값이 this로 사용된다는 점인데 이 둘의 차이점은 매개변수로 입력할 값에 대한 입력 방식이다.
function Character(name, level) {
this.name = name;
this.level = level;
}
function Player(name, level, job) {
Character.apply(this, [name, level]);
this.job = job;
}
var me = new Player('Nana', 10, 'Magician');
function Character(name, level) {
this.name = name;
this.level = level;
}
function Player(name, level, job) {
Character.call(this, name, level);
this.job = job;
}
var me = {};
Player.call(me, 'nana', 10, 'Magician');
call은 인수 목록을 받고, apply는 인수 배열을 받는다는 차이점을 가지고 있다.
apply와 call은 보통 유사 배열 객체에게 배열 메서드를 쓰고자할 때 사용을 한다.
function func(a, b, c) {
console.log(arguments);
arguments.push("hi!"); // ERROR! (arguments.push is not a function);
}
function func(a, b, c) {
var args = Array.prototype.slice.apply(arguments);
args.push("hi!");
console.log(args);
}
func(1,2,3); // [1,2,3, 'hi!']
* arguments : arguments 객체는 모든 함수 내에서 이용 가능한 지역 변수입니다. arguments 객체를 사용하여 함수 내에서 모든 인수를 참조할 수 있으며, 호출할 때 제공한 인수 각각에 대한 항목을 갖고 있습니다. 항목의 인덱스는 0부터 시작합니다. (MDN)
aruguments 객체를 apply 또는 call을 통해 배열로 변경을 할 수가 있다.
추가적으로 ES6 이상부터 Array.from()과 스프레스 연산자를 통해 유사 배열 객체를 얕게 복사해 새 Array 객체로 만든다.
화살표 함수로 작성된 this
함수 안에서 this가 전역 객체가 된다고 싶을 때는 화살표 함수를 사용하면 된다.
화살표 함수는 전역 컨텍스트에서 실행되더라도 this를 새로 정의하지 않고, 바로 바깥 함수나 클래스의 this를 사용하기 때문이다.
var Person = function(name, age) {
this.name = name;
this.age = age;
this.say = function() {
console.log(this); // Person {name: "Nana", age: 28}
setTimeout(function () {
console.log(this);
console.log(this.name + ' is ' + this.age + ' years old');
}, 100);
};
};
var me = new Person('Nana', 28);
me.say();
위의 코드를 보면 내부 함수에서 this가 전역 객체를 가리키는 바람에 의도와는 다른 결과가 나왔다.
var Person = function (name, age) {
this.name = name;
this.age = age;
this.say = function() {
console.log(this); // Person {name: "Nana", age: 28}
setTimeout(() => {
console.log(this); // Person {name: "Nana", age: 28}
console.log(this.name + ' is ' + this.age + ' years old');
}, 100);
};
};
var me = new Person('Nana', 28); // Nana is 28 years old
화살표 함수로 바꾸면, 함수 안에서 this가 전역객체를 가리키지 않고 함수 안의 this를 가리키게 된다.
레퍼런스
'개발적인' 카테고리의 다른 글
[에러일지] ESLint - Function component is not a function declaration (0) | 2023.03.01 |
---|---|
토스 채용 서비스인 줄 알았는데,, (0) | 2023.02.24 |
Axios Header에 Access Token을 넘기는 방법은? (0) | 2023.01.07 |
요즘 많이 사용하는 JWT는 뭘까? (0) | 2023.01.05 |
useEffect는 왜 사용할까? (0) | 2022.12.05 |
댓글