요즘 JS를 배우고 있는데 변수를 선언할 때 let, const로 배우고 있지만, 예전 코드들을 찾아보면 심심찮게 var로 변수를 선언하는 것을 볼 수 있습니다. 근데 왜 var는 이제 쓰지 않는 추세입니다! 그 이유는 무엇일까요?
그리고 this 키워드를 도대체 어떤 걸 가리키고 있는 지 헷갈리는 데 정확하게 알아보고 공부하려 합니다!
[목차]
1. var, let, const의 차이점 및 예시
2. 다양한 상황 속에서 this가 향한 곳은?
var, let, const의 차이점 및 예시
1. 선언
var는 중복 선언이 가능해요.
var x = 10;
var x = 20;
console.log(x);
같은 x가 쓰였지만 덮여씌워져서 console에는 20으로 출력이 됩니다.
let x = 10;
let x = 20;
const y = 10;
const y = 20;
let과 const은 중복 선언이 불가해서 error가 발생합니다.
2. 스코프(scope) : 범위
var는 함수 스코프를 가지고 있어서 함수 내에서는 var로 선언된 변수에 접근할 수 있어요! 아래 예시를 보면
function example(){
if(true){
var x = 10;
}
console.log(x);
}
if문 안에서 var가 선언되었지만, 함수 안에서는 자유롭게 쓸 수 있어요.
하지만 let과 const는 block(블록) 스코프를 가지고 있어서 {} (중괄호) 안에서만 사용이 가능합니다! {} 밖에서 쓰인다면 error가 발생합니다.
function example(){
if(true){
let x = 10;
const y = 20;
}
console.log(x);
console.log(y);
}
3. 호이스팅(Hoisting) : 코드가 실행 전 선언이 된 변수가 상단으로 올라가 작동되는 것
var와 let, const는 다 호이스팅이 되긴 하지만 var는 최상단으로 끌어올려진 것처럼 행동합니다.
console.log(x);
var x = 10;
선언이 되기 전에 출력을 실행한다면 에러가 아니라 undefined 값으로 반환됩니다. 변수를 사용할 수는 있지만, 초기화가 되어있지 않기 때문에, undefined로 출력됩니다.
console.log(x);
let x = 10;
let과 const는 TDZ(Temporal Dead Zone)가 생성됩니다. 직역하자면 일시적 사각지대로, 변수선언과 초기화 사에 발생하는 것입니다. TDZ 사이에 변수에 접근하려고 하면 에러가 발생합니다. 그래서 위 예시는 ReferenceError가 일어납니다. 그래서 선언과 초기화가 동시에 이루어져야합니다.
이렇게 얘기를 들으면 var가 더 좋아보이고 왜 안쓰는 지 이해가 안가네요. 그 이유는!
1. 중복 선언은 코드의 가독성과 안정성을 낮춘다.
2. 함수 스코프만 지원하기 때문에 블록 스코프를 제대로 처리하지 못한다.
3. 호이스팅은 변수가 선언된 위치와 상관 없이 최상단으로 끌어올라가지만
초기화는 원래 위치에서 일어나기 때문에 undefined 같은 예상치 못하는 출력 결과가 나올 수 있다.
따라서 현대 js에서는 안전하고 예측 가능한 let과 const를 권장하고 있습니다.
다양한 상황 속에서 this가 향한 곳은?
this는 상황 속에서 다르게 동작하고 값 또한 방식에 따라 달라져서 많이 헷갈립니다.
그래서 상황 별로 가리키는 것을 정확하게 알아보려고 해요!
1) 전역 context에서
전역 context에서는 전역 객체를 가리킵니다! 즉, 어떤 세상을 가리키고 있는 지 알 수 있죠.
브라우저에서는 window를 출력하게 됩니다. Node.js 환경에서는 global이라는 이름을 가지고 있어, global를 출력하게 됩니다.
console.log(this);
2) 일반 함수 내
함수 내에서는 기본적으로 전역 객체인 세상을 가리키지만, 'use strict'(엄격 모드)에서는 자아를 잃어버립니다..ㅎ 그래서 undefined 값이 출력됩니다.
function normalFunction() {
console.log(this); // 전역 객체
}
function strictFunction() {
'use strict';
console.log(this); // 여기는 아무도 없어... (undefined)
}
3) 객체 메소드 내
객체 메소드 내에서는 객체 자신을 가리킵니다! 그래서 아래의 예시에서는 this는 study 객체를 가리키며 자기 자신의 name을 출력해야하므로 JavaScript를 출력하게 됩니다.
const study = {
name: 'JavaScript',
describe() {
console.log(this.name); // 'JavaScript'를 출력
}
};
4) 생성자 함수에서
여기서 new는 새로운 객체를 만들 때 쓰이는 생성자 함수입니다! 그래서 새로운 객체가 나타나게 된다면 this는 생성된 객체를 가리키게 됩니다. 따라서 return을 하지 않더라도 생성된 객체를 반환할 수 있습니다.
function Animal(type) {
this.type = type;
}
const pet = new Animal('Dog');
console.log(pet.type); // 'Dog'가 출력됨
새로 만들어진 객체에 type이라는 속성을 추가하고 , 그 값을 type으로 설정합니다.
그래서 new 키워드를 사용하여 Animal의 인스턴스를 만듭니다.
5) 이벤트 핸들러에서
이벤트 핸들러 안에서 this는 이벤트를 일으킨 요소를 가리킵니다! 이벤트 핸들러인 addEventListener에서 클릭 된 #actionButton을 가리키게 됩니다!
document.querySelector('#actionButton').addEventListener('click', function() {
console.log(this); // 클릭된 버튼을 가리킴
});
6) 화살표 함수에서
제가 가장 헷갈리는 this 스코프인데요. 다른 함수와 달리 자기만의 this를 갖지 않고, 함수가 정의된 환경의 this를 그대로 가져오는 상속 개념을 가지게 됩니다.
const module = {
name: 'JavaScript',
traditionalFunc() {
setTimeout(function() {
console.log(this.name); // undefined, 왜냐하면 전역 객체에서 찾음
}, 100);
},
arrowFunc() {
setTimeout(() => {
console.log(this.name); // 'JavaScript', 왜냐하면 부모 스코프인 module 객체의 this를 상속받음
}, 100);
}
};
module.traditionalFunc();
module.arrowFunc();
this가 전역 객체를 가리켜서 name을 찾지 못하게 된다면, 화살표 함수는 정의된 시점의 this를 상속받아 module 객체를 참조하게 됩니다!
var, let, const는 확실한 개념이 잡혔지만, 아직도 this는 많이 헷갈리는 개념입니다...
따라서 this의 내용은 코드잇 사이트에 나와있는 내용들을 참고하고 응용하여 작성하였습니다.
화살표 함수에서 this를 조금 더 많이 알아보고 정확하게 머리에 집어넣어야 할 것 같습니다. 앞으로도 웹을 향해서 열심히 해보아요!
'위클리페이퍼' 카테고리의 다른 글
React: 렌더링, Virtual DOM, Component (0) | 2024.08.25 |
---|---|
렉시컬 스코프(Lexical Scope): 코드 유효 범위 이해하기 (0) | 2024.08.18 |
브라우저(browser)가 어떻게 동작하는지 알아보자! (0) | 2024.08.11 |
Cascading 스타일 시트란? CSS의 계단식 적용 원리와 장점 (0) | 2024.08.03 |
개발자가 알아야 할 '시맨틱 태그'의 장점 (0) | 2024.08.03 |