JS 스터디 15장

magpies1221·2022년 7월 5일
0

JavaScript

목록 보기
14/24
post-thumbnail

블록레벨 스코프 (let, const)

var 키워드로 선언한 변수의 문제점

  • ES5까지 변수를 선언할 수 있는 유일한 방법은 var키워드를 사용

변수 중복 선언 허용

var x = 1;
var y = 1;

var x = 100;
var y;

console.log(x);
console.log(y);

// 결과
100
1
  • var 키워드로 선언한 변수를 중복 선언하면 초기화문의 유무에 따라 다르게 동작
  • x의 경우 초기화문으로 다시 중복 선언되면 JS engine에 의해 var 키워드가 없는 것 처럼 동작
  • y의 경우 초기화문이 아니므로 무시된다.
  • 에러가 발생하지 않기 때문에 의도치 않게 먼저 선언된 변수의 값이 변경되는 부작용 발생

함수 레벨 스코프

  • var 키워드로 선언한 변수는 오로지 함수의 코드 블록만을 지역 스코프로 인정
  • 따라서, 함수 외부에서 선언한 변수를 코드 블록 내에 다시 선언하면 그 변수 또한 전역 변수가 된다.
  • 함수 레벨 스코프는 전역변수를 남발할 가능성이 높다. 이로 인해 변수가 중복 선언되는 경우가 발생
var x = 1;

if (true) {
  var x = 3;
}

console.log(x);

for (var x = 0; x < 10; x++) {
  continue;
}

console.log(x);

// 결과 
3
10

변수 호이스팅

  • var 키워드로 변수를 선언하면 변수 호이스팅에 의해 변수 선언문 이전에 참조할 수 있다.
  • 할당문 이전에 참조하면 undefined를 반환
console.log(number);

number = 1

console.log(number);

var number;

// 결과
undefined
1

let 키워드

  • 위의 문제들을 보완하기 위해 ES6에서는 새로운 변수 선언 키워드인 let과 const를 도입

변수 중복 선언 금지

  • var 키워드로 이름이 동일한 변수를 중복 선언하면 아무런 에러가 발생하지 않지만, let 키워드로 중복 선언하면 문법 에러(Syntax Error)가 발생
var varValue = "old";
var varValue = "new";

let letValue = "old";
let letValue = "new";

// 결과
"SyntaxError: Identifier 'letValue' has already been declared"

블록 레벨 스코프

  • var 키워드로 선언한 변수는 함수 레벨 스코프
  • let 키워드로 선언한 변수는 코든 코드 블록(함수, if문, for문, while문 등)을 지역 스코프로 인정하는 블록 레벨 스코프를 따른다.
var valValue = "old";
let letValue = "old";

{
  var valValue = "new";
  let letValue = "new";
}

console.log(`valValue: ${valValue}`);
console.log(`letValue: ${letValue}`);

// 결과
"valValue: new"
"letValue: old"

변수 호이스팅

  • var 키워드로 선언한 변수와 달리 let 키워드로 선언한 변수는 변수 호이스팅이 발생하지 않는 것 처럼 동작
  • let 키워드로 선언한 변수를 변수 선언문 이전에 참조하면 참조 에러(Reference Error)가 발생
console.log(letValue);

let letValue;

// 결과
"ReferenceError: Cannot access 'letValue' before initialization"
  • var 키워드 변수는 런타임 이전에 JS Engine에 의해 "선언 단걔"와 "초기화 단계"가 한번에 진행
  • 선언단계에서 스코프(실행 컨텍스트의 렉시컬 환경)에 변수 식별자를 등록, 초기화 단걔애서 undefined로 변수 초기화
console.log(valValue);

var valValue;

// 결과
undefined

  • let 키워드로 선언한 변수는 "선언 단계"와 "초기화 단계"가 분리되어 진행된다.
  • 즉, 런타임 이전에 자바스크립트 엔진에 의해 선언 단계가 먼저 실행되지만 초기화 단계는 변수 선언문에 도달했을 때 실행된다.
  • let 키워드로 선언한 변수는 스코프의 시작 지점부터 초기화 단계 시작 지점까지 변수를 참조할 수 없다. 이 구간을 일시적 사각지대(TDZ, Temporal Dead Zone)라고 부른다.

  • 결국 let 키워드로 선언한 변수는 참조 에러를 반환하기 때문에 변수 호이스팅이 발생하지 않는 것처럼 보인다. 하지만 그렇지 않다.
let letValue = "old";

{
  console.log(letValue);
  let letValue = "new";
}

// 결과
"ReferenceError: Cannot access 'letValue' before initialization"
  • let 키워드로 선언한 변수가 호이스팅이 발생하지 않는다면 위 코드에서는 전역 변수의 letValue의 값인 old를 출력해야 한다.
  • 하지만, 호이스팅이 발생하기 때문에 지역 변수의 letValue의 식별자가 등록되어 참조 에러가 발생한다.
  • 자바스크립트는 ES6에서 도입된 let, const를 포함하여 모든 선언(var, let, const, function, class)을 호이스팅한다.
  • 단, ES6에서 도입된 let, const, class의 경우 호이스팅이 발생하지 않는 것처럼 동작한다.

전역 객체와 let

  • var 키워드로 선언한 전역 변수와 함수는 전역 객체 브라우저에서 window의 프로퍼티가 된다.
var valValue = "val";
function test() {}

console.log(window.valValue);
console.log(window.test);

// 결과
"val"
ƒ test() {}

window의 프로퍼티란?

  • window객체는 BOM(Browser Object Model)객체의 최상위 객체로서 웹페이지가 열려 있을때의 window창과 관련된 위치 및 크기와 관련된 프로퍼티와 메소드
  • 하지만, let 키워드로 선언한 전역 변수는 window의 프로퍼티가 아니다.
  • let 전역 변수는 보이지 않는 개념적인 블록(전역 레시컬 환경의 선언적 환경 레코드) 내에 존재하게 된다.
let letValue = "let";

console.log(window.letValue);

// 결과
undefined

const 키워드

  • const 키워드는 상수를 선언하기 위해 사용된다.

선언과 초기화

  • const 키워드로 선언한 변수는 반드시 선언과 동시에 초기화 해줘야 한다.
  • 초기화 해주지 않으면 문법 에러(Syntax Error)가 발생
const TAX_RATE;

// 결과
"SyntaxError: Missing initializer in const declaration"

재할당 금지

  • let 키워드로 선언한 변수는 재할당이 가능하다
  • const 키워드로 선언한 변수는 재할당이 불가능
let price = 1000;
price = 2000;

const TAX_RATE = 0.1;
TAX_RATE = 0.2;

// 결과
"TypeError: Assignment to constant variable."

상수

  • 상수는 상태 유지와 가독성, 유지보수의 편의를 위해 사용
  • 일반적으로 상수의 이름은 대문자로 선언
  • 여러 단어로 이루어진 경우 언더 스코어(_)로 구분
const TAX_RATE = 0.1;

let price = 3000;
price = price + (price * TAX_RATE);

const 키워드와 객체

  • const 키워드로 선언된 변수에 원시 값을 할당하면 값을 변경할 수 없다.
  • 하지만, const 키워드로 선언된 변수에 객체를 할당한 경우에는 값을 변경할 수 있다.
const product = {
  price: 1000
}

product.price = 3000;
console.log(product);

// 결과
{ price: 3000 }
  • const 키워드의 새로운 프로퍼티 동적 생성은 가능하다
profile
Web FrontEnd Developer

0개의 댓글