기존의 javascript는 var
키워드로 변수를 선언하였다.
var
키워드로 선언된 변수들은 아래와 같은 특정이 있다.
for(var i = 0; i < 10; i++){};
console.log(i) // 10
조건문과 반복문에서
var
키워드로 선언된 변수들을 조건문과 반복문 밖에서 참조할 수 있다.
var
키워드를 생략하고 식별자만으로 변수를 선언할 수 있다.name = "ldh";
var foo = 3;
var foo = 4;
foo = 5;
console.log(foo) // 5
의도하지 않은 변수값의 변경이 일어날 수 있다.
function foo() {
console.log(a);
var a;
a = 3000;
}
foo(); // undefined
변수를 선언하기 이전에 참조할 수 있다.
위와 같은 var
의 단점들을 보완하고자 ES6
에서 let
과 const
키워드를 도입하였다.
let
과 const
가 등장하기 전에 자바스크립트는 함수 레벨 스코프를 따르고 있었으나, let
과 const
가 등장하면서 블록 레벨 스코프를 따르는 변수를 선언할 수 있게 되었다.
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;
var
와 let
모두 호이스팅이 발생하였음에도 둘의 결과가 다른 이유는 변수선언 3단계를 보면 알 수 있다.
(변수의 라이프사이클이라고도 함)
- 변수 선언 3단계
- 선언 단계
- 값을 저장하기 위한 메모리 공간을 확보하고 저장한 값을 식별하기 위한 식별자(변수명)을 설정하는 것
- 초기화 단계
- 선언 단계에서 메모리 공간을 확보한 후에 해당 메모리 공간을
undefined
로 초기화- 할당 단계
undefined
로 초기화 되어있는 메모리에 값을 할당
var
키워드와 let
키워드의 변수선언 3단계에는 차이점이 있다.
var
키워드의 경우에는 선언 시에 선언 단계와 초기화 단계가 동시에 일어나게 된다.
반면 let
키워드의 경우에는 선언 단계와 초기화 단계가 나누어져 있는데, 그 사이에 일시적 사각지대(TDZ, Temporal Dead Zone)이라는 선언과 초기화 사이의 사각지대가 존재한다. 그래서 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
키워드로 전역에 선언된 변수는 전역 객체의 프로퍼티가 아니다.let
과 마찬가지로 블록 레벨 스코프를 갖는다let
은 재할당이 가능하지만 const
키워드는 재할당이 불가능 하다. 그렇기 때문에 const
키워드로 선언한 변수는 반드시 선언과 할당이 동시에 이루어져야 한다. 그렇지 않을 경우 문법 에러가 발생한다.
const a;
// Uncaught SyntaxError: Missing initializer in const declaration
a = 100;
const
로 선언된 변수는 재할당과 재선언이 모두 불가능하다.상수
const
란 키워드 이름은 상수의 뜻을 가지고 있는constant
에서 가져온 말이다.
상수란 변하지 않는 값을 말한다.
const
는 재할당이 금지된다. 이것은 const
로 선언된 객체에 대한 참조를 변경하지 못한다는 것을 의미한다.
하지만 이때 객체의 프로퍼티는 보호되지 않는다. 즉 객체를 재할당 할 수는 없지만 객체의 프로퍼티는 변경할 수 있다.
const user = {
name : "ldh"
}
user.name = "hdl"
console.log(user.name) // "hdl"
const
로 선언된 객체를 재할당하는 것은 불가능하지만 객체의 프로퍼티를 재할당하는 것은 가능하다.const
로 선언 시에 선언과 할당을 동시에 해주어야 한다.let
과 같이 선언 이전에 참조가 불가능하다.const
로 선언한 객체를 재할당 할 수는 없지만, 할당된 객체의 프로퍼티를 수정하는 것은 가능하다.ES6
에 도입된 새로운 문자열 표기법이다.
기존의 문자열은 '
과 "
을 사용했지만 탬플릿 리터럴을 사용한 표기법은 백틱 `을 사용한다.
const str1 = `안녕하세요`
const str2 = `안녕히 가세요
다음에 또 만나요
`
const str3 = `${str1}, ${str2}`
${...}
을 사용하여 식별자를 삽입할 수 있다.화살표 함수는 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
를 가리킨다. 이를 렉시컬 디스(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