코딩일상
JavaScript의 ES5/ES6 문법 차이!! 본문
들어가기 앞서
ES5/ES6 문법 차이를 왜 알아야 하는가?
물론 현재 자바스크립트로 개발을 하게되면
ES6+를 통해서 개발이 진행이 될 것입니다.
그래도 왜 ES5을 알아야 하는 이유는 과거에 만들어진
JS코드를 리팩토링 해야할 경우도 있고
모든 회사가 항상 최신 문법을 쓰지 않기 때문입니다.
또한, 과거와 현재가 뭐가 어떻게 달라졌는지를 알게되면,
현재 기준에 대한 이해도를 올릴수도 있으며,
언제가 현재의 최신코드도 과거의 코드가 되어
쓰레기 취급 받을수도 있기에 이러한 변화와 차이를 아는것이 중요하다 생각합니다.
그리고 특히ES5/ES6의 차이를 물어보는 이유는
이 버전업데이트에서 기능추가된 점들이 지향하는 바의 차이가
크기 때문입니다.
ES5/ES6의 각각의 특징
ES5(출시년도2009)는 HTML5와 함께 출현한 표준안
JSON, strict mode, 접근자 프로퍼티, 프로퍼티 어트리뷰트 제어,
향상된 배열 조작가능(forEach, map, filter,reduce ,some ,every)
ES6(출시년도2015)
let/const, 클래스, 화살표함수, 템플릿리터럴, 디스트럭처링 할당, 스프레드문법,
rest 파라미터, 심벌, 프로미스, Map/set, 이터러블, for.. of, 제너레이터, proxy, 모듈import/export
템플릿 리터럴
ES6부터 새롭게 등장한 템플릿 리터럴. 덕분에 문자열 표현이 훨씬 간단해졌다.
템플릿 리터럴이란 작은 따옴표나 큰 따옴표 대신 백틱(`)으로 문자열을 감싸 표현하는 기능을 말한다.
템플릿 리터럴을 사용하면 플레이스 홀더(${variable})를 사용하여 백틱 내부에 문자열과 함께 표현식을 넣을 수 있다.
ES5
copy javascriptvar name = "현진";
var age = 25;
console.log("저의 이름은 " + name + "이고, 나이는 " + age + "살 입니다.");
ES6
copy javascriptvar name = "현진";
var age = 25;
console.log(`저의 이름은 ${name}이고, 나이는 ${age}살 입니다.`);
화살표 함수
ES6부터 새롭게 등장한 화살표 함수로 함수 선언법이 좀 더 간단해졌다.
ES5
함수 선언식
copy javascriptfunction str(arg1, arg2) { console.log("용민"); }
생성자 함수(많이 사용하지 않음)
copy phpvar str = new Function("arg1", "arg2", "console.log('용민')");
함수 리터럴(익명 함수를 만들 때 사용)
copy javascriptvar str = function(arg1, arg2) { console.log("용민"); };
참고
여기서 익명 함수란 말 그대로 이름이 없는 함수를 뜻한다.
ex) var bar = function (a, b) {...};
반대로 기명 함수는 이름이 있는 함수이다.
ex) var bar = function funcName(a, b) {...}
ES6
copy coffeescriptvar str = (arg1, arg2) => {
console.log("용민");
};
copy javascriptvar str = arg1 => console.log(arg1);
화살표 함수에 인자(argument)가 하나밖에 없다면 괄호를 생략할 수 있다.
또한 한줄로 표현이 가능하다면 위와 같이 중괄호({})를 생략할 수 있다.
copy swiftvar str = func => ({ id: "31" });
화살표 함수가 객체를 반환한다면 위와같이 표현해줄 수 있다.
this의 다른 동작
ES5
ES5같은 경우 객체 내에 있는 메소드를 실행 시 this는 메소드가 선언된 해당 객체를 가리킨다.
하지만 객체 안에서 선언된 함수의 this는 해당 객체가 아닌 window를 바라보고 있기 때문에 함수 안에서
this.name, this.age 를 하여도 아무 값이 나오지 않는다.
이러한 경우 해결방안으로 innerInfo.call(this) 를 통해 this 를 바인딩 시켜주거나 this를 해당 변수에 담아서 var self = this 와 같은 방식으로 접근하면 사용하면 된다.
copy javascriptvar thisTest = {
name : "김현진",
age : 25,
info : function() {
console.log(this)
console.log(this.name , this.age)
function innerInfo() {
console.log(this)
return this.name + ":" + this.age
}
return innerInfo()
}
}
// 실행결과
// {name: "김현진", age: 25, info: ƒ}
// 김현진 25
// Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, parent: Window, …}
// ":undefined"
ES6
ES6에서의 this 는 자신을 둘러싸고 있는 this를 바라보기 때문에 따로 바인딩이나 변수에 담을 필요 없다.
copy kotlinlet thisTest = {
name : "김현진",
age : 25,
info() {
console.log(this)
console.log(this.name , this.age)
innerInfo = () => {
console.log(this)
return this.name + ":" + this.age
}
return innerInfo()
}
}
// 실행결과
// {name: "김현진", age: 25, info: ƒ}
// 김현진 25
// {name: "김현진", age: 25, info: ƒ}
// "김현진:25"
생성자 함수의 인스턴스의 경우, this는 인스턴스를 가리킨다.
copy csfunction Obj(value) {
this.value = value;
}
var obj = new Obj(0);
console.log(obj.value); // 0
화살표 함수를 쓰면 함수가 선언된 스코프에 자동 바인딩이 된다.
copy javascriptvar obj = {
value: 10,
// 메소드 호출
show: function () {
console.log(this.value); // 10
// 함수 호출
function show_01 () {
console.log(this.value); // undefined
}
show_01();
// 화살표 함수
function show_02 = () => {
console.log(this.value); // 10
}
show_02();
}
}
obj.show();
변수 선언
ES5
ES5에선 var 밖에 존재하지 않았다. var 는 변수를 선언할 때 사용되는 키워드로,
재할당과 재선언에 굉장히 자유롭다.
copy javascriptvar x = 10;
x = 15;
console.log(x); //15
var x = 12;
console.log(x); //12
ES6
ES6부터 let, const가 추가되었다.
let은 한번 선언된 변수에 동일한 이름으로 선언할 수 없다.
하지만, 값은 재할당 할 수 있다.
copy javascriptlet x = 10;
x = 15;
console.log(x); //15
let x = 12; // Identifier 'x' has already been declared
const는 한번 초기화된 변수에 재할당/재선언할 수 없다.
copy cppconst x = 10;
console.log(x); // 10;
x = 15; // TypeError: Assignment to constant variable.
그리고, let, const는 블록 스코프 또는 Function 스코프 내부에 선언되면 해당 스코프 밖에서 안에 있는 변수를 참조할 수 없다.
쉽게 설명하자면, 중괄호로 묶인 부분 내부에 선언된 let, const를 중괄호 외부에서 참조할 수 없다는 것이다.
copy javascriptif (true) {
var i = 0;
}
console.log(i); // 0
if (true) {
let j = 10;
}
console.log(j); // ReferenceError
if (true) {
const k = 100;
}
console.log(k); // ReferenceError
밖에서 안에 있는 const, let은 참조할 수는 있다.
copy cppconst i = 5;
if (ture) {
console.log(i); // 5
}
var는 Function 스코프는 내부에 선언된 var를 외부에서 참조할 수 없지만
블록 스코프에선 내부에 선언되어 있어도 외부에서 참조 가능하다.
copy javascriptfunction f() {
var v = 5;
console.log(v); // 5
}
console.log(v); // ReferenceError: v is not defined
if (true) {
var i = 0;
}
console.log(i); // 0
정리하자면 다음과 같다.
재 선언 | 재 할당 | Block scope | Function scope | |
var | O | O | 외부에서 내부 참조 가능 | 외부에서 내부 참조 불가 |
let | X | O | 외부에서 내부 참조 불가 | 외부에서 내부 참조 불가 |
const | X | X | 외부에서 내부 참조 불가 | 외부에서 내부 참조 불가 |
모듈
ES5 이전에는 각 기능별로 JS 파일을 나누고 개발 및 관리하는 것이 불가능했다.
ES5
ES5 에선 require 를 통해 모듈화를 할 수 있었다.
예를 들어 아래와 같은 구조인 경우,
copy luajs / - - -script.js
|
--- slider.js
copy xml<script>
src = "slider.js";
</script>
<script>
src = "script.js";
</script>
index.html
copy javascriptvar slider = require(./slider.js)
// 혹은 require(./slider)
script.js
위와 같이 함으로써, slider.js를 임포트할 수 있었다. 이러한 방법으로 파일 자체를 사용할 수 있다.
ES6
ES6 부터는 import/export 로 모듈을 관리할 수 있다.
모듈은 실현가능한 특정 프로그램의 그룹니다.
그리고 이것은 다른 파일의 변수, 함수를 참조한다.
클래스와 같은 모듈이 로딩될 때, import와 export를 이용해 사용될 수 있다.
하나의 모듈만 공유할 때
로드 모듈
copy coffeescriptimport 'import to loadname' from '파일 경로'
아웃풋 모듈
copy coffeescriptexport default 'module'
copy coffeescriptimport Carousel from "./carousel";
cosnt carousel = new Carousel();
script.js
copy javascriptexport default class Carousel {
constructor() {
this.calc();
}
calc() {
console.log(10);
}
}
carousel.js
여러 모듈을 사용할 때
아웃풋 관점에서, export는 사용하고 싶은 곳에 붙이고, import는 다음과 같이 사용하면 된다.
copy coffeescriptimport {a1, a2, ...} from '파일 경로'}
copy javascriptimport { multi, SuperMulti } from "./Multiplay";
console.log(multi(5)); // 50
console.log(SuperMulti(6)); // 600
script.js
copy javascriptexport const i = 10;
export function multi(x) {
return i * x;
}
export function superMulti(x) {
return i * x * 10;
}
만약 모등 모듈을 전달받기 위해서는 import를 아래와 같이 작성하면 된다.
copy kotlinimport * as ‘object name’ form ‘파일 경로’
copy javascriptimport * as lib from "./multiply";
console.log(lib.multi(5)); // 50
클래스
ES5
ES5에선 class라는 키워드는 없었지만 프로토타입을 통해 실현 가능했다.
copy javascriptvar Add = function(arg1, arg2) {
this.arg1 = arg1;
this.arg2 = arg2;
};
Add.prototype.calc = function() {
return this.arg1 + "+" + this.arg2 + "=" + (this.arg1 + this.arg2);
};
var num = new Add(5, 8);
console.log(num.calc()); // 5 + 8 = 13
ES6
ES6에서는 class 키워드를 사용해서 선언할 수 있다.
copy kotlinclass Add {
constructor(arg1, arg2) {
this.arg1 = arg1;
this.arg2 = arg2;
}
calc() {
return this.arg1 + "+" + this.arg2 + "=" + (this.arg1 + this.arg2);
}
}
var num = new Add(5, 8);
console.log(num.calc()); // 5 + 8 = 13
클래스 상속
클래스의 상속과 오버라이딩은 super를 사용해서 수행할 수 있다.
ES5
copy javascriptvar AddSquare = function(arg1, arg2) {
Add.call(this, arg1, arg2);
};
Object.assign(AddSquare.prototype, Add.prototype);
AddSquare.prototype = {
calc: function() {
// 메소드는 생략될 수 없습니다.
Add.prototype.calc.call(this);
},
calcSquare: function() {
this.pow = Math.pow(this.arg1 + this.arg2, 2);
return "(" + this.arg1 + "+" + this.arg2 + ")^2=" + this.pow;
}
};
var numSquare = new AddSquare(5, 8);
console.log(numSquare.calc()); // 5 + 8 = 13
console.log(numSquare.calcSquare()); // (5 + 8) ^ 2 =169
ES6
copy scalaclass AddSquare extends Add {
constructor(arg1, arg2) {
super(arg1, arg2);
}
calc() {
super.calc();
}
calcSquare() {
this.pow = Math.pow(this.arg1 + this.arg2, 2);
return "(" + this.arg1 + "+" + this.arg2 + ") ^ 2 =" + this.pow;
}
}
var numSquare = new AddSquare(5, 8);
console.log(numSquare.calc()); // 5 + 8 = 13
console.log(numSquare.calcSquare()); // (5 + 8) ^ 2 = 169
'개발 공부 > JavaScript' 카테고리의 다른 글
[객체지향프로그래밍]this 란?? (0) | 2022.08.04 |
---|---|
[객체지향프로그래밍]super, prototype은 과연 언제 사용할까요? (0) | 2022.07.31 |
JavaScript의 ES란? (0) | 2022.07.24 |
유사배열과 배열의 차이는 무엇 일까요? (0) | 2022.07.22 |
padStart padEnd 주어진 길이 만큼 채우기 (0) | 2022.07.21 |