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; // 소수점 아래에서도 사용 가능