JavaScript의 역사와 함께 알아보는, ES6의 등장

2022년 3월 24일

#JavaScript

JavaScript 역사

1995년 : 자바스립트의 탄생

당시 네스케이프사의 네비게이터가 웹브라우저 시장을 지배하고 있었는데, 네스케이프는 HTML 페이지에 경량의 프로그램 언어를 통하여 인터렉티브 한 것을 추가 하기로 결정했다. 그렇게, 브래던 아이크 (Brendan Erich) 를 고용했고, 그는 10일 만에 언어를 만들었다. 그 언어의 이름은 ‘모카’였으며, 9월 ‘라이브스크립트’로 이름을 변경하였다. 그해 12월 네스케이프와 썬은 ‘라이브스크립트’를 ‘자바스크립트’ 라고 최종 이름을 결정하였다. ‘모카 → 라이브스크립트 → 자바스크립트’ 로 이름이 변경된 것이다. 이 자바스크립트는 네비게이터 2.0B3에 포함되었다. 하지만, 자바스크립트가 탄생한지 얼마되지 않아 자바스크립트의 파생 버전인 JScript가 등장한다.

1996년 8월 : 자바스크립트의 파편화

당시 마이크로소프트는 자바스크립트의 파생 버전 JScript를 인터넷 익스플로어 3.0 에 탑재하였다. 여기서 문제점은 JavaScript와 JScript 가 표준화되지 못하고 일부만 호환 되었던 것이다. 자사 브라우저의 시장 점유율을 점유하기 위해, 각 자사의 브라우저에서만 동작하는 기능을 경쟁적으로 개발하였다. 이로 인해 브라우저에 따라 웹 페이지가 정상 동작하지 않는 크로스 브라우징 이슈 가 발생하기 시작했고, 모든 브라우저에서 동작하는 웹을 개발하는 것을 어려웠다. 이에 모든 브라우저에서 동일하게 동작하는 표준화된 자바스크립트에 대한 필요성 이 제기되었다.

1997년 7월 : ECMAScript 공개

1996년 11월, 넷스케이프 커뮤니케이션즈는 컴퓨터 시스템의 표준을 관리하는 비영리 표준화 기구인 ECMA 인터네셔널에 자바스크립트의 표준화를 요청 하였다. 1997년 7월 ECMA-262로 불리는 표준화된 JS 초판의 명세가 완성되었고, 상표권 문제로 자바스크립트는 ECMAScript로 명명되었다. 이후 ES3, ES5가 등장하였고, 2015년에 ES6가 등장하면서 큰 변화가 있었다.

1999년 : 서버와 브라우저의 비동기적 통신, Ajax 등장

초창기 자바스크립트는 웹 페이지의 보조적인 기능을 수행하기 위해 한정적인 용도로 사용되었다. 이 시기에 대부분 로직은 주로 웹 서버에서 실행되었고 브라우저는 서버로부터 전달받은 HTML과 CSS를 단순히 렌더링하는 수준이었다.

1999년, 자바스크립트를 이용해서 **비동기적(Asynchronous)**으로 서버와 브라우저가 데이터를 교환할 수 있는 통신 기능인 **Ajax(Asynchronous JavaScript and XML)가 XMLHttpRequest**이라는 이름으로 등장했다.

Ajax 등장 이전 Ajax 등장 이후
서버로부터 완전한 HTML 전송 받아, 웹 전체를 랜더링 변경이 필요없는 부분은 랜더링하지 않음
화면이 전환되면 서버로부터 새로운 HTML 전송 받아 웹 페이지 전체를 리랜더링 서버로부터 필요한 데이터만 전송 받아 필요한 부분을 한정적으로 랜더링하는 방식
불필요한 데이터 통신, 변경이 없는 부분까지 다시 랜더링
화면 전환시 깜빡이는 현상, 퍼포먼스 측면에서 불리 빠른 퍼포먼스와 부드러운 화면 전환

2006년 : DOM을 쉽게 제어할 수 있는, jQuery 등장

2008년 : V8 자바스크립트 엔진의 등장, JS 웹 개발 언어로 정착

V8 자바스크립트 엔진의 등장과 함께, 웹 서버에서 수행되던 역할들이 클라이언트(브라우저)로 이동하였고, 이로써 웹 애플리케이션에서 Front-end 영역이 주목받는 계기가 되었다.

2009년 : NodeJS 등장으로 브라우저에서 벗어나 서버 사이드 애플리케이션 개발에도 활용

그리고 ECMAScript 2015 (ES6) 등장

ECMAScript 2015는 자바스크립트의 두 번째 주요 개정판이다. ECMAScript 2015는 ES6, ECMAScript 6으로도 알려져 있다.

ES6가 주목받는 이유는 무엇일까!?

ES6 🔥

ES6가 큰 관심을 받은 이유는 단지 최신 버전이기 때문일까? ❎

1997년 6월에 1판을 시작으로 불규칙적이게 개정되던 것이 2015년 부터는 매년 6월에 규칙적으로 개정이 되고 있다.

특히 이 중 ES6 에서는 ES5 이하 명세에서 문제가 되었던 부분들이 해결되었고 많은 기능들이 추가되었다.

이는 가독성과 유지보수성 향상 으로 이어졌다.

  • 많은 사람들이 ES6에 주목하는 이유를 ‘아름다운 코드’를 작성하는데 이바지하였기 때문이라고 한다.

React 나 Vue 등 유명 라이브러리들도 이에 맞춰 개발 환경을 ES6로 바꾸게 되었다. 이러한 이유로 인해 사람들이 ES6에 주목하고 관심을 갖게 되었다.


1️⃣ var, let , const 의 차이점은 스코프

  • ES5 이하

    • var 함수 스코프 (스코프는 어떤 변수들에 접근할 수 있는지 정의한 범위)를 가지며, 동일한 식별자로 재선언하면 기존 값을 덮어쓰게 됨.
    • 스코프 내에 이미 동일한 식별자를 가진 변수가 존재한다면 해당 변수를 재할당한다.
    function foo(){
      var i ;
    	for(var i=0; i<10; i++{
    		// 우리의 예상 : 이 안에서만 i에 접근할 수 있음. 하지만...
    	}
    	console.log(i);
    	// 10 -> var은 함수 스코프를 가지기 때문에 함수 내에 있는 변수에 접근 가능함.
    	//       만약 i가 for 문 이전에 선언되었더라면, for문에서 값이 덮어씌여졌을 것이다.
    }
    
    foo();
    • 예측 불가한 오류가 발생할 가능성이 높다
  • ES6 ~

    • let const 블록 스코프를 가지고, 재선언 불가
    • 재할당 가능한 변수 선언 키워드 let 과 (↔  var은 함수 스코프)
    • 상수 선언 키워드 const가 추가되었다.
    • 블록 스코프를 가지고 있다는 것은 변수를 둘러싼 블록 ({}) 안에서만 (위 예시에서 for문 같은 경우) 해당 변수에 접근할 수 있다는 것이다. → 이는 애플리케이션의 안정성을 높여준다.
    • 기존 var 키워드만 있었을 때 보다 예측 가능한 코드를 작성 할 수 있게 되었다.

2️⃣ 화살표 함수, 기본 파라미터

  • 화살표 함수 : 화살표 함수를 통해 코드를 짧고 효율적으로 표현할 수 있게 되었다.

    // ES5 이하
    var result = years.filter(function (data) {
      return data.year > 2008;
    });
    
    // ES6 ~
    const arrowReulst = years.filter((data) => data.year > 2008);
  • 기본 파라미터 : 함수의 기본 파라미터를 셋팅해줄 수 있다. 인자를 필요로 하는 함수에서 인자 없이 호출했을 때의 기본 값을 지정해주는 것이다.

    const testFunc = (year = 2021) => {
      console.log(year);
    };
    
    testFunc(); // 2021
    testFunc(2022); // 2022

3️⃣ for 변수 of 배열

  • for 변수 in 배열 → 변수의 index 값을 리턴한다. (권장X)
  • 배열.forEach → 내부에서 break 문을 사용할 수 없다. (권장X)
  • for 변수 of 배열 → 배열의 내용 출력 가능하며, 내부에서 break 문을 사용할 수 있다.
const years = [2001, 2010, 2015, 2018];

for (let year of years) {
  console.log(year);

  if (year == 2001) {
    break;
  }
  // 2001
}

→ 만약 break 문을 사용해야 하는 함수라면 for…of 문을 사용하면 좋을 것 같다.

→ 속도 측면에서는 for 문이 best

4️⃣ 스프레드 연산자

...연산자를 사용해 배열, 객체, 문자열을 다른 배열, 객체, 문자열과 결합하기가 수월해졌다.

  • ES5 이하
    • 기존에는 배열에서 concat 함수를 사용하거나 객체에 assign 함수를 사용하여 결합하였다
    • assign 같은 경우는 기존 객체를 변화시켜, 예상치 못한 변화를 일으킬 수 있다.
    const newArr = arr1.concat(arr2);
    const newObj = Object.assign(obj1, obj2); // obj1에도 newObj와 같이 새로운 값이 할당된다.
  • ES6 ~

    • 다음과 같이 표현 가능하다.
    • props 에서도 활용 가능하다. (Rest Parameter)
    const newArr = [1, 2, 3, ...arr1, ...arr2, 10, 1000];
    const newObj = { ...obj1, ...obj2 }; // 기존 객체에 변화가 생기지 않는다.
    function printYearsWithRestParameter(...years) {
      console.log(years);
    }
    
    printYearsWithRestParameter(2000, 2001, 2010, 2015, 2018);
    // [ 2000, 2001, 2010, 2015, 2018 ]

5️⃣ 객체 관련

  • 객체 비구조화 할당 : 객체의 프로퍼티를 꺼내 바로 사용할 수 있게 되었다.
const address = {
  country: "South Korea",
  city: "Seoul",
  street: "Gangnam",
  str_num: 141,
  postcode: "00510",
};

// ES5 이하

console.log(address.country);
console.log(address.city);
console.log(address.str_num);

// ES6 ~

const { country, city, str_num } = address;
  • 객체 프로퍼티 초기화 단축 : 객체 프로퍼티 이름이 로컬 변수 이름과 같으면 콜론과 값 없이 작성해도 된다. 값을 직접 명시해주는 경우와 함께 사용할 수 있다.
function getAddress(country, city, street) {
  const myAddress = {
    country, // country: country,
    city, // city: city,
    street, // street: street,
  };
}

getAddress("Korea", "Seoul", "Euncheon");

6️⃣ String 관련

  • 템플릿 리터럴
    • ES5 이하 : 변수, 상수가 많아진다면 가독성이 떨어진다.
    • ES6 ~ : 문자열 내의 변수, 상수, 줄바꿈까지 간결하게 작성할 수 있게 되었다.
// ES5
var str1 = ", ";
var str2 = "World!";
var str3 = "Hello" + str1 + str2;
  • includes() , startsWith(), endsWith() 메소드가 추가되었다.
years.indexOf(2014) !== -1); // ES5 이하
years.includes(2014); // ES6 ~

Promise

  • ES5 이하 : 비동기 처리를 위해 Callback 을 사용해왔다.
    • 비동기 처리를 순차적으로 실행해야 하는 경우에
    • (단점1) 비동기 처리를 중첩시켜서 표현하여 에러 및 예외처리가 어렵다는 점
    • (단점2) 중첩으로 인한 복잡도가 증가한다는 점이 있었다.
    try {
      setTimeout(() => {
        throw "Error!";
      }, 1000);
      // 에러를 만들지만 캐치하지 못한다.
      // (setTimeout()함수의 콜백은 이벤트큐에 있다가 콜스택이 비어지면 실행되기 때문)
    } catch (e) {
      console.log("에러를 캐치하지 못한다..");
      console.log(e);
    }
  • ES6 ~ : 비동기에서 성공과 실패를 분리하여 메서드를 수행한다.
//프로미스 생성
const promise1 = function (param) {
  return new Promise(function (resolve, reject) {
    if (param) {
      resolve("resolve");
    } else {
      reject("reject");
    }
  });
};

//프로미스 실행
promise1(true).then(
  function (result) {
    console.log(result); //resolve
  },
  function (err) {
    console.log(err); //reject
  }
);

→ 성공했을 때 resolve(), 실패했을 때 reject() 를 실행한다.

  • 비동기 함수 중간에 에러가 난다면 .then .catch 를 통해 체이닝이 가능하다.

Map

  • Map() 은 자바스크립트의 key-value 쌍으로 이루어진 컬렉션
  • key 를 사용해서 value 를 get, set 할 수 있음
  • key 는 중복될 수 없음, 하나의 key 에는 하나의 value 만
  • key 로 사용할 수 있는 데이터형
    • string, symbol(ES6), object, function
    • number 는 사용할 수 없음에 주의!
// 새로운 map 을 만들고

let me = new Map();

// map 에 key, value 엔트리를 추가

me.set('name', 'juhee');
me.set('age', 24);

console.log(me.get('name'); // juhee
console.log(me.get('age'); // 24
// 대괄호를 사용해서 map 을 선언 [[KEY, VALUE], [KEY, VALUE], [KEY, VALUE]]
const roomTypeMap = new Map([
  ["01", "예시1"],
  ["02", "예시2"],
  ["03", "예시3"],
  ["04", "예시4"],
  ["05", "예시5"],
]);
  • Object와의 차이? Object에서 key 는 string, 추후에 나올 Symbol 만 가능 map.size 로 바로 크기를 알 수 있다.

Set

  • value 로만 이루어진 컬렉션 (Array 와 비슷)
  • Array와 차이점? value가 중복될 수 없다. index가 존재하지 않지만, has() 를 통해 존재하는 값인지 확인할 수 있다. (indexOf 보다 연산이 빠르다고 한다)
// Set 선언
let setA = new Set();

// 비어있는 새로운 set 을 만들고 value를 추가
let setB = new Set().add("a").add("b");
setB.add("c");

console.log(setB.size); // 3

// has(): 주어진 값이 set 안에 존재할 경우, true 를 반환. indexOf() 보다 빠름. 단, index 가 없음
console.log(setB.has("b")); // true

// set 에서 주어진 값을 제거
setB.delete("b");
console.log(setB.has("b")); // false

// set 안의 모든 데이터를 제거
setB.clear();
console.log(setB.size); // 0

→ 중복되는 값을 포함하면 안되는 자료 구조를 작성할 때 Set 을 활용하면 적절할 것 같다.

Symbol

  • ES6에 도입된 원시 타입. 데이터의 유일함을 나타날 때 사용하며, 생성된 심볼은 다른 어떤 심볼과도 일치하지 않는다. (new 키워드를 사용하지 않는다)
  • 객체나 클래스에서 유일한 프로퍼티 만들 때 사용한다. 유일성이 보장되기에 프로퍼티 추가 시 충돌이 날 수 없으며, 의도치 않은 프로퍼티 변경을 막을 수 있다.
const sym1 = Symbol(”key”)
const sym2 = Symbol(”key”)

sym1 === sym2 // false

Array Method

array.every(function)

  • 배열 안의 모든 요소가 주어진 판별 함수 function 을 통과하는지 검사한다. Boolean 값을 return 한다.
  • true에 대한 all 조건
  • [12, 5, 8, 130, 44].every(elem => elem >= 10); // false

array.some(function)

  • 하나라도 true가 발생하면 ture 를 반환한다.
  • true에 대한 or 조건

array.fill(value ,start, end)

  • 배열의 start 인덱스(기본값 0) 부터 end-1 (기본값 array.length) 인덱스까지 정적인 값 value로 채운다.

const array1 = [1, 2, 3, 4];

console.log(array1.fill(0, 2, 4)); // index 2부터 3까지 0으로 채운다. // expected output: [1, 2, 0, 0]

array.flat

array.flatMap

array.reduce V

array.reverse

등 배열 자료형을 쉽게 다룰 수 있는 문법이 등장하였다.

보너스 : ES2021

1. replaceAll

  • 문자열을 한 번에 여러 개 바꿀 수 있는 기능이 추가되었다.
  • 이전에는 정규식을 통해 작성했었다.
"hello,world,everyone".replace(/,/g, " ");
// 'hello world everyone'
"hello,world,everyone".replaceAll(",", " ");
// 'hello world everyone'

2. Logical Assignment (||=, &&=, ??=)

a = a || 1;

b = b && 2;

c = c ?? 3;
  • 위처럼 ||, &&, ?? 연산을 줄여서 표기할 수 있다.

3. numeric separators

  • 124412039120 처럼 자바스크립트에서 큰 숫자를 상수로 표시할 때는 헷갈리기 쉽다. 따라서 콤마는 아니지만 숫자 단위를 구분할 수 있는 _ 기호가 추가되었다. 구분하고 싶은 곳에다 _ 기호를 추가하면 된다. 소수점 아래에도 추가 가능하다.
1_000_000;
1_2345_2345;
25.12_2364; // 소수점 아래에서도 사용 가능

Profile picture

주희(Joy)
가치를 고민하는 과정을 함께해요