오늘 적어볼 것은 할 수 있을지는 모르겠지만
Hoisting, Scope, var let const에 관한 것이다.
ES6(2015)이 나오기 전의 JS는 모든 변수를 선언할때
var
를 사용했다.
그러나 ES6이 나온 후let
과const
가 추가되면서var
를 사용하지말라!
라고 이야기를 할 정도로 골치덩이가 되버렸다.
그렇다면 여기서 생각을 해야하는 것은 바로 응 안쓰면 그만이야~~~ 보다는
왜 쓰면 안되고, 어떤 차이가 있는지 알아보는 것이라고 생각한다.
값 재할당 | 재선언 | |
---|---|---|
var | 가능 | 가능 |
let | 가능 | 불가능 |
const | 불가능 | 불가능 |
위의 표를 코드로 적어보면
var a = 10; var a = 20;
위처럼 적을 경우 var a 는 20이 된다.
값도 바꿀 수 있고 a를 또 다시 선언을 할 수 있다
let a = 10; a = 20;
위처럼 적을 경우 let a 는 20이 된다.
하지만 위의 var처럼 let a = 10; let a = 20;을 적을 경우
SyntaxError: Identifier 'a' has already been declared.
문법에러, 식별자 a는 이미 선언되었습니다. 라는 에러코드를 받게 되고
const a = 5; a = 10;
위처럼 적을 경우 TypeError: Assignment to constant variable.
타입 에러, 상수 변수에 할당하였습니다. 라며 에러코드를 받게 되고
const a = 5; const a = 10;
이라고 적을 경우엔 let에서 재할당을 했던 것처럼
SyntaxError: Identifier 'a' has already been declared.
라는 에러코드를 받게 된다.
그래서 보통은 let은 변수, const의 경우에는 상수(변하지않는)라고 표현을 한다.
어려운 표현으로는 값을 재할당을 받을 수 있다고 하여
돌연변이를 뜻하는 Mutable let
재할당을 받지 못해 부정형을 붙여 Immutable const
라고 표현하는 경우 또한 존재한다.
값을 변경시켜버리고, 선언했던 것을 새로 선언한다는 것이 큰 문제였을까?
라고 생각을 해보면 사실 프로그래밍을 공부하면서 코드가 짧을 때는 상관없지만
조금만 길어져도 툭하면 바꾸고 고치는 경우를 볼 수 있을텐데
프로그래밍 특성상 한명이 작업하는 것이 아닌 많은 인원이 한번에 작업을 했기에 엄청나게 큰 문제가 생겼을 것이고, 그것 때문에 새로운 규칙을 적용했을 것이라고 생각한다.
그렇다면 이제 Scope
에 대해서 알아볼 수 있는 기본적인 준비가 됐다.
Scope는 범위라는 사전적 뜻을 가지고 있으며, Javascript가 아닌 그 외의 프로그래밍 언어에서도 사용을 하고 있다.
프로그래밍 언어에서의 Scope는 식별자가 접근할 수 있는 범위를 의미하고 있다.
코드의 가장 밖의 Scope를 Global Scope(전역 스코프)
라고 부르며
그 외의 Scope를 Local Scope(지역 스코프)
라고 부른다.
중요한 규칙들이 몇가지가 존재하는데
1. 밖의 범위(스코프)에서 선언하는 것은 안의 범위(스코프)에서 사용이 가능하나, 밖은 불가능하다.
2. 함수 속에 함수, 그 속에 함수같이 스코프는 중첩이 가능하다. (사각형을 그리고 그 속에 또 그려넣고)
조금 더 쉽게 이해하려면 평소에 자주 쓰던 말인
최상단에 선언하여 모든 곳에서 사용할 수 있는 전역 변수와
특정 함수, 혹은 조건문 속에 넣어서 사용하는 지역 변수를 생각해보면 이해를 하는데 더 도움이 될 것이라고 생각한다.
그리고 이 Scope는 블록과 함수
에 의해 한번 또 나눠질 수 있는데
이것을 블록 스코프, 함수 스코프
라는 명칭으로도 사용한다.
함수 스코프는 말 그대로 함수 속에서 사용하는 것을 이야기하고
블록 스코프는 중괄호 {} 속에서 사용하는 것을 이야기한다.
함수 스코프는 const, let, var 모두 사용이 불가능하지만,
블록 스코프에서는 조금 다른 것이 존재한다.
아래 코드를 보면 if문 속에 var, let, const를 선언하고 그 밖에서 값들을 호출을 한 것이다.
중괄호로 구성이 되어있는 if문의 경우에는 블록 스코프임에도 불구하고
var의 값은 밖에서 호출이 가능한 것이다.
그렇다는 의미는 var로 선언된 변수는 전역 스코프(전역변수)가 되어 어디서든 사용이 가능하다는 것을 의미한다.
이러한 문제가 있었기에 ES6에서 let과 const라는 새로운 변수와 상수가 생겼으며,
최근에 올라오는 강의들에서는 절!대!로! var을 쓰지말라고 경고를 수없이 많이 한다
이유는 코드가 꼬일 수 있다는 것도 있지만,
전역변수라는 것이 존재하면 언제나 메모리를 할당하고 있기 때문에 프로그램이 무거워질 수 있어서
var를 안쓰는 것도 물론이거니와 전역변수 자체를 선언하지 않는 것이 좋다고 이야기한다.
호이스팅이란?
mdn에 적혀있는 내용으로는 변수와 함수의 메모리 공간을 선언(특정 값을 넣기)전에 미리할당하는 것을 의미한다고 적혀있다.
이 말이 무슨 말인가하면
변수, 또는 함수는 특정 메모리 공간을 할당받아 그곳에서 빼서 사용을 하는 것인데
변수,함수를 생성한 것 자체로 계속 코드 내부를 떠돌고 있다고 보면 될 것 같다.
그래서 MDN에 올라와있는 코드 일부를 가져와봤다. > 이것을 누르면 해당 문서로 이동합니다 <
분명 JS는 폭포수(캐스캐이딩)언어이기 때문에 위에서 아래로 내려오면서 실행되는 것이 일반적이라
함수를 생성하고 나서야지만 선언을 했을 때 불러올 수 있을 것이라 생각했지만?
미리 메모리 공간에 할당을 받기에 역순으로 실행을 하더라도 함수가 작동하는 것을 볼 수 있다
또한 변수에서는 어떤 것이 있냐면 바로 계속 문제라고 이야기하는 var
가 또 문제를 일으킨다.
5라는 값이 a라는 선언을 하기 전에 콘솔로 찍었을 때, undefined (존재하지만 값이 부여되지않음) 이라는 것이 뜬다.
그렇다면 let의 경우에는 어떻게 나오는지 확인을 해보자.
a라는 것이 존재하지 않는다는 레퍼런스 에러를 뱉게 된다.
이것은 위에 스코프를 설명할 때도 나왔던 이야기와 동일한데
함수 스코프(함수 속의 공간)이 아닌 곳에서 선언되는var
는 전역 스코프(전역 변수) 속성을 가지고 있고
값을 선언하지 않더라도 언제나 메모리의 공간을 낭비하는 불필요한 코드가 된다는 것을 알 수 있다.
MDN문서 상에는 let과 const가 생겨나기 이전 ES6에는 호이스팅이라는 것이 이런 맥락이 아니였다고 하는데
개선을 하기 위해서 let과 const가 나오고 정말 쓰지말라고 한번 더 경고해주는게 아닌가~ 라는 생각도 든다.
적어가면서 무슨 생각을 했냐면
함수 또한 선언을 하기 전부터 메모리값을 할당받고 있다. 라고 이야기를 하고 있는데
그래서 모듈이라는 것이 구성된 것이 아닌가 하는 의문이 문득 들었다.
이것에 대한 내용을 적어보고 싶긴 한데... 할게 너무 많아서 당장은 쓰기 힘들 것 같고
내일 멘토님한테 여쭤나봐야겠다 ㅎㅎ;
끗