⛏️
공부방
  • README.md
  • 프로젝트
    • ft_transcendence
      • 설계
        • 0. 프론트 디자인
        • 1. BackboneJS 뷰 객체
        • 2. API 설계
        • 3. 레일즈 라우팅 구현
        • 4. DB 설계
        • 5. 채널 설계
    • slab-saver
    • react-payment
  • 공부
    • HTML, CSS
      • GRID
      • emmet
      • position
      • CSS Unit
        • 단위 정리
        • 기준을 정해보자
        • em의 정확한 기준은 뭐야?
      • flex
      • NAVBAR 실습
      • 유튜브 화면 만들어보기
    • SQL
      • 이론
        • 1강 데이터베이스
        • 2강 다양한 데이터 베이스
        • 3강 데이터베이스 서버
      • 명령어
        • DB 관리
        • TABLE 관리
        • Constraints
        • SQL 명령어 - 1
        • SQL 명령어 - 2
        • SQL 명령어 - 3
        • SQL 명령어 - 4
        • SQL 명령어 - 5
    • Ruby
      • 루비 객체와 클래스
      • 곡괭이
        • Chapter2. Ruby.new
        • Chapter3. 클래스, 객체, 변수
        • Chapter4. 컨테이너, 블록, 반복자
        • Chapter5. 기능 공유하기
        • Chapter6. 표준 타입
        • Chapter8. 메서드 파헤치기
    • Python
      • 유용한 링크
    • RubyOnRails
      • 아직 정리하지 못한 것들
        • RSPEC 을 이용한 테스트 완전 자동화
        • 레일즈 이니셜라이징 과정
        • 액션케이블 구체적으로 정리하기
        • 웹팩으로 자바스크립트 모듈 관리하기
      • ACTIVE JOB
        • 액티브잡의 기본
        • 실전! 액티브 잡을 이용한 스케쥴링
        • 서버를 껏다 키면 스케쥴링 된 이벤트가 사라진다!
      • ACTION CABLE
        • 액션케이블 Consumer를 이용해서 문제 해결
        • 액션케이블 연결 순서
      • ACTIVE STORAGE
      • 모델
        • validation
          • seeds 데이터 validation 스킵
          • validation 검사가 save, update, create 모든 경우에 일어난다
          • validator 클래스
          • 커스텀Validation
          • validates format(정규표현식)
        • 액티브레코드 find의 다양한 활용
        • 한 레코드에 동시 접속 막자!! with_lock
        • 레일즈 where 사용법
        • 레일즈에서 모델 관련 이슈
        • 모델이름바꿀때명심할것
        • 모델의 includes 메서드
        • 연관 모델을 다른 이름으로 설정하고 가져오기
      • 기본 상식
        • form으로 전달되는 params를 분석해보자
        • StrongParameter 쿼리 배열 받기
        • view helper로 디버깅 하는 방법
        • css 파일을 수정했는데 적용이 안된다?
        • StrongParameter 일반데이터와 객체 데이터 한번에 받기
        • wrap-parameter body가 두 번씩 날라오는 이유
        • 컬렉션 map에서 요소 스킵하는법
        • CASE를 이용해서 정렬(일반적인 정렬 X)
        • 문자열(정규표현식)
        • TIME ZONE 설정하기
        • 커스텀exception
      • RSPEC으로 모델 테스트하기
      • 한 눈에 읽는 루비 온 레일즈
      • Perfect RubyOnRails
        • Chapter1. 소개
        • Chapter2. RubyOnRails 기본
        • Chapter3. 스캐폴딩
        • Chapter7. 라우팅
        • Chapter8. 테스트
    • Javascript
      • var, let, const 차이
      • 브라우저 동작 원리
      • 디바운싱과 쓰로틀링
      • Tagged Template Literal(styled-components)
      • IntersectionObserver 를 사용해서 스크롤 이벤트의 부하 줄여주기
      • EVENT LOOP
        • 자바스크립트에서 어떻게 비동기적인 실행이 가능한걸까?
        • 이벤트 루프의 동작
        • setTimeout이 실행되면 어떤 동작이 일어날까?
        • 블록은 실행이 보장된다
        • 콜스택에 있는 블록이 보장된다는 점을 이용해서 브라우저 죽이기
        • setTimeout 무한반복으로 브라우저는 죽을까?
        • Promise 무한반복으로는 브라우저를 죽일 수 있을까?
        • RAF는 그럼 뭐야?
      • forEach는 반복도중 멈출 방법이 throw 밖에 없다!
      • 임시
        • 정리할 것 목록
          • 자바스크립트 기본 문법
        • 이벤트 임시 정리
      • 유용한 링크
      • arrow function 을 이용한 bind 이슈 해결
      • preventDefault - passive
      • CRITICAL-RENDERING-PATH
      • setInterval에 클로져 개념 사용하기
      • 오디오 문제 이슈
      • 자바스크립트의 식과 문
        • 식과 문이란 무엇인가...
        • 식
          • 1. 기본값과 래퍼객체
          • 2. 참조값과 가비지컬렉팅
        • 식을 조금 더 자세히 알아보자
      • prototype, [[Prototype]] 차이
      • export, import 학습
      • ESlint
      • 아주아주기본
        • Chatper1. 기본
        • Chapter2. 타입
        • Chapter3. 연산자
        • Chapter4. 제어문
        • Chapter5. 배열
        • Chapter6. 함수
        • Chapter7-1. 객체
        • Chapter7-2. 객체
        • Chapter8. 표준객체
        • Chapter9. DOM
      • 이벤트 위임
      • 이벤트가 버블링 되서 root 까지 가다보면... 부모의 부모의 ... 모든 click 이벤트를 발동시키는거 아니야?
      • classList
    • BackboneJS
      • Backbone Model 프로토타입에 메서드 구현하기
      • BackboneJS의 각 요소의 역할과 책임을 확실히 이해하자
      • Window 이벤트를 listenTo로 감시하기
      • 뷰 자신이 자신을 지워야 할 때를 감지하려면 어떻게 해야하는가?
      • 백본 VIEW의 remove와 jquery의 remove 는 다르다!
      • 백본 컬렉션 URL에 쿼리 붙이기
      • index.html.erb와 BackboneJS의 결합
      • 백본 모델과 컬렉션에서 fetch 를 통해 JSON 가져오기!
      • 모델은 urlRoot, 컬렉션은 url
      • ISSUE
      • Absolute Beginner
        • Part1
        • Part2
        • Part3
        • Part4
    • 문제풀이
      • 01. 유효한 팰린드롬(leetcode: 125)
      • 02. 문자열 뒤집기(leetcode: 344)
      • 03. 로그파일 재정렬(leetcode 937)
      • 04. 가장 흔한 단어(leetcode: 819)
      • 05. 그룹 애너그램(leetcode: 49)
      • 06. 가장 긴 팰린드롬 문자열(leetcode: 5)
      • 07. 두 수의 합(leetcode: 1)
      • 08. 빗물 트래핑
      • 09. 세 수의 합(leetcode: 15)
    • BlackCoffeeStudy
      • level1
        • 1주차
    • express
      • Untitled
      • 구글 애널리틱스 연결하기
      • passport를 활용한 로그인
      • express-init 명령어 사용
      • ec2와 DBeaver
      • mariadb 설치
      • sequelize 설치 및 사용법
        • sequelize 설치
        • sequelize-cli 사용법
        • 모델 간 연관관계 맺기
        • Hook 사용하기
      • express-ejs-layout 활용하기
      • Bootstrap
      • npm install로 설치한 모듈 ejs에서 사용하기
      • 미들웨어
    • cypress
      • window.alert 테스트는 어떻게 하지?
      • 상수를 어디에 저장할건가?
      • before()와 beforeEach()
    • aws
      • aws로 프로젝트를 배포해보자!
      • nginx로 리버스프록시 서버를 만들자
      • github actions 로 푸쉬되면 자동으로 업데이트 하는 기능 만들어보기
    • react
      • Drag & Drop 를 이용해서 리스트 요소 순서 바꾸기
      • CRA에서 CRACO 사용하지 않고 절대경로 import(NODE_PATH)
      • useEffect내에서 state의 dependency 문제
      • IntersectionObserverAPI로 무한스크롤 구현
      • react-testing-library
        • 기본
        • react-router-dom 에서의 에러
        • event 발생시키기
        • Integration testing하기
        • async하게 렌더링 되는 요소 잡기
        • Mocking 하기
      • CRA로 만든 앱에서 절대경로로 import 해오기(alias하기)
      • 커스텀 훅 만들기
    • 타입스크립트
      • 조건부타입 (Conditional types)
      • Generics
      • Keyof 타입 오퍼레이터
      • Indexed Access Types
      • 타입 챌린지
        • easy
          • 00. Awaited
          • 01. Concat
          • 02. Exclude
          • 03. First Of Array
          • 04. If
          • 05. Includes
          • 06. Pick
          • 07. Readonly
          • 08. Length
          • 09. Tuple to Object
        • mediun
          • 01. Absolute
    • Firebase
      • 파이어스토어 규칙
    • 기타
      • 협업 프로세스
      • UUID
      • 구글애널리틱스 설치하기
      • 드림코딩 강의
        • 포트폴리오
          • CSS
            • nth-child
            • CSS 팁
          • 자바스크립트
            • 1. 스크롤에 따른 navbar 의 색 변경하기
            • 2. navbar 버튼을 누르면 해당 페이지로 스크롤링 되게 만들자
            • 3. 스크롤 다운 하면 arrow-up 버튼 나오게 하기
            • 4. project 필터링 구현
            • 5. project 필터링에 transition 효과 넣기
      • GIT
        • 기본 사용법 정리
        • git remote update - remote 브랜치 가져오기
  • 기타
    • 이것저것
      • 독서
        • 클린코드
          • Chapter0. 나는 왜 클린코드 책을 읽는가?
          • Chapter1. 클린코드
          • Chapter2. 의미있는 이름
          • Chapter3. 함수
          • Chapter4. 주석
          • Chapter5. 형식 맞추기
      • 용어
      • IDE
        • RubyMine
          • 실전이 중요!
          • 1. Editor Basic
          • 2. Navigation
          • 3. Completion
          • 4. Refactoring
          • 5. Code Assistance
      • MAC에서 살아남기
        • Alfred - Spotlight 업그레이드
        • Vimium
        • BetterTouchTool - 트랙패드
        • 구름 입력기 - ESC, `
        • Spectacle - 화면 분할
    • 원티드 프리온보딩
      • 1주차
        • 월요일
        • 목요일
      • 2주차
      • 3주차
      • 4주차
      • 5주차
      • 6주차
    • 일기장
      • 2020
        • December
          • 20201208(화)
          • 20201209(수)
          • 20201210(목)
          • 20201211(금)
          • 20201214(월)
          • 20201215(화)
          • 20201216(수)
          • 20201217(목)
          • 20201218(금)
          • 20201219(토)
          • 20201221(월)
          • 20201222(화)
          • 20201223(수)
          • 20201224(목)
          • 20201226(토)
          • 20201228(월)
          • 20201229(화)
          • 20201230(수)
          • 20201231(목)
      • 2021
        • January
          • 20210101(금)
          • 20210102(토)
          • 20210105(화)
          • 20210106(수)
          • 20210107(목)
          • 20210108(금)
          • 20210109(토)
          • 20210112(화)
          • 20210113(수)
          • 20210114(목)
          • 20210115(금)
          • 20210117(일)
          • 20210118(월)
          • 20210119(화)
          • 20210120(수)
          • 20210121(목)
          • 20210125(월)
          • 20210126(화)
          • 20210127(수)
          • 20210128(목)
          • 20210129(금)
        • February
          • 20210201(월)
          • 20210202(화)
          • 20210203(수)
          • 20210204(목)
          • 20210205(금)
          • 20210207(일)
          • 20210208(월)
          • 20210209(화)
          • 20210217(수)
          • 20210218(목)
          • 20210219(금)
          • 20210220(토)
          • 20210222(월)
          • 20210223(화)
          • 20210224(수)
          • 20210226(금)
          • 20210228(일)
        • March
          • 20210302(화)
          • 20210303(수)
          • 20210304(목)
          • 20210305(금)
          • 20210306(토)
          • 20210308(월)
          • 20210309(화)
          • 20210310(수)
          • 20210311(목)
          • 20210312(금)
          • 20210313(토)
          • 20210315(월)
          • 20210316(화)
          • 20210317(수)
          • 20210318(목)
          • 20210319(금)
          • 20210322(월)
          • 20210323(화)
          • 20210324(수)
          • 20210325(목)
          • 20210327(토)
          • 20210329(월)
          • 20210330(화)
          • 20210331(수)
        • April
          • 20210406(화)
          • 20210407(수)
          • 20210408(목)
          • 20210409(금)
          • 20210410(토)
          • 20210412(월)
          • 20210413(화)
          • 20210414(수)
          • 20210415(목)
          • 20210416(금)
          • 20210417(토)
          • 20210419(월)
          • 20210420(화)
          • 20210421(수)
          • 20210422(목)
        • July
          • 20210728(수)
Powered by GitBook
On this page
  • var 에 대해 알아보자
  • 변수 선언 및 초기화
  • 스코프
  • 이제 var와 let, const 의 차이점을 알아보자.
  • 1. 중복선언
  • 2. 재할당
  • 3. 스코프
  • 4. 호이스팅
  • 5. 전역객체 프로퍼티 여부

Was this helpful?

  1. 공부
  2. Javascript

var, let, const 차이

PreviousJavascriptNext브라우저 동작 원리

Last updated 3 years ago

Was this helpful?

var 에 대해 알아보자

자바스크립트를 처음 사용할 때 부터 var 의 존재는 익히 들어 알고있었지만, 사용해본적은 없었다. 이참에 알아보자.

변수 선언 및 초기화

자바스크립트에서 변수 선언은 선언 + 초기화 로 이루어진다. 간단히 말해보자면

  • 선언: 자바스크립트엥게 변수의 존재를 알린다.

  • 초기화: 확보된 메모리 공간에 값을 넣는다. 만약 값이 없다면 undefined 가 된다.

여기까지는 다른 언어와 동일하지만, 자바스크립트에는 호이스팅 이라는 괴상한게 존재한다.

console.log(name);  // undefined
var name = 'sanam';
console.log(name); // sanam

위와같은 코드가 있다면 분명 에러가 나야하겠지만, 자바스크립트에서는 undefined 가 출력될 뿐이다. 왜 그럴까? 왜냐하면 자바스크립트의 호이스팅 은 코드 실행 이전에 모든 선언문(변수 선언문, 함수 선언문 등..)등을 찾아내서 먼저 실행하기 때문이다. 따라서 변수 선언이 어디에 있던 상관없이 다른 코드보다 먼저 실행되게 된다.

var, let, const, function, class 등 의 키워드로 선언된 모든 식별자들은 호이스팅 된다. 선언 만 먼저 되고 할당은 런타임에서 이루어진다.

위의 코드를 분석해보면 아래와 같다.

var name;                // 선언문은 호이시팅 되서 위로 올라옴. 단 아직 할당은 되지 않음.
consoel.log(name)        // undefined
name = 'sanam';          // 할당
consoel.log(name)        // sanam

궁금증

함수선언문과 함수표현식에 대해 학습하자.

위에서 변수 선언문과 함수 선언문이 호이스팅이 되어서 맨 위에 오게된다는걸 알게되었다. 그런데 아래 코드에서 왜 함수는 선언 이전에 잘 실행이 되는데 var 로 선언한 변수는 undefined 가 될까?

func() // '이건 잘 된다'
console.log(value) // undefined

var value = 10;
function func() {
    console.log('이건 잘 된다');
}

그 이유는 함수 function func() { ..code .. } 자체가 함수선언문이기 때문이다. 따라서 위의 코드를 자바스크립트가 되어서 생각해본다면 아래처럼 될 것이다.

var value;
function func() {
    console.log('이건 잘 된다');
}
func();
console.log(value);
value = 10;

스코프

스코프는 식별자들의 유효범위를 의미한다. 선언된 위치에 따라 유효범위가 달라진다.

전역 변수는 어디에서든지 참조가 가능하다. 지역변수의 유효범위는 현재 자신의 스코프와 그 하위 스코프에서 유효하다. C 언어와 C++ 를 생각해보면 각 변수는 블록레벨에 스코프였다. 하지만 var 는 블록레벨이 아닌 함수레벨스코프 다. 아래의 예시를 보자.

for (var i = 10; i < 10; I++);
console.log(i);    // 10

다른 언어 같았으면 i 의 출력 결과는 not defined 같이 나와야겠지만, 자바스키립트는 함수레벨스코프 를 따르고 for 반복문은 함수레벨이 아니기 때문엔 var의 유효범위가 같게 되어서 10이 출력된다.

아래의 경우는 변수 a 는 test 라는 함수범위 안에서 유효하므로 에러가 발생한다.

console.log(a);
function test() {
    var a = 10;
}

이제 var와 let, const 의 차이점을 알아보자.

크게 5가지 차이점이 존재한다.

  1. 중복선언 가능 여부

  2. 재할당 가능 여부

  3. 변수 스코프 유효범위

  4. 변수 호이스팅 방식

  5. 전역객체 프로퍼티 여부

1. 중복선언

var 는 중복선언이 가능하다.

// NOTE: 선언 및 초기화
var name = 'sanam';
console.log(name); // sanam

// NOTE: 선언 및 초기화
var name = 'nam';
console.log(name);  // nam

// NOTE: 선언
var name;
console.log(name); // nam

var 로 선언한 변수는 중복해서 선언 및 초기화가 가능하다. 만약 초기화를 하지 않고 선언 만 할 경우 마지막에 할당된 값이 변수에 저장된다. 아래의 문제를 풀어보자. 각 console.log 에는 어떤 값이 찍힐까?

function quiz(x) {
    console.log(x);

    var x;
    console.log(x);

    var x = 2;
    console.log(x);
}
quiz(1);

정답은 .... 1 1 2다! 이유를 생각해보면.... 1. quiz 라는 함수의 인자 x 에 1을 넣었다. 2. 첫번쨰 로그에서는 인자로 들어온 1이 출력된다. 3. var x 로 변수를 선언했다. 선언만 하고 초기화는 하지 않았으므로 인자로 이전의 값인 1이 들어온다. 4. 두번째 출력도 1이 된다. 5. var x = 2 로 선언 및 초기화가 이루어졌다. 따라서 값이 변했으므로 출력 또한 2로 변하게 된다.

이 경우에 let x 를 하면 당연히 안된다!

let, const 는 중복선언이 불가능하다.

const test1 = 10;
const test1 = 10; // Identifier 'test1' has already been declared

let test2 = 10;
let test2 = 10; // Identifier 'test2' has already been declared

중복선언이 불가능하다.

2. 재할당

var와 let은 재할당이 가능하다. const 는 그러면?

const 는 재할당이 불가능하다.

재할당이 불가능하다. 재할당이 불가능하다는 말을 풀어 말하면 선언과 동시에 할당이 되지 않으면 에러가 발생한다는 것. 따라서 초기값을 항상줘야한다.

const test;    // Uncaught SyntaxError: Missing initializer in const declaration

만약 재할당을 하게 되면 에러가 발생한다.

const name = 'sanam';
name = 'nam'; // Uncaught TypeError: Assignment to constant variable.

3. 스코프

앞서 var는 함수레벨스코프 를 따른다고 했다. let과 const 는 블록레벨 스코프를 따른다!

블록레벨 스코프는 함수 내부, if문, for 문 그리고 단순한 코드 블럭 { } 에서 선언된 변수를 지역변수로 취급한다.

const name = 'sanam';

if (true) {
    const name = 'if';
    console.log(name);    // if
}

for(i = 0;i < 1;i++) {
    const name = 'for';
    console.log(name);    // for
}

{
    const name = 'block';
    console.log(name);    // block
}

{
     console.log(name);    // sanam
}

마지막 블록 출력값은 `sanam` 으로, 블록밖의 변수가 참조되었다. 왜? 본인의 스코프에서 찾지 못하면 상위의 스코프에 있는 값을 찾아오기 때문이다.

4. 호이스팅

var 을 이야기할 때 자바스크립트는 선언문을 대상으로 호이스팅을 한다고 이야기했다. var변수선언의 호이스팅으로 인해 선언문 자체만 위로 끌어올려진다. 그리고 undefined 값이 할당이 된다. 따라서 변수의 값을 넣어 주기 전까지는 해당 변수는 undefined 의 값을 갖게된다. 그러면 let 도 var 처럼 재할당이 가능한 키워드니깐, 호이스팅이 되어서 초기화를 해주기 전까지는 undefined 가 되겠군!! 이라고 생각하면 큰 오산이다!!!

var와 let, const 의 호이스팅은 다른 방식으로 이루어진다.

TDZ (Temporal Dead Zone): 변수의 선언(호이스팅) 과 초기화 사이에 존재하는 일시적으로 변수 값을 참조할 수 없는 구간

이전의 추측대로 let 을 사용해보자. var 와는 다르게 초기화를 하기 전에는 접근할 수 없다는 에러 메시지가 나온다.

console.log(a);    // Uncaught ReferenceError: Cannot access 'a' before initialization
let a;

도대체 let 과 const 는 어떻게 생겨먹었길래 var 와 다르게 호이스팅이 될까? 간단하다. var 는 호이스팅이 되고 undefined 값이 세팅이 되지만 let과 const 는 초기화과정이 없는 것이다.

즉, 변수의 선언(호이스팅) 과 초기화 사이에 일시적으로 변수 값을 참조할 수 없는 구간이 생기는 것. 이 구간을 TDZ(Temporal Dead Zone) 이라고 한다.

TDZ를 어떻게 확인할 수 있을까?

간단한 예시를 들어보자.

let test = 10;
{
    console.log(test);    // Uncaught ReferenceError: Cannot access 'a' before initialization
    let test = 20; 
}

만약 아래의 let test = 20 라인이 없다면 콘솔로그는 10 이 나와야한다.. 하지만 초기화전에는 접근할 수 없다는 에러메시지가 나온다. 왜? 왜냐면 블록스코프에 존재하는 test 라는 변수가 호이스팅 되서 위에서 선언되었기 때문이다. 따라서 상위 스코프에 있는 test 가 무시되고 하위 스코프의 test 를 참조하게 되는데, 로그 이후에 초기화가 되므로 이런 에러가 나오는 것.

TDZ를 조금 더 살펴보자.

아래의 예시는 잘 동작한다. func 함수에서 사용되는 letVar 변수가 함수표현식 이후에 선언 및 초기화 되고 있지만, 선언 자체는 호이스팅으로 문제 없이 되고, 함수의 호출은 letVar의 TDZ 이후에 일어나기 때문이다!

// letVar TDZ starts
const func = () => console.log(letVar);

let letVar = 3;
// letVar TDZ ends
func();

아래의 코드에서는 왜 에러가 발생했을까? 그리고 어떻게 if 문 안으로 들어간 걸까?

  • if의 foo는 var foo 다. 따라서 if 블록 안으로 들어가게 된다.

  • 블록스코프에서 foo 가 선언되었다. 따라서 상위 스코프의 foo 는 무시되고 블록에서 선언된 foo 를 사용하게된다.

  • 여기서 문제가 발생한다. 지금 foo 는 선언및 초기화 과정에서 자기 자신의 값을 사용하려고한다. 하지만 우리는 실행 순서가 무엇인지 알고 있다. 할당 연산자를 사용할 때는 2번째 항이 먼저 계산된다. 즉 foo 는 초기화를 하기도 전에 자기 자신을 참조하고 있는것. 따라서 에러가 발생함

function test(){
   var foo = 33;
   if(foo) {
      let foo = (foo + 55); // ReferenceError
   }
}
test();

5. 전역객체 프로퍼티 여부

var 로 선언된 변수는 window 의 프로퍼티가 된다.

var name = 'sanam`;
console.log(window.name);

let, const 로 선언된 변수는 전역객체의 프로퍼티가 되지 않는다.

let name = 'sanam`;
console.log(window.name);    // undefined

MDN을 보자
[자바스크립트] 변수 선언 방식 차이: var / let / const카레유
참고 블로그
var - JavaScript | MDN
var와 호이스팅
let - JavaScript | MDN
let 과 TDZ
Logo
Logo
Logo