Dev-Tino 3주차(5):: JavaScript 기본 문법, ES6에 추가된 문법
자바스크립트, 자바스크립트 문법 특징, 자바 스크립트 기본 개념, 자바스크립트 추가된 개념
많은 이들이 알고 있듯, 자바스크립트는 정적인 HTML 콘텐츠를 프로그램 구현을 통해 동적으로 변경하거나 사용자와의 상호작용을 담당하도록 하는 언어이다. 이언어는 HTML이나 CSS와 달리 C언어, 자바와 같은 일반 프로그래밍 언어와 비슷한 구조를 가진다.
기본 문법에 대해서는 이런 유튜브나 시판의 책을 참고하도록 하자.
자바스크립트는 객체 기반의 스크립트 언어이다.
자바 스크립트는 객체((Object)기반의 스크립트 언어로, 기본적으로는 웹 브라우저에서 해석되는 인터프리터(코드를 한 줄씩 읽어 내려가며 실행하는 프로그램, 코드 전체를 읽어 기계어로 번역하는 컴파일러와는 대조적이다.) 언어이다. 객체 기반이기에 객체 지향 프로그래밍과 함수형 프로그래밍을 모두 표현할 수 있으며, 관련된 글을 찾아보았다면 알 수 있듯 ‘HTML의 내용, 속성, 스타일을 변경’ 할 수 있다는 특징 역시 가진다.
이 자바 스크립트는 1995년 처음 발표되어 웹의 발전과 함께 지금까지 계속해서 성장해나가고 있다. ES5(2009), ES6(2015), ES8(2017)… 다양한 버전 중 우리가 확인할 것은 2015년 버전, ES6이다.
ES6(2015) 주요 특징
1. 기본 매개 변수 (Default Parameters)
2. 템플릿 리터럴 (Template Literals)
3. 멀티 라인 문자열 (Multi-line Strings)
4. 비구조화 할당 (Destructuring Assignment)
5. 향상된 객체 리터럴 (Enhanced Object Literals)
6. 화살표 함수 (Arrow Functions)
7. 프로미스의 추가 (Promises) : 자바스크립트 비동기 콜백 문제 해결
8. 모듈 (Modules)
9. let, const 키워드 추가
10. iterator/generator 추가
1. 기본 매개 변수의 추가
ES6이 나오기 전에는 함수에 넘겨주는 인자 값에 대한 default 처리를 위해 추가 구문을 할당했어야 한다. (예시 1) 그러나 ES6이 나옴으로써 우리는 매개변수 옆에 바로 기본값을 지정할 수 있게 됐다.
2. 템플릿 리터럴
템플릿 리터럴은 내장된 표현식을 허용하는 문자열 리터럴이다. 여러 줄로 이뤄진 문자열과 문자 보간 기능을 사용할 수 있다. 이전 버전 명세에서는 “template strings”라 불렸다. 이는 이중 따옴표나 작은 따옴표 대신 백틱(` `)을 이용하며, 플레이스 홀더를 이용해 표현식을 넣을 수 있다. 이는 $와 중괄호 ‘{}’ 로 표시한. 플레이스 홀더 안에서의 표현식과 그 사이의 텍스트는 함께 함수로 전달된다.
3. 멀티 라인 문자열
다른 언어와 달리 자바 스크립트는 문자열 입력시에 소스상에서의 개행을 지원하지 않는다. 개행 후 문자열을 기입할 시 구문 에러가 발생한다.
다음과 같이 오류가 발생한다(…)
따라서 문자열을 여러 줄로 나눠 기입하기 위해서는 문자열을 개행하고자 하는 단위로 잘라, 아래와 같이 +를 이용하여 문자열을 이어주어야 한다.
약간 불편하지만 큰 이슈가 되지는 않았다고 하는데, 이것이 Node.js 를 통해 서버를 구현하고 쿼리문을 작성하며 문제가 되기 시작했다고 한다. 자바 스크립트에서 제공하는 문법으로 작성하려면 멀티 라인으로 작성하기가 어렵다. 따라서 한 줄로 쿼리를 작성해야 하는데. 쿼리가 복잡해질 경우 수정할 때 눈에 쉽게 들어오지 않아 힘들어진다고 한다.
역슬래시를 이용할 수도 있지만, 이것은 결과 출력 시에 한 줄로 출력된다는 문제점이 있다. 게다가 이 방식은 실수로 ‘\’ 뒤에 공백이라도 들어가면 오류가 발생한다는 점이다.
ES6에서는 이 점을 개선하였다. 위와 같은 백틱(``)을 이용해 간단히 멀티 라인 스트링을 만들 수 있다.
다음과 같은 식이다.
4. 비구조화 할당 (Destructuring Assignment)
배열이나 객체 속성을 해체하여 개별 변수에 값을 답는 JavaScript 표현식. 구조 분해 할당이라고도 부른다.
이는 객체 안에 있는 값을 추출하여 변수 혹은 상수로 바로 선언하기 위한 문법이다.
…위 배열의 요소를 세 가지 변수에 각각 넣기 위해서는 배열의 요소를 꺼내어 각각 지정해야 한다는 번거로움이 발생한다. 이를 비구조화 할당 문법을 이용하면 쉽게 정리할 수 있다.
비구조화 할당 문법::
왼 쪽에 변수, 또는 상수를 넣고 오른쪽에는 객체를 넣는다. 이 비구조화 할당 문법은 객체/배열 안에 있는 값을 바로 넣을 수 있다.
6. 화살표 함수
이는 함수 표현식보다 단순하고 간결한 문법으로 함수를 만드는 방법이며, 이는 문법의 생김새를 차용하여 지어졌다.
7. 프로미스의 추가
프로미스가 추가되었다. 프로미스는 3주차 스터디 (3) 글을 참고한다.
https://withglyph.com/fleshgolem_com/758495453
8. 모듈
모듈이란?
어플리케이션을 구성하는 개별적 요소로 재사용 가능한 코드 조각이다. 일반적으로 파일 단위로 분리하며 필요에 따라 명시적으로 모듈을 로드하여 사용한다. 모듈은 기능별로 분리되어 작성하므로, 코드의 단위를 명확히 분리하여 어플리케이션을 구성할 수 잇으며 재사용성이 좋아 개발 효율성과 유지 보수성을 높일 수 있다.
이는 자바의 클래스와 비슷한 느낌의 개념인데, 이전의 자바스크립트에는 모듈 기능이 존재하지 않아 AMD, CommonJS, UMD 방식의 모듈 시스템만을 사용하였다. 그러나 ES6의 경우 모듈에 대한 표준을 도입하여 유용하다. (ES6 모듈 기능을 사용하지 않으면 분리된 자바스크립트 파일이 하나의 전역을 공유하게 된다.) import, export 구문을 통해 모듈을 내보내고 받을 수 있다. (+모듈에서 하나만을 export 할 때에는 default를 사용한다.)
9. let과 const의 추가
ES5까지의 변수를 선언할 수 있는 유일한 방법은 var 키워드를 사용하는 것이었다. var 키워드로 선언된 변수는 아래와 같은 특징을 가진다::
-함수 레벨 스코프
>함수의 코드 블록만을 스코프로 인정한다. 따라서 전역 함수 외부에서 생성한 변수는 모두 전역 변수이다. 이는 전역 변수를 남발할 가능성을 높인다.
>for문의 변수 선언문에서 선언한 변수를 for 문의 코드 블록 외부에서 참조할 수 있다.
-var 키워드 생략 허용
>암묵적 전역 변수를 양산할 가능성이 크다.
-변수 중복 선언 허용
>의도하지 않은 변수값의 변경이 일어날 가능성이 크다
-변수 호이스팅
>변수를 선언하기 이전에 참조할 수 있다.
이 때문에 전역변수 관련한 문제가 발생할 수 있다. 변수의 내용이 의도치 않게 변경되거나 유효 범위가 넓어 어디에 사용해야 할 지 모를 수 있고, 결과적으로 복잡성을 증가시켜 코드를 불편하게 만든다.
이 문제점을 미연에 방지하기 위하여 보완한 변수-변수의 스코프를 줄인 변수가 let과 const 변수이다. 대부분의 언어가 블록 레벨 스코프를 따르는 데에 반해 자바스크립트는 함수 레벨의 스코프를 따른다.
함수 레벨의 스코프는 ‘함수 내에서 선언된 변수는 함수 내에서만 유효하며 함수 외부에서는 참조할 수 없’다. 함수 내부에서 선언한 변수는 지역 변수리고, 함수 외부에서 선언한 변수는 모두 전역 변수이다.
변수 레벨의 스코프는 ‘모든 코드 블록’ 내에 대해 이야기한다. 모든 코드 블록 내에서 선언된 변수는 코드 블록 내에서만 유효하며 코드 블록 외부에서는 참조할 수 없다. 즉, 코드 블록 내부에서 선언한 변수는 지역 변수이다.
이 let 변수는
1. 블록 수준의 스코프를 지원하며
2. 같은 이름을 가지는 변수를 중복하여 선언할 수 없고
3. 선언문 이전에 참조하면 참조 에러가 발생한다.
이는 let 키워드로 선언된 변수가 스코프의 시작에서 변수의 선언까지 일시적 사각지대(Temporal Dead Zone: TDZ)에 빠지기 때문이나, 이에 대해서는 나중에 후술하겠다.
const는 상수(변하지 않는 값)을 위해 사용한다. 반드시 상수만을 위해 사용하지는 않는다. let의 특징을 공유하나 ‘재할당이 금지된다’는 차이점이 있다. 그렇기에 const는 반드시 ‘선언과 동시에 할당이 이루어져야’ 한다. 이는 const 변수 타입의 객체의 경우 객체에 대한 참조를 변경하지 못한다는 것을 이야기한다. 이 때 객체의 프로퍼티는 보호되지 않는다. 즉, “재할당은 불가능하지만 이미 할당된 객체의 내용” (프로퍼티의 추가, 삭제, 프로퍼티 값의 변경)은 변경할 수 있다.
10. iterator(반복자)와 generator의 추가
Iterable
반복 가능한:: 자바 스크립트에서 Iterable이란 반복이 가능함을 의미한다. 배열, Map(배열을 순회하여 각 요소를 콜백 함수로 적용해 처리해 모은 새로운 배열을 반환하기 위한 함수, map 함수에 전달되는 콜백 함수는 각 요소를 변환하여 새로운 배열로 매핑하는 역할을 한다), set(중복되지 않는 값들의 집합을 나타내는 내장 객체. 원시 값과 객체 참조를 모두 포함할 수 있다. 값의 순서를 유지한다.)등이 모두 iterable한 요소이다. 이는 Iterable Protocol-객체를 반복 가능하게 만드는 표준 방법을 제시하는 규약, 이 프로토콜을 따라 iterator를 구현할 수 있다-을 따르기 때문에 가능한 일이다.
iterator는 결국 데이터 안의 요소를 연속적으로 꺼내는 행위를 위한 객체이다. ‘반복 처리가 가능한 객체’ 말이다. 반복문, for each의 경우 메소드의 작업은 내부적으로 처리되므로 개발자가 각 처리 단계를 제어할 수 없으나, iterator를 사용하면 개발자가 반복 처리를 단계별로 제어할 수 있다.
ES6의 이터레이터는 일반적으로 다음 두 가지 항목을 만족하는 객체이다.
-next 메소드를 가진다.
-next 메소드의 반환값은 value 프로퍼티와 done 프로퍼티를 가진 객체이다. 이 때 value에는 꺼낸 값이 저장되고 done에는 반복이 끝났는지를 뜻하는 논리값이 저장된다.
-즉, next 메소드의 반환값이 iterator result 객체여야 한다.
제네레이터 (generator)
하나의 값(혹은 0개의 값)만을 반환하는 일반 함수와는 달리, 여러 개의 값을 필요에 따라 하나씩 반환(yield)할 수 있는 함수. 제네레이터(generator)와 iterable(반복 처리가 가능한 객체)한 객체를 함께 사용하면 손쉽게 스트림(*전체 데이터 세트를 메모리에 로드할 필요 없이 소스에서 데이터를 읽거나 데이터를 청크 단위로 대상에 쓰는 데에 사용하는 요소. 대용량 데이터를 처리하거나 시간이 지남에 따라 데이터가 도착할 때 강력한 도구.)을 만들 수 있다.
제네레이터를 만드는 법:: 제네레이터 함수
제네레이터는 일반 함수와 달리 function 키워드의 앞에 *을 붙인다. 이 제네레이터 함수는 일반 함수와 동작 방식이 다른데. 제네레이터 함수를 호출하면 코드가 실행되는 대신 ‘실행을 처리하는 특별 객체’, ‘제네레이터 객체’가 반환되는 식이다.
이 generator 함수에서 신경써야 할 점은 ‘함수 선언 방식’과 yield 키워드이다. yield 키워드는 제네레이터 함수를 멈추거나 다시 시작하게 하는 데에 사용하는 키워드이다. 중간에 원하는 부분에서 멈추었다가 그 부분에서부터 다시 실행할 수 있는 능력을 가진 함수, generator와 yield는 떼어놓을 수 없는 한 짝이다. 제네레이터 함수의 특징은 다음과 같다::
제네레이터(Generator) 함수의 특징::
-제네레이터 함수에는 화살표 함수를 사용할 수 없다.
-제네레이터 함수는 함수 호출자에게 함수 실행의 제어권을 양도(yield)할 수 있다. (일반 함수 같은 경우에는 함수가 어딘가에서 호출되었을 때 그 함수에 대한 제어권은 호출한 함수 본인에게 넘어간다.)
-제네레이터 함수는 함수 호출자와 함수의 상태를 주고받을 수 있다.
호출되는 순간에 매개 변수(parameter)를 통해 함수 외부에서부터 값을 전달 받고 실행되는 일반 함수와는 달리 (일반 함수, 함수가 실행되고 있는 동안에는 함수 외부에서 함수 내부로 값을 전달하여 함수의 상태 변경 불가능.) 제네레이터 함수는 ‘함수 호출자와 양방향으로 함수의 상태를 주고받을 수 있’다. 즉, 제네레이터 함수는 함수 호출자에게 자신의 상태를 전달할 수 있고, 함수 호출자로부터 추가적으로 상태를 전달받을 수도 있다는 것이다.
-함수 호출 시 제네레이터 객체를 생성해 반환한다.
일반 함수는 호출될 때에 함수의 코드 블록을 실행시킨다. 반면에 제네레이터 함수는 코드 블록을 실행시키는 것이 아니라 제네레이터 객체를 생성해 반환한다.
제네레이터 객체::
제네레이터 함수가 실행될 때 생성, 및 반환되는 객체. 제네레이터 객체는 이터러블(*이터러블 프로토콜을 준수한 객체)이며 동시에 이터레이터(*이터러블에 Symbol.iterator 메소드를 호출했을 때 반환되는 값) 이다.
iteraot에 있는 next 메소드를 이용하여 이터러블의 각 요소를 순회할 수 있으며, next 메소드를 호출하면 이터레이터 리절트 객체(iterator result object)가 반환된다. 이터레이터 리절트 객체는 value와 done이라는 프로퍼티를 가지고 있다.
번외) for each, for in, for of
자바스크립트가 나온 지 얼마 되지 않았을 당시, 반복문을 위해 우리는 다음과 같은 코드를 사용했다::
그러나 ES5이후에는 forEach 코드를 사용할 수 있게 되었다.
그러나 이 방식은 break 구문을 이용하여 루프를 중단하거나 return 구문을 이용하여 함수를 벗어날 수 없다는 점이 문제이다. 다른 방식인 for-in 구문은 루프의 순회 순서가 무작위이며 index에 할당되는 값이 문자열이지 숫자가 아니라는 점 등때문에 좋지 않다.
새로 나온 문법은 다음과 같다::
이를 for-of 구문이라 부른다. 이것은 for-in 구문의 단점을 배제하며, forEach()구문과 달리 break; continue; return 구문을 지원한다는 장점이 존재한다. 이것으로 data를 순회할 수 있으며, 배열과 비슷한 대부분의 객체를 대상으로 사용할 수도 있다.
2022년 ES13이 나왔다. 자바스크립트는 계속해서 발전해나가고 있다. 개발자도 이에 맞추어 끊임없이 새 문법을 공부하여야 할 것이다.
[참고 자료]
-https://dinfree.com/lecture/frontend/123_js_1.html
-https://namu.wiki/w/%EC%9D%B8%ED%84%B0%ED%94%84%EB%A6%AC%ED%84%B0
-https://blog.asamaru.net/2017/08/14/top-10-es6-features/
-https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Template_literals
-https://velog.io/@kim_unknown_/JavaScript-ES6
-https://ko.javascript.info/arrow-functions-basics
-https://poiemaweb.com/es6-block-scope
-http://hacks.mozilla.or.kr/2015/08/es6-in-depth-iterators-and-the-for-of-loop/
-https://itholic.github.io/js-multiline-string/
-https://learnjs.vlpt.us/useful/06-destructuring.html
-https://developer.mozilla.org/ko/docs/Web/JavaScript/Guide/Iterators_and_generators
-https://nukw0n-dev.tistory.com/21
- 카테고리
- #기타
댓글 0
추천 포스트