ES6이란?
- 자바스크립트 표준 사양인 ECMAScript의 6번째 버전
→ 기존 자바스크립트의 단점을 보완하고 코드 작성의 생산성과 가독성을 크게 향상시킨 표준 - ECMAScript 2015로 알려져 있으며 ES6으로 불림
- 2009년에 표준화된 ES5 이후 2015년에 자바스크립트의 대규모 업데이트가 이루어진 것이 ES6
- ECMAScript는 ES6이후 매년 새로운 버전을 발표하였으며 버전 이름은 발표 연도로 정해지지만, ES6 이후의 버전들은 ES6+로 불림
Ex) ES7(2016), ES8(2017), ES9(2018), ES10(2019), ES11(2020), ES12(2021), ES13(2022)
ES6 문법
const와 let
- ES6에서 새로 등장한 키워드
- const는 상수 선언이기 때문에 값의 재할당 불가능
→ Java의 final과 유사하지만 final은 변수 뿐만 아니라 클래스, 메서드에도 사용 되어 상속, 오버라이딩 제한 등 더 광범위한 의미를 가짐 - const는 HTML 요소를 선택할 때 사용하는 것은 매우 좋은 관례
→ 단, 참조 변경이 필요할 경우 let 사용
// ES5
var MyBtn = document.getElementById('mybtn');
// ES6
const MyBtn = document.getElementById('mybtn');
- let은 const와 달리 값의 재할당 가능
→ 즉, 변경 가능한 변수가 생성 됨 - 중복 선언이 불가하여 동일한 이름의 변수를 같은 스코프 내에서 재 선언 불가
let name = '철수';
name = '영희';
console.log(name);
// 출력 => 영희
let a = 10;
let a = 20; // SyntaxError: Identifier 'a' has already been declared
- var는 선언 위치와 상관 없이 스코프의 최상단으로 끌어올려지는 현상(호이스팅) 때문에 코드의 예측 가능성을 낮춤
- const와 let은 블록스코프를 가지며, 선언 이전에 사용할 경우 ReferenceError가 발생하여 var 보다 안전
호이스팅(hoisting) 이란?
- JavaScript 엔진이 실행 전에 변수와 함수 선언을 스코프의 최상단으로 끌어올리는 동작을 의미
- 이로 인해 코드에서 변수를 선언하기 전에 참조해도 오류가 발생하지 않는 상황이 발생할 수 있음
console.log(a); // undefined (호이스팅 발생)
var a = 10;
console.log(a); // 10
- 위의 코드는 JavaScript 엔진이 var를 호이스팅하여 아래와 같이 실행 됨
var a; // 선언만 끌어올림
console.log(a); // undefined
a = 10; // 할당은 원래 위치에서 수행
console.log(a); // 10
- 하지만, let과 const는 호이스팅 되더라도 TDZ(Temporal Dead Zone)에 걸려 선언 전에 접근 시 ReferenceError 발생
→ TDZ는 let과 const의 변수 선언 이전에 해당 변수를 참조하지 못하도록 보호하는 메커니즘
→ TDZ는 JavaScript 코드의 안정성과 예측 가능성을 높임
console.log(a); // ReferenceError
let a = 10;
화살표 함수 (Arrow Functions)
- 코드의 가독성을 높이고 this 바인딩 문제를 해결하는 데 유용
- 화살표 함수를 map과 filter, reduce 등 내장 함수와 함께 사용 가능
- Java의 람다 표현식과 유사
구문 간결화
// ES5
function myFunc(name) {
return '안녕' + name;
}
console.log(myFunc('영희')); // 안녕 영희
// ES6 화살표 함수
const myFunc = (name) => {
return `안녕 ${name}`;
}
console.log(myFunc('영희')); // 안녕 영희
// 중괄호와 return 또한 생략 가능
const myFunc = (name) => `안녕 ${name}`;
console.log(myFunc('영희')); // 안녕 영희
this 바인딩
- 화살표 함수는 자신만의 this를 가지지 않는 대신 선언된 위치의 this를 상속
- 일반 함수에서의 this는 호출되는 객체에 따라 달라지지만 화살표 함수는 이를 고정
const obj = {
value: 10,
regularFunction: function () {
console.log(this.value); // 10 (obj를 가리킴)
},
arrowFunction: () => {
console.log(this.value); // undefined (전역 `this`를 가리킴)
},
};
obj.regularFunction();
obj.arrowFunction();
익명 함수로 사용
- 화살표 함수는 항상 익명
- 함수 이름이 필요하지 않은 곳(콜백 함수 등)에서 자주 사용
// ES5
const myArrary = ['진수', '영철', '영희', 5];
let arr1 = myArrary.map(function(item) {
return item;
});
console.log(arr1); // 출력 => (4) ["진수", "영철", "영희", 5]
// ES6
let arr2 = myArrary.map((item) => item);
console.log(arr2); // 출력 => (4) ["진수", "영철", "영희", 5]
const numbers = [1, 2, 3];
const squares = numbers.map(num => num * num);
console.log(squares); // [1, 4, 9]
매개변수가 하나일 때 괄호 생략 가능
const square = x => x * x; // 매개변수가 하나라면 괄호 생략 가능
중괄호 사용 시 return 필요
- 여러 줄로 구성된 함수는 중괄호를 사용하고 명시적으로 return을 반드시 사용
const multiply = (a, b) => {
const result = a * b;
return result;
};
화살표 함수의 한계
this를 가지지 않음
- 객체 메서드로 사용할 때 화살표 함수는 적합하지 않음
const obj = {
value: 10,
method: () => console.log(this.value),
};
obj.method(); // undefined (this가 전역 객체를 가리킴)
arguments 객체를 가지지 않음
- 화살표 함수는 arguments 객체를 사용할 수 없는 대신, ...rest 문법을 사용
const func = (...args) => args;
console.log(func(1, 2, 3)); // [1, 2, 3]
생성자로 사용할 수 없음
- 화살표 함수는 new 키워드로 호출할 수 없음
const Person = (name) => {
this.name = name;
};
const john = new Person('John'); // TypeError: Person is not a constructor
템플릿 리터럴 (Template Literals)
- 기존 ES5에서 문자열과 변수를 연결하기 위해서는 작은 따옴표( ' ) 혹은 큰 따옴표( " )와 더하기 연산자(+)를 사용하여 표현
- ES6에서는 백틱(`)을 사용하여 더하기 연산자(+) 없이 더 간결하고 직관적으로 표현 가능
// ES5
const name = '철수';
const age = 25;
const message = '안녕하세요, 제 이름은 ' + name + '이고, 나이는 ' + age + '살입니다.';
console.log(message); // 안녕하세요, 제 이름은 철수이고, 나이는 25살입니다.
// ES6 템플릿 리터럴
const name = '철수';
const age = 25;
const message = `안녕하세요, 제 이름은 ${name}이고, 나이는 ${age}살입니다.`;
console.log(message); // 안녕하세요, 제 이름은 철수이고, 나이는 25살입니다.
- ${} 구문을 사용하여 문자열 안에 변수 삽입이 가능할 뿐만 아니라 표현식도 사용 가능
→ JSP의 EL 표현식( ${} )과 유사
const x = 10;
const y = 20;
console.log(`x + y = ${x + y}`); // 출력: x + y = 30
- 템플릿 리터럴을 사용하면 줄바꿈(\n) 없이도 여러 줄 문자열을 작성 가능
const multiline = `이것은
여러 줄로 작성된
문자열입니다.`;
console.log(multiline);
/* 출력:
이것은
여러 줄로 작성된
문자열입니다.
*/
- 템플릿 리터럴을 가공하기 위해 함수와 함께 사용 가능
function tag(strings, ...values) {
console.log(strings); // ["안녕하세요, 제 이름은 ", "이고, 나이는 ", "살입니다."]
console.log(values); // ["철수", 25]
return `${values[0]}님은 ${values[1]}살입니다.`;
}
const name = '철수';
const age = 25;
console.log(tag`안녕하세요, 제 이름은 ${name}이고, 나이는 ${age}살입니다.`); // 철수님은 25살입니다.
기본 매개 변수 (Default Parameters)
- 함수에서 특정 파라미터에 값이 전달되지 않은 경우 해당 파라미터에 대한 기본값을 사용하는 방식
- 함수 호출 시 매개변수를 명시적으로 전달하지 않아도 기본값을 사용해 예상치 못한 undefined 에러를 방지
- 기본 매개 변수의 동작
- 파라미터가 넘어오지 않았을 경우
- undefined가 넘어왔을 경우
단, null이 전달될 경우 기본값이 무시 되고 null 사용
// 기본 매개 변수를 사용하지 않은 경우
function greet(name) {
return `Hello, ${name}!`;
}
console.log(greet()); // Hello, undefined!
console.log(greet('철수')); // Hello, 철수!
// 기본 매개 변수를 사용하는 경우
function greet(name = '익명') {
return `Hello, ${name}!`;
}
console.log(greet()); // Hello, 익명!
console.log(greet('철수')); // Hello, 철수!
- 기본 매개 변수와 undefined
function greet(name = '익명') {
return `Hello, ${name}!`;
}
console.log(greet(undefined)); // Hello, 익명!
console.log(greet(null)); // Hello, null!
- 동적 기본값 설정
- 두 번째 매개 변수 b의 기본값이 첫 번째 매개 변수 a를 활용
function sum(a = 0, b = a * 2) {
return a + b;
}
console.log(sum()); // 0 (a = 0, b = 0 * 2)
console.log(sum(5)); // 15 (a = 5, b = 5 * 2)
console.log(sum(5, 10)); // 15 (a = 5, b = 10)
배열 및 객체의 비구조화 (Array and Object destructing)
- 배열이나 객체의 속성을 간단하고 가독성 좋게 변수로 추출하는 방법
- 기존의 ES5 방식보다 훨씬 간결하고 효율적인 코드를 작성 가능
비구조화 할당
// 객체의 비구조화 할당 : 중괄호 사용
// ES5
const person = {
name: '철수',
age: 25,
city: '서울'
};
const name = person.name;
const age = person.age;
const city = person.city;
console.log(name, age, city); // 철수 25 서울
// ES6
const person = {
name: '철수',
age: 25,
city: '서울'
};
const { name, age, city } = person;
console.log(name, age, city); // 철수 25 서울
// 배열의 비구조화 할당 : 대괄호 사용
// ES5
const colors = ['red', 'green', 'blue'];
const first = colors[0];
const second = colors[1];
const third = colors[2];
console.log(first, second, third); // red green blue
// ES6
const colors = ['red', 'green', 'blue'];
const [first, second, third] = colors;
console.log(first, second, third); // red green blue
기본값 설정
// 객체의 기본값
const person = { name: '철수', city: '서울' };
const { name, age = 20, city } = person;
console.log(name, age, city); // 철수 20 서울
// 배열의 기본값
const colors = ['red', 'green'];
const [first, second, third = 'blue'] = colors;
console.log(first, second, third); // red green blue
중첩 구조의 비구조화
// 객체의 중첩 구조
// ES5
var person = {
name: '철수',
address: {
city: '서울',
zip: '12345'
}
};
// 중첩된 속성에 직접 접근
var name = person.name;
var city = person.address.city;
var zip = person.address.zip;
console.log(name); // 철수
console.log(city); // 서울
console.log(zip); // 12345
// ES6
const person = {
name: '철수',
address: {
city: '서울',
zip: '12345'
}
};
const { name, address: { city, zip } } = person;
console.log(name, city, zip); // 철수 서울 12345
// 배열의 중첩 구조
// ES5
var colors = [
['red', 'green'],
['blue', 'yellow']
];
// 중첩된 배열의 요소에 인덱스를 이용해 접근
var first = colors[0][0];
var second = colors[0][1];
var third = colors[1][0];
var fourth = colors[1][1];
console.log(first); // red
console.log(second); // green
console.log(third); // blue
console.log(fourth); // yellow
// ES6
const colors = [
['red', 'green'],
['blue', 'yellow']
];
const [ [first, second], [third, fourth] ] = colors;
console.log(first, second, third, fourth); // red green blue yellow
Rest 패턴
- 나머지 값을 별도로 추출할 때도 유용
// 객체의 Rest 패턴
const person = {
name: '철수',
age: 25,
city: '서울'
};
const { name, ...rest } = person;
console.log(name); // 철수
console.log(rest); // { age: 25, city: '서울' }
// 배열의 Rest 패턴
const colors = ['red', 'green', 'blue', 'yellow'];
const [first, ...rest] = colors;
console.log(first); // red
console.log(rest); // ['green', 'blue', 'yellow']
객체의 비구조화 할당 주의 사항
- 객체의 속성명과 동일한 이름의 변수가 아니라면 undefined 반환
- 반드시 속성의 이름과 동일하게 할당을 해야하며, 변수의 이름을 변경하려면 콜론( : )을 사용하여 변경 가능
// 속성명과 다를 경우 undefined
const person = {
name: '철수',
age: 25,
city: '서울'
};
let { username, age, city } = person;
console.log(username, age, city); // undefined 25 서울
// 콜론을 사용하여 변수명 변경
const person = {
name: '철수',
age: 25,
city: '서울'
};
let { name : username, age, city } = person;
console.log(username, age, city); // '철수' 25 '서울'
가져오기 및 내보내기 (Import and Export)
- 모듈(module) 기능을 제공하는 ES6의 핵심 개념
- JavaScript 코드의 재사용성과 관리성을 높이는 데 매우 유용
export
- 다른 파일에서 사용할 수 있도록 함수, 변수, 클래스 등을 내보내는 역할
- 두 가지 방식으로 사용
Named Export
- 하나의 모듈에서 여러 개를 내보낼 수 있음
- 각 항목은 고유한 이름 가져야 함
// math.js
export const add = (a, b) => a + b;
export const subtract = (a, b) => a - b;
export const multiply = (a, b) => a * b;
export const divide = (a, b) => a / b;
Default Export
- 모듈에서 하나의 기본 값만 내보낼 때 사용
- export default는 이름 없이 내보낼 수 있음
// greet.js
export default function greet(name) {
return `Hello, ${name}!`;
}
import
- 다른 파일에서 내보낸 값을 가져오는 역할
- 내보낸 방식에 따라 가져오는 방법이 다름
Named Import
- 중괄호 {}를 사용해 원하는 항목을 가져옴
- 이름이 정확히 일치해야 함
// main.js
import { add, subtract } from './math.js';
console.log(add(10, 5)); // 15
console.log(subtract(10, 5)); // 5
Default Import
- 이름을 자유롭게 지정해서 가져올 수 있음
- 중괄호 {} 없이 가져옴
// main.js
import greet from './greet.js';
console.log(greet('철수')); // Hello, 철수!
Named Import와 Default Import를 함께 사용
// utils.js
export const format = (text) => text.toUpperCase();
export default function log(message) {
console.log(message);
}
// main.js
import log, { format } from './utils.js';
log(format('hello world')); // HELLO WORLD
Import All (*)
- 모든 Named Export를 하나의 객체로 가져올 수 있음
// main.js
import * as math from './math.js';
console.log(math.add(10, 5)); // 15
console.log(math.multiply(10, 5)); // 50
모듈 경로
- 상대 경로 : ./ 또는 ../로 시작 (./math.js)
- 절대 경로 : node_modules 또는 프로젝트의 설정에 따라 경로 지정 가능 (lodash)
프로미스(Promiss)
- ES6에서 추가된 비동기 코드를 사용하는 방식
- 이에 대해서는 콜백 함수, 프로미스, async/await에 대해 정리해둔 링크를 참조
나머지 매개 변수 및 확산 연산자(Rest parameter and Spread operator)
- 배열을 더 유연하고 간결하게 다룰 수 있도록 도와줌
나머지 매개변수 (Rest Parameter)
- 함수의 매개변수로 전달된 나머지 값을 배열 형태로 받는 문법
- ...을 사용하여 나머지 값을 하나의 배열로 처리
- 함수의 매개변수 목록에서 마지막에 위치
function introduce(name, age, ...hobbies) {
console.log(`이름: ${name}, 나이: ${age}`);
console.log(`취미: ${hobbies.join(', ')}`);
}
introduce('철수', 25, '축구', '음악', '영화 감상');
// 출력:
// 이름: 철수, 나이: 25
// 취미: 축구, 음악, 영화 감상
- 전달된 인자의 개수를 알 수 없을 때 유용
function sum(...numbers) {
return numbers.reduce((acc, curr) => acc + curr, 0);
}
console.log(sum(1, 2, 3, 4, 5)); // 15
확산 연산자 (Spread Operator)
- 확산 연산자는 배열을 개별 요소로 분리하거나, 복사 및 결합하는 데 사용
- ...을 사용하며, 배열, 함수 호출 등 여러 상황에서 활용
// 배열 복사
const arr1 = [1, 2, 3];
const arr2 = [...arr1]; // arr1의 복사본 생성
console.log(arr2); // [1, 2, 3]
// 배열 결합
const arr1 = [1, 2];
const arr2 = [3, 4];
const combined = [...arr1, ...arr2];
console.log(combined); // [1, 2, 3, 4]
// 함수 호출
const numbers = [10, 20, 30];
console.log(Math.max(...numbers)); // 30
차이점
특징 | 나머지 매개 변수(Rest) | 확산 연산자(Spread) |
역할 | 나머지 값을 배열로 수집 | 배열을 개별 요소로 분리 |
주요 사용처 | 함수의 매개 변수 | 배열, 함수 호출 등 |
문법 위치 | 함수 정의 시 ...변수명 | 배열, 함수 호출 앞 ... |
클래스(Classes)
- 객체를 생성하기 위한 템플릿 역할
- 이전에는 생성자 함수와 프로토타입을 사용하여 객체를 생성하고 상속을 구현했으나, ES6에서 클래스 문법이 도입되면서 더 간결하고 직관적인 방식으로 객체 지향 프로그래밍이 가능해짐
class Person {
// 생성자 함수 (객체 초기화)
constructor(name, age) {
this.name = name;
this.age = age;
}
// 메서드 정의
greet() {
console.log(`안녕하세요, 저는 ${this.name}이고, ${this.age}살입니다.`);
}
}
const person1 = new Person('철수', 25);
person1.greet(); // 안녕하세요, 저는 철수이고, 25살입니다.
클래스의 주요 특징
생성자(Constructor)
- 클래스에서 객체를 초기화하기 위해 사용하는 메서드
- 클래스 안에 한 번만 정의 가능
- 객체가 생성될 때 자동으로 호출
class Car {
constructor(brand, model) {
this.brand = brand;
this.model = model;
}
}
const myCar = new Car('Hyundai', 'Sonata');
console.log(myCar);
메서드 (Method)
- 클래스 안에서 정의된 함수
- 생성된 객체를 통해 호출 가능
class Animal {
constructor(name) {
this.name = name;
}
speak() {
console.log(`${this.name}가 소리를 냅니다.`);
}
}
const dog = new Animal('강아지');
dog.speak(); // 강아지가 소리를 냅니다.
정적 메서드 (Static Method)
- 클래스 자체에서 호출할 수 있는 메서드
- 객체가 아니라 클래스 이름으로 호출
- static 키워드로 선언
class MathUtil {
static add(a, b) {
return a + b;
}
}
console.log(MathUtil.add(5, 3)); // 8
상속 (Inheritance)
- extends 키워드를 사용하여 클래스를 확장 가능
- 부모 클래스의 속성과 메서드를 자식 클래스에서 사용 가능
- super를 사용하여 부모 클래스의 생성자나 메서드를 호출 가능
class Vehicle {
constructor(type) {
this.type = type;
}
describe() {
console.log(`이것은 ${this.type}입니다.`);
}
}
class Bike extends Vehicle {
constructor(type, brand) {
super(type); // 부모 클래스의 생성자 호출
this.brand = brand;
}
showBrand() {
console.log(`브랜드: ${this.brand}`);
}
}
const myBike = new Bike('자전거', '삼천리');
myBike.describe(); // 이것은 자전거입니다.
myBike.showBrand(); // 브랜드: 삼천리
클래스와 객체 리터럴의 차이
특징 | 클래스 (Class) | 객체 리터럴 (Object Literal) |
생성 방식 | new 키워드를 사용해 인스턴스 생성 | 중괄호 {}로 생성 |
메서드 정의 | 클래스 내부에 정의 | 객체에 직접 정의 |
상속 | extends와 super로 구현 | Object.create() 또는 프로토타입 사용 |
참고 자료
'Language > Javascript' 카테고리의 다른 글
[ES6+] ES7 ~ ES13 추가 기능 (1) | 2024.12.26 |
---|---|
[Javascript] DOM 렌더링 시점 (1) | 2024.12.09 |
[Javascript] DOM (Document Object Model)의 개념 (0) | 2024.12.09 |
[Javascript] 비동기 프로그래밍 [Callback, Promise, async/await] (0) | 2024.12.09 |
[Javascript] Javascript 동작 원리 [동기, 비동기] (0) | 2024.12.06 |