-
[Javascript] 호이스팅 Hoisting and 변수키워드 var, let, const (feat. 둘리)To infinity/Javascript 이론 2021. 6. 13. 12:30
20201.06.13 Ver1
1. 호이스팅
Javascript에는 다른 언어와 다른 특이한 기능이 있는데 바로 호이스팅이라는 것이다.
호이스팅은 선언문 전에 실행 컨텍스트 환경이 세팅되고 초기화가 진행되는 현상이다.
그래서 만약에 아래코드를 실행하면 아래와 같은 결과가 나온다.
let hoist = 1;
{
console.log(hoist); // access불가
let hoist = 2;
}
결과: 만약 호이스팅이 일어나지 않으면 지역스코프의 hoist 값인 1을 참조해서 1의 결과를 내야 하지만 해당 결과는 access할 수 없다고 뜬다. 즉, 호이스팅이 일어나서 해당 함수코드 내에 실행콘텍스트가 생긴 것이다.
즉, 자바스크립트에서 모든변수는 호이스팅이 발생한다.
2. 변수키워드 var, let, const 비교
[참고] ES6에 도입된 키워드: let, const, class
var let (ES6) const (ES6) For 변수선언 For 변수선언 For 상수선언 변수 중복선선 허용 변수 중복선언 불가 변수 중복선언 불가 재할당 가능 재할당 가능 재할당 금지 ('불변'을 의미하는 것은 아님) - - 변수에 원시값을 할당 한 경우 할당된 값을 변경할 수 없다. (상수=재할당이 금지된 변수)
하지만 변수에 객체를 할당 한 경웨 객체는 직접 변경이 가능하니까 재할당 없이도 값을 변경할 수 있다.함수 레벨 스코프
- Only 함수만이 지역스코프이다!블록 레벨 스코프 블록 레벨 스코프 호이스팅 발생
- 선언과 초기화가 한번에 진행됨호이스팅 발생
but 발생하지 않는 것 처럼 동작
- 선언과 초기화가 분리되어 진행
- 따라서 선언과 초기화 사이에 사각지대가 존재(TDZ Temporal Dead Zone)반드시 선언과 동시에 초기화 해야함
즉, const foo = 1;
만약 const foo; 로 선언하면 문법에러 남전역객체 window의 프로퍼티 전역객체의 프로퍼티 아님 전역객체의 프로퍼티 아님 렉시컬 환경 내
객체 환경 레코드렉시컬 환경 내
선언적 환경 레코드렉시컬 환경 내
선언적 환경 레코드[참고] 상수이름은 대문자로, 여러단어일 경우에는 언더스코어(_)를 이요해 스네이크 케이스로 표현.
결론! 변수 선언시에는 기본적으로 const를 사용하고 재할당이 필요한 경우 한정하여 let을 사용하자. 이때 변수 스코프는 최대한 좁게 만들자. 재할당이 필요할지 모르겠으면 일단 const를 쓰자!
3. 초기화?
const는 선언과 동시에 초기화해야한다고 하는데 여기서 궁금한게 생겼다.
1) let은 변수선언 시 초기화가 진행된다고 한다.
변수선언이란 let foo; 이 선언문을 작성하는 것을 의미한다.
그렇다면 const도 초기화를 한다고 하면, const foo;라고 치면 초기화되어야하는거 아닌가?
그런데 이렇게 하면 오류가 나고 const foo = 1; 이라고 꼭 값을 같이 할당해줘야한다.
응? 그렇다면 초기화라는 말은 무슨 의미지?
2) 그리고 console창에 var foo = 1; // undefined 가 뜬다.
나는 foo라는 변수에 1을 넣으라고 선언했으니까 당연히 결과가 1이 뜰 거라고 생각했다.
하지만 내가 foo변수를 선언해야 그제서야 1이라는 값이 나온다.
엥? 그렇다면 대체 var foo = 1; 은 무엇이란 말인가?
내가 변수 foo에다가 1이란 값을 넣겠다는 선언인가?
즉 var foo; 는 foo변수를 사용하겠다는 선언문이고
var foo = 1;이란 것은 내가 foo변수에 1을 넣겠다는 선언문인건가????
질문. const를 초기화 하려면 const foo = 1;로 써야한다고 하는데 let은 초기화하려면 let foo;만 적어도 되는데
그렇다면 초기화라는 것은 값을 할당하는 것인가? 대체 왜 const는 값을 할당하는데?!
아 알았어.
초기화라는 것은 초기값을 할당하는 것을 의미하는 거였다.
즉, let 키워드는 let foo;를 적으면 undefined로 초기값이 설정되지만, const함수는 undefined로 초기값을 설정하지 않기 때문에 초기값을 할당해서 초기화를 시켜줘야하는 것이었다!!!!!
자, 책 4장의 변수를 찾아보자.
var foo; // 변수 선언 -> 선언 시, 호이스팅이 발생하여 실행콘텍스트 생성 및 변수가 초기화 된다. 런타임 이전
foo = 1; // 값의 할당 -> 변수에 값을 할당한다. 런타임 이후
해당 표현은 한줄로 쓸 수도 있다.
var foo = 1; // 즉, 선언과 할당을 단축하여 표현하는 것이다. 자바스크립트는 호이스팅 때문에 한줄로 써도 본능적으로 변수를 먼저 선언하기 때문. 어, 여기서 또다른 의문 그렇다면 다른언어는 꼭 분리해서 표현해야 하나?
그나마 다룰 수 있는 언어인 파이썬으로 테스트를 해보자
파이썬에서 변수를 호출하면 (foo) // undefined라고 뜬다.
자바스크립트에서 var foo; // undefiend라고 똑같네? ㅇㅅㅇ???????????
원래 의도를 벗어났다. 변수 말고 다른 곳을 찾아가보자.
23장 실행컨텍스트부분을 다시 읽어본다.
아. 대박. 혹시 이런건가?
변수 foo를 선언하면 런타임 이전에 전역 코드 평가시점에 객체환경레코드에 바인딩 된 BindingObject를 통해 전역객체에 변수식별자를 키로 등록한다음(여기선 foo) 암묵적을 undefined를 바인딩 한다. 즉, foo = undefiend가 되는거임 (평가)
그러고 나서 런타임이 진행되면서 foo를 찾아서 값에 1을 할당해 주는거임.(실행)
실행컨텍스트 내에선 이미 foo = 1이라고 바인딩이 되어있지만 내가 foo를 부르지 않았잖아? 나는 변수 foo에 1을 넣을거야라고 애기한거지. 그래서 평가결과를 보여주는건거야. 그래서 undefined가 나오는거고?
아아아아아!
원래는 할당 시에 초기화가 이뤄지는게 원칙인데 자바스크립트는 특이하게 호이스팅이라는 개념이 있어서 할당 전에 초기화가 이뤄지는 건가보다!!
그래서 var는 선언시 암묵적으로 초기화되는거고, 그걸 보완하기 위해서 let 키워드를 만들어서 마치 호이스팅이 일어나지 않는 것 처럼 만들고 .... 음? 그러면 왜 변수선언 시 undefined가 되도록 만든거지?
아니면 혹시 const는 상수를 선언하기 위한 키워드여서 let과 동작방식이 다른건가? 재할당을 가능하게 하기 위해서 그런가? 아 왠지 그런가봄. const는 한번 선언하면 값의 변경이 불가하니까 선언만 할 순 없고 선언하면서 할당까지 같이 해야하는거고 let은 재할당이 가능하니까 키워드만 선언해도 방을 내주는거지.
아아아!!! 대박 이거네.
선언 할 때, 메모리 공간에 변수이름표가 맵핑되잖아. 근데 const는 재할당이 금지된 키워드니까 방이 한번 정해지고 거기 누가들어갈지까지가 정해져야하는거야. 그래서 할당까지 한꺼번에 해야하는거고, let은 재할당이 가능하니까 일단 방부터 만들어 놓고 누가 들어올지는 나중에 정해도 되는거지. 아 대박 이거네.
즉, const는 재할당이 금지된 상수개념이니까 처음부터 누구를 할당할지 정해줘야 하는거고
let은 재할당이 가능하니까 처음부터 할당문까지 같이 쓸 필욘 없는거지.
옥케이~
아, 근데 왜 undefined가 나오는지가 궁금한거 아니었어? ㅇㅅㅇ.. 아 그렇네.
왜 const는 할당까지 하는지가 궁금했던거였는데 그게 해결됐으니 위의 문제는 차차 읽어가며 해결하도록 하자.
->위에 주황색으로 표시!
[참고] 변수는 선언, 함수는 정의라고 표현함.
'To infinity > Javascript 이론' 카테고리의 다른 글
[Javascript] 함수 (0) 2021.06.14 [Javascript] 함수 호출방식과 this 바인딩 (related to 생성자 함수) (0) 2021.06.14 [Javascript] 프로퍼티 어트리뷰트 (프로퍼티 상세속성 바꾸기) (0) 2021.06.13 [Javascript] 실행컨텍스트 flow (코드실행 시 일어나는 과정) (0) 2021.06.12 [Javascript] 스코프 scope (유효범위) (0) 2021.06.10