본문 바로가기

프로그래밍 언어/Javascript

Javascript) ES6 기본 개념과 문법 정리

ES6 란?

ES6는 ECMAScript 표준의 최신 버전으로 2009년도에 표준화된 ES5 이후 언어 기능에 대한 첫 업데이트입니다. 여기서 ECMAScript(ES) 란 ecma international이라는 정보 통신 시스템을 위한 국제 표준 기구가 표준화한 스크립트 프로그래밍 언어를 말합니다. 즉, 국제 표준화 기구가 자바 스크립트를 표준화하기 위해 만든 기술 규격이라고 할 수 있습니다. 최근 트랜드로 대두되고 있는 프레임워크 (react, vue등)이 개발 환경을 es6으로 맞춰가고 있기 때문에 es6에 주목할 필요가 있습니다. ES5 이하에서 문제 되었던 많은 부분들이 해결되었고, 가독성 및 유지보수성을 향상시키는 문법들이 새롭게 생겼기 때문에 지금부터 새로운 기본 문법에 대해 알아보겠습니다. 

새로운 기능 

  • const & let
  • arrow functions
  • template literals
  • default parameters
  • array & object destructuring
  • import & export
  • promises
  • rest parameter & spread operator 
  • classes 

1. const and let 

1.1 var의 문제점 

var 키워드는 기존 es5이하 문법에서 변수 선언을 위해 사용되었습니다. 자바스크립트에서 변수 선언은 변수 명을 등록하여 자바스크립트 엔진에 변수의 존재를 알리는 선언 단계를 거쳐 값을 저장하기 위한 메모리 공간을 확보하고 암묵적으로 undefined를 할당해 초기화 단계를 수행합니다. var 키워드는 선언과 초기화를 동시에 진행합니다. 그런데 여기서 문제점, var 키워드는 호이스팅이 됩니다. 런타임에 변수가 선언되는 것이 아니라 스크립트가 실행되기 이전에 모든 선언문을 찾아내 먼저 실행되기 때문에 그 위치가 어디에 있건 선언된 var 변수는 이미 undefined가 할당되어 있게 됩니다. 호이스팅으로 인해 var 변수는 함수 내에 선언되어도 그 스코프를 벗어난 곳에서 호출을 해도 오류가 생기지 않게 되어 개발자가 의도하지 않은 전역 변수, 중복 변수 등이 발생하게 되며, 이는 프로그램 흐름상 오류를 유발하거나 가독성을 떨어뜨립니다. 이를 보완하기 위해 ES6에서 const 와 let 키워드를 도입했습니다. 

1.2 const 

const는 한번 선언되면 변수를 다시 재할당할 수 없습니다. 그래서 선언과 동시에 초기화를 해야합니다. 즉, 변수를 만든 뒤, 저장된 값을 변경하는 것이 불가능합니다. 이는 var 키워드의 중복 허용으로 인한 의도치않은 값 재할당 문제를 해결해줍니다. 또한 선언한 범위 내에서만 사용할 수 있기 의도치 않은 전역 변수 선언도 발생하지 않게 됩니다. 

1.3 let

let은 const와 마찬가지로 선언한 범위 내에서만 사용할 수 있습니다. 그러나 const와 다르게 var처럼 초기화한 이후에도 값을 재할당 할 수 있습니다.

결론적으로 앞으로는 var 보다는 const와 let을 사용하는 것이 좋습니다. 값이 변하지 않을 경우 const를, 값이 변할 경우 let을 사용합니다.

2. Arrow function  

화살표 함수는 기존 함수 선언 문법을 변경한 것으로 전체적인 가독성을 높여줍니다. 특히, map, filter, reduce 등의 내장 함수와 함께 사용할 때 가독성이 높아지는 것을 확연히 느낄 수 있습니다. 

2.1 ES5 함수 선언 문법

function myFunc(name) {
	return '안녕' + name;
}

console.log(myFunc('영희'));

// >> 안녕 영희

2.2 ES6 화살표 함수 

const myFunc1 = (name) => {
	return `안녕 ${name}`;
}

const myFunc2 = (name) => `안녕 ${name}`;

console.log(myFunc1('영희')); 
// >> 안녕 영희

console.log(myFunc2('영희')); 
// >> 안녕 영희

위와 같이 function 이라는 키워드 대신에 화살표를 사용하기 때문에 보기 좋고, 왠지 더 있어보입니다. 위 예시에서 사용한 ${...} 는 아래 template literal 부분에서 설명합니다. 어쨌거나 myFunc1처럼 사용할 수도 있고, {.. }으로 함수 코드 부분을 감싸지 않고 바로 하나의 값이나 문자열 등을 리턴하는 경우 myFunc2와 같이 return 키워드 와 {..} 로 감싸주는 것 없이도 사용할 수 있습니다. 

3. Template Literals 

3.1 ES5 문자열 연결 

기본 문법에서는 문자열을 연결하기 위해서 + 연산자를 사용했습니다. 이는 코드 작성도 보기도 좋지 않습니다. 

var name = '영희';
var age = '25';

console.log(name + '는 ' + age + '살 입니다.';
// >> 영희는 25살 입니다.

3.2 ES6 문자열 문법 

ES6에서는 + 로 연결하는 대신 백틱(`)을 사용하여 문자열 내에 변수를 사용할 수 있게 합니다. 이건 보기도 좋고 증맬 편합니다. 

const name = '영희';
const age = 25;

console.log(`${name}는 ${age}살 입니다.`)
// >> 영희는 25살 입니다.

4. Default parameters 

매개변수에 기본값을 미리 정의해 두어 함수 호출시 인자를 전달하지 않은 경우, 기본값으로 사용하여 오류가 나지 않게 합니다. 아래 예시처럼 myFunc1을 호출할 때 name에 인자를 전달했지만 age에 인자를 전달하지 않았습니다. 이때, 자동으로 기본값인 22를 age의 값으로 사용하게 되어 사전에 오류를 처리해둘 수 있습니다.  

const myFunc = (name, age = 22) => {
	return `안녕 ${name} 너의 나이는 ${age}살 이니?`; 
};

console.log(myFunc1('영희'));
// >> 안녕 영희 너의 나이는 22살 이니?

5. Array and object destructing

5.1 ES5 비구조화

const contacts = {
	famillyName: '이',
	name: '영희',
	age: 22
};

let famillyName = contacts.famillyName;
let name = contacts.name;
let myAge = contacts.age;

console.log(famillyName); // 이
console.log(name); // 영희
console.log(age); //22

5.2 ES6 비구조화

const contacts = {
	famillyName: '이',
	name: '영희',
	age: 22
};

let { famillyName, name, age } = contacts;

console.log(famillyName); // 이
console.log(name); // 영희
console.log(age); //22

참고로 이 방식으로 비구조화 할당을 할 때에는 속성 이름과 동일한 변수명을 사용해야 합니다. 간단하게 생각해봐도 이름이 동일하지 않다면 어떤 변수에 어떤 값을 할당해야 할지 모를 것 같습니다. 대신 다른 변수 명으로 사용하고 싶으면 : 으로 다른 변수명을 지정해줄 수 있습니다. 

let { famillyName, name: ontherName, age } = contacts;

console.log(ontherName); // 영희

배열의 경우 속성명이라는게 따로 없기 때문에 배열에 저장된 순서대로 그 값을 매칭시킵니다. 

const arr = ['광희', '지수', '영철', 20];

let [value1, value2, value3] = arr;

console.log(value1); // 광희
console.log(value2); // 지수
console.log(value3); // 영철

6. Import and Export 

모듈, 컴포넌트 단위로 개발할 수 있도록 하는데 핵심적인 역할을 하는 문법입니다. 특정 모듈, 모듈을 작성 후 export 하고, 다른 컴포넌트에서 해당 모듈을 import하여 사용할 수 있기 때문에 재사용성이 높아집니다.

아래와 같은 함수를 detailComponent.js라는 파일에 선언하고 export 합니다. 

export default function detail(name, age) {
	return `안녕 ${name}, 너의 나이는 ${age}살 이다!`;
}

위 함수를 homeComponent.js라는 파일에서 import해서 사용합니다. 

import detail from './detailComponent';

console.log(detail('영희', 20));
// >> 안녕 영희, 너의 나이는 20살 이다!

export func1 ..,  export func2,...이런식으로 한 파일에 export 하는 모듈이 여러개인 경우 아래와 같이 중괄호로 감싸 여러개의 모듈을 가져올 수 있습니다. 

import { func1, func2 } from './moduleFile.js';

export 선언은 여러개 할 수 있기 때문에 위와 같이 export로 선언한 여러개의 함수를 중괄호로 감싸 import할 수 있지만 export default 는 한 파일 당 하나만 선언 가능하기 때문에 해당 파일에서 import할 대 중괄호로 감싸지 않고 모듈 이름만 가져오면 됩니다. 

7. Promises

프로미스는 ES6에 새롭게 등장한 기능으로 비동기 처리에 사용되는 객체입니다. 

const myPromise = () => {
	return new Promise((resolve, reject) => {
		resolve('안녕하세요 Promise가 성공적으로 실행했습니다');
	});
};

cosole.log(myPromise());
// Promise {<resolved>: "안녕하세요 Promise가 성공적으로 실행했습니다"}

프로미스 객체는 API를 통해 대량의 데이터를 가져와서 사용성을 떨어뜨리지 않고 매끄럽게 보여주기 위해서는 필수적으로 알아야 할 기능 같습니다. 캡틴 판교님의 블로그에 자세하게 설명된 글을 참고해야겠습니다. 

8. Rest parameter and Spread operator

8.1 Rest parameter

Rest 파라미터는 (...)라는 스프레드 연산자를 사용하여 함수의 파라미터를 작성한 형태를 말합니다. 이것을 사용해서 함수의 파라미터로 오는 값들을 배열로 전달 받을 수 있습니다. 즉, 함수 선언문에서 파라미터에 ...을 이용해서 가변인자를 받아 배열로 만들어 사용하는 것입니다. 이때 스프레드 연산자를 사용한 변수는 파라미터 중 맨 뒤에 써야 합니다

아래와 같이 ...rest 형태로 함수의 파라미터를 설정하면 함수내 rest 라는 변수는 항상 배열의 형태입니다. 몇개의 인자를 전달받을지 확실하지 않은 상태에서도 사용할 수 있다는 장점이 있습니다. 

const foo = (...rest) => {
  console.log(Array.isArray(rest)); // true
  console.log(rest); // [ 1, 2, 3, 4, 5 ]
}
foo(1, 2, 3, 4, 5);

8.2 Spread operator

스프레드 연산자는 함수를 호출할 때 전달하는 인자에 사용하는 것을 말합니다. 문법은 rest와 유사하지만 호출 시 사용하여 해당 매개변수로 각각 맵핑되는 것이기 때문에 rest와 다릅니다. 

// rest
const foo = (param, ...rest) => {
  console.log(param); // 1
  console.log(rest);  // [ 2, 3 ]
}
foo(1, 2, 3);


// spread 
const bar = (x, y, z) => {
  console.log(x); // 1
  console.log(y); // 2
  console.log(z); // 3
}

bar(...[1, 2, 3]);

배열을 연결하는 용도로 사용하기도 좋습니다. 

const arr = [1, 2, 3];
console.log([...arr, 4, 5, 6]); // [ 1, 2, 3, 4, 5, 6 ]


const arr1 = [1, 2, 3];
const arr2 = [4, 5, 6];
arr1.push(...arr2); 
console.log(arr1); // [ 1, 2, 3, 4, 5, 6 ]

또는 객체에서도 사용할 수 있습니다. 

const o1 = { x: 1, y: 2 };
const o2 = { ...o1, z: 3 };
console.log(o2); // { x: 1, y: 2, z: 3 }
 
const target = { x: 1, y: 2 };
const source = { z: 3 };
console.log(Object.assign(target, source)); // { x: 1, y: 2, z: 3 }

9. Classes

객체 지향 프로그래밍의 핵심인 클래스를 통해 코드를 캡슐화하여 더 깔끔하고 정교한 코드를 짤 수 있습니다. 

class myClass {
	constructor(name, age) {
		this.name = name;
		this.age = age;
	}

	sayHello() {
		console.log(`안녕 ${this.name} 너의 나이는 ${this.age}살이다`);
	}
}

// myClass 메서드 및 속성 상속
class UserProfile extends myClass {
	userName() {
		console.log(this.name);
	}
}

const profile = new UserProfile('영희', 22);

profile.sayHello(); // 안녕 영희 너의 나이는 22살이다.
profile.userName(); // 영희

References