[ES6] ECMA Script 6 part1

Lee Dong Hyeon·2022년 7월 4일
0

[ES6]ESCMA Script 6

목록 보기
1/1

변수선언 키워드 let, const

등장배경

기존의 javascript는 var 키워드로 변수를 선언하였다.
var 키워드로 선언된 변수들은 아래와 같은 특정이 있다.

var 키워드 특징

1. 함수레벨 스코프

  • 함수의 코드 블록만을 스코프로 인정하기 때문에 함수 외부에서 선언된 모든 변수들은 전역 변수가 된다.
for(var i = 0; i < 10; i++){};
console.log(i) // 10

조건문과 반복문에서 var 키워드로 선언된 변수들을 조건문과 반복문 밖에서 참조할 수 있다.

2. var 키워드 생략 허용

  • var 키워드를 생략하고 식별자만으로 변수를 선언할 수 있다.
name = "ldh";

3. 변수 중복 선언 허용

var foo = 3;
var foo = 4;
foo = 5;
console.log(foo) // 5

의도하지 않은 변수값의 변경이 일어날 수 있다.

4. 변수 호이스팅

function foo() {
    console.log(a);
    var a;
    a = 3000;
}
foo(); // undefined

변수를 선언하기 이전에 참조할 수 있다.

위와 같은 var의 단점들을 보완하고자 ES6에서 letconst 키워드를 도입하였다.


let

블록 스코프

letconst가 등장하기 전에 자바스크립트는 함수 레벨 스코프를 따르고 있었으나, letconst가 등장하면서 블록 레벨 스코프를 따르는 변수를 선언할 수 있게 되었다.

var foo = 123; // 전역 변수
{
  var foo = 456; // 전역 변수
}
console.log(foo); // 456

let bar = 123; // 전역 변수
{
  let bar = 456; // 지역 변수
}
console.log(bar); // 123
  • let 키워드로 선언한 변수는 블록({}) 스코프를 가진다.

변수 중복 선언 금지

var 키워드로는 동일한 이름을 갖는 변수를 중복해서 선언할 수 있었따. 하지만 let 키워드로 선언한 변수는 중복 선언 시 문법 에러(SyntaxError)가 발생한다.

var foo = 123; 
var foo = 456; // 재선언, 재할당 가능

let bar = 123; 
bar = 789; // 재할당 가능
let bar = 456; // 재선언 불가능
  • let 키워드는 재할당은 가능하지만, 재선언은 불가능하다.

호이스팅

자바스크립트에서 모든 선언식은 호이스팅이 발생한다.
하지만 let 키워드로 선언된 선언문은 변수를 선언문 이전에 참조하려고 할 경우 참조 에러(ReferenceError)가 발생한다.

console.log(foo); // undefined
var foo;

console.log(bar); // Uncaught ReferenceError
let bar;

varlet 모두 호이스팅이 발생하였음에도 둘의 결과가 다른 이유는 변수선언 3단계를 보면 알 수 있다.
(변수의 라이프사이클이라고도 함)

  • 변수 선언 3단계
    • 선언 단계
      • 값을 저장하기 위한 메모리 공간을 확보하고 저장한 값을 식별하기 위한 식별자(변수명)을 설정하는 것
    • 초기화 단계
      • 선언 단계에서 메모리 공간을 확보한 후에 해당 메모리 공간을 undefined로 초기화
    • 할당 단계
      • undefined로 초기화 되어있는 메모리에 값을 할당

var 키워드와 let 키워드의 변수선언 3단계에는 차이점이 있다.
var 키워드의 경우에는 선언 시에 선언 단계와 초기화 단계가 동시에 일어나게 된다.
반면 let 키워드의 경우에는 선언 단계와 초기화 단계가 나누어져 있는데, 그 사이에 일시적 사각지대(TDZ, Temporal Dead Zone)이라는 선언과 초기화 사이의 사각지대가 존재한다. 그래서 let 키워드의 경우 호이스팅이 발생하여도 let 키워드로 선언된 변수는 아직 초기화가 되지 않았기 때문에 참조 에러가 발생하게 된다.

  • let 키워드는 호이스팅이 발생하지만, 선언 이전에 참조할 수 없다.

전역객체와 let의 관계

전역에서 선언된 변수나 함수들은 전역객체의 프로퍼티가 된다.

function foo(){
    console.log(this)
}

var bar = 123;

window.foo(); 
//Window {window: Window, self: Window, document: document, name: '', location: Location, …}
window.bar; // 123

하지만 let 키워드로 선언한 변수는 전역 객체의 프로퍼티가 아니다.

let foo = 123;

window.foo // undefined
  • let 키워드로 전역에 선언된 변수는 전역 객체의 프로퍼티가 아니다.

const

블록 레벨 스코프

  • let과 마찬가지로 블록 레벨 스코프를 갖는다

선언과 초기화

let은 재할당이 가능하지만 const 키워드는 재할당이 불가능 하다. 그렇기 때문에 const 키워드로 선언한 변수는 반드시 선언과 할당이 동시에 이루어져야 한다. 그렇지 않을 경우 문법 에러가 발생한다.

const a;
// Uncaught SyntaxError: Missing initializer in const declaration
a = 100;
  • const로 선언된 변수는 재할당과 재선언이 모두 불가능하다.

상수

const란 키워드 이름은 상수의 뜻을 가지고 있는 constant에서 가져온 말이다.
상수란 변하지 않는 값을 말한다.

const로 선언된 객체

const는 재할당이 금지된다. 이것은 const로 선언된 객체에 대한 참조를 변경하지 못한다는 것을 의미한다.
하지만 이때 객체의 프로퍼티는 보호되지 않는다. 즉 객체를 재할당 할 수는 없지만 객체의 프로퍼티는 변경할 수 있다.

const user = {
  name : "ldh"
}

user.name = "hdl"

console.log(user.name) // "hdl"
  • const로 선언된 객체를 재할당하는 것은 불가능하지만 객체의 프로퍼티를 재할당하는 것은 가능하다.

요약

let

  • 블록 레벨 스코프를 갖는다.
  • 전역에서 선언하더라도 전역 객체의 프로퍼티에 속하지 않는다.
  • 재선언은 불가능, 재할당은 가능하다.
  • 호이스팅은 발생하지만 변수 선언 3단계 중 선언단계 이후에 일시적 사각지대(TDZ) 때문에 초기화가 되지 않았기 때문에 선언 이전에 참조가 불가능하다.

const

  • 블록 레벨 스코프를 갖는다.
  • 전역에서 선언하더라도 전역 객체의 프로퍼티에 속하지 않는다.
  • 재선언, 재할당 모두 불가능 하다.
  • const로 선언 시에 선언과 할당을 동시에 해주어야 한다.
  • let과 같이 선언 이전에 참조가 불가능하다.
  • const로 선언한 객체를 재할당 할 수는 없지만, 할당된 객체의 프로퍼티를 수정하는 것은 가능하다.

탬플릿 리터럴 (Template literal)

ES6에 도입된 새로운 문자열 표기법이다.
기존의 문자열은 '"을 사용했지만 탬플릿 리터럴을 사용한 표기법은 백틱 `을 사용한다.

const str1 = `안녕하세요`
const str2 = `안녕히 가세요
다음에 또 만나요
`
const str3 = `${str1}, ${str2}`
  • 탬플릿 리터럴은 이스케이프 시퀀스를 사용하지 않고 공백을 표현할 수 있고 줄바꿈을 별다른 표기없이 사용할 수 있다.
  • 탬플릿 리터럴로 표기된 문자열 내부에 문자열 인터폴레이션 ${...} 을 사용하여 식별자를 삽입할 수 있다.

화살표 함수 (Arrow Function)

화살표 함수는 function 키워드를 대신하여 화살표(=>)를 사용하여 보다 간략하게 함수를 표현하고 선언할 수 있게 해준다.

// 화살표 함수 문법

// 선언식
() 	=> {} // 매개변수가 없는 경우
x   => {} // 매개변수가 1개인 경우, 소괄호를 생략
(x, y) => {} // 매개변수가 여러 개인 경우

x => { return x - 1 } 
x => x + 1 // 함수 몸체가 한 줄인 경우, 중괄호 생략

() => {
  let x = 3;
  console.log(x + 1);
}

// 표현식
const foo = () => {
  let x = 123;
  console.log(x + 456);
}

const bar = x => x + 1

const boo = (x,y) => {
  console.log(x * y);
}

foo();
bar(1);
boo(2,3);
  • 화살표 함수는 익명 함수로만 사용할 수 있기 때문에 화살표 함수를 호출하기 위해서는 함수 표현식을 사용한다.

화살표 함수에서의 this

화살표 함수가 일반 함수의 가장 큰 차이점은 this이다.
일반 함수의 경우 함수의 호출 방식에 의해서 this에 바인딩 되는 객체가 동적으로 결정된다.
그러나 화살표 함수는 함수를 선언할 때 this에 바인딩할 객체가 정적으로 결정된다. 동적으로 결정되는 일반 함수와는 달리 화살표 함수의 this는 언제나 상위 스코프의 this를 가리킨다. 이를 렉시컬 디스(Lexical this)라고 한다.

렉시컬 스코프와 유사함

function Prefixer(prefix) {
  this.prefix = prefix;
}

Prefixer.prototype.prefixArray = function (arr) {
  // this는 상위 스코프인 prefixArray 메소드 내의 this를 가리킨다.
  return arr.map(x => `${this.prefix}  ${x}`);
};

const pre = new Prefixer('Hi');
console.log(pre.prefixArray(['Lee', 'Kim']));

화살표 함수의 특징

  • 화살표 함수에서 this는 정적으로 바인딩 된다.
  • 화살표 함수에서 this는 화살표 함수가 선언된 상위 스코프의 this를 가리킨다. 이를 렉시컬 this라고 한다.
  • call, apply, bind 메소드를 사용하여 this를 변경할 수 없다.
  • arguments 객체를 받을 수 없다.
    • 추후 설명할 Rest 파라미터를 이용하면 받을 수 있다.
function foo() {
	console.log(arguments)
}

const bar = () => {
  console.log(arguments)
}

foo(1,2,3);
// Arguments(3) [1, 2, 3, callee: ƒ, Symbol(Symbol.iterator): ƒ]
bar(1,2,3); 
// Uncaught ReferenceError: arguments is not defined
  • 생성자 함수로 사용할 수 없다

profile
지금은 프론트엔드

0개의 댓글