일단 기본적으로 ES5 까지는 비 파괴적인 데이터 구조를 갖고 있고, 비 파괴적인 데이터 구조는데이터의 변형을 일으키지 않기 때문에 하더라도 데이터 구조가 메모리에 크게 영향을 주지 않았다. 하지만 컴퓨터의 성능은 갈수록 좋아지고 있고, 이제 이러한 웹 사이트에서 Javascript 의 데이터를 이용한다고 하더라도 페이지가 느리게 로딩 되거나 하지 않기 때문에 ES6 파괴적인 데이터를 가진 내장 Methods도 포함된다.
var x = 3;
function func(get_number){
if(get_number){
var x = Math.random();
return x;
} // scope end point
return x;
}
func(false); // undefined
var x = 3;
function func(randomsize) {
var x; // x선언
if(randomsize) {
x = Math.random();
return x;
} // scope end point
return x;
}
func(false); // undefined
javascript의 초기 코드인 var를 let과 const로 맹목적으로 변경할 수 없다.
let x = 3;
function func(randomsize) {
if (randomsize) {
let x = Math.random();
return x;
}
return x;
}
func(false);
// Uncaught SyntaxError: Identifier 'x' has already been declared
(function () { // open IIFE
var tmp = ···;
···
}()); // close IIFE
console.log(tmp); // ReferenceError
ES6에서 쉽게 block과 let을 선언(혹은const 선언)을 사용할 수 있습니다.
```jsx
{ // open block
let tmp = ···;
···
} // close block
console.log(tmp); // ReferenceError
template literals
ES6를 통해 문자열을 보간하거나, 다양한 형태의 결괏값을 리터럴하여 인자로 사용할 수 잇다.
function printCoord(x, y) {
console.log('('+x+', '+y+')');
}
function printCoord(x, y) {
console.log(`(${x}, ${y})`);
}
Template literal
var HTML5_SKELETON =
'<!doctype html>\n' +
'<html>\n' +
'<head>\n' +
' <meta charset="UTF-8">\n' +
' <title></title>\n' +
'</head>\n' +
'<body>\n' +
'</body>\n' +
'</html>\n';
Template literal
const HTML5_SKELETON = `
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
</body>
</html>`;
(예는 공백을 포함하는 양에 차이가 있지만, 이 경우에는 상관이 없습니다.)
var HTML5_SKELETON = '\
<!doctype html>\n\
<html>\n\
<head>\n\
<meta charset="UTF-8">\n\
<title></title>\n\
</head>\n\
<body>\n\
</body>\n\
</html>';
function
expressions to arrow functions
B코드에 접근하기 위한 A코드 구현
function UiComponent() {
var _this = this; // (A)
var button = document.getElementById('myButton');
button.addEventListener('click', function () {
console.log('CLICK');
_this.handleClick(); // (B)
});
}
UiComponent.prototype.handleClick = function () {
···
};
ES6에서는 화살표 기능을 사용할 수 있다.
function UiComponent() {
var button = document.getElementById('myButton');
button.addEventListener('click', () => {
console.log('CLICK');
this.handleClick(); // (A)
});
ES6에서는 constructor 함수 대신 클래스를 사용할 수 있는 옵션도 있다.
화살표 기능은 식의 결과만 반환하는 짧은 콜백에 특히 유용합니다.
var arr = [1, 2, 3];
var squares = arr.map(function (x) { return x * x });
const arr = [1, 2, 3];
const squares = arr.map(x => x * x);
매개 변수를 정의할 때 매개 변수가 단일 식별자일 경우 괄호를 생략할 수도 있으므로,
(x) => x x => x x 모두 허용됩니다.
values
함수나 methods는 배열이나 객체를 통해 여러 개의 값을 반환한다. ES5에서는 항상 중간 변수를 생성해야 합니다. ES6에서는 파괴를 통해 중간 변수를 피할 수 있다.
exec()은 Array-like 개체를 통해 caputer된 그룹을 반환한다. ES5에서는 그룹에만 관심이 있더라도 중간 변수(아래 예제의 matchObj)가 필요한다:
var matchObj =
/^(\d\d\d\d)-(\d\d)-(\d\d)$/
.exec('2999-12-31');
var year = matchObj[1];
var month = matchObj[2];
var day = matchObj[3];
ES6에서 파괴하면 이 코드가 더 간단해집니다:
const [, year, month, day] =
/^(\d\d\d\d)-(\d\d)-(\d\d)$/
.exec('2999-12-31');
Array 패턴 시작 부분의 빈 슬롯은 Array 요소를 인덱스 0에서 건너뜁니다.
values
via objects
var obj = { foo: 123 };
var propDesc = Object.getOwnPropertyDescriptor(obj, 'foo');
var writable = propDesc.writable;
var configurable = propDesc.configurable;
console.log(writable, configurable); // true true
const obj = { foo: 123 };
const {writable, configurable} =
Object.getOwnPropertyDescriptor(obj, 'foo');
console.log(writable, configurable); // true true
{ writable: writable, configurable: configurable }
for
to forEach()
to for-of
var arr = ['a', 'b', 'c'];
for (var i=0; i<arr.length; i++) {
var elem = arr[i];
console.log(elem);
}
arr.forEach(function (elem) {
console.log(elem);
});
```jsx
const arr = ['a', 'b', 'c'];
for (const elem of arr) {
console.log(elem);
}
```
각 배열 요소의 인덱스와 값을 모두 원하는 경우, for-of는 새 배열 메서드 항목()과 파괴 기능을 통해서도 사용할 수 있다.
```jsx
for (const [index, elem] of arr.entries()) {
console.log(index+'. '+elem);
}
```
ES5에서는 다음과 같이 파라미터에 대한 기본값을 지정한다.
function foo(x, y) {
x = x || 0;
y = y || 0;
···
}
ES6는 구문이 더 좋음:
function foo(x=0, y=0) {
···
}
추가적인 이점은 ES6에서 매개 변수 기본 값은 정의되지 않은 경우에만 트리거 되지만 이전 ES5 코드의 임의의 잘못된 값에 의해 트리거 된다는 의미 이다.
selectEntries({ start: 0, end: -1 });
function selectEntries(options) {
var start = options.start || 0;
var end = options.end || -1;
var step = options.step || 1;
···
}
function selectEntries({ start=0, end=-1, step=1 }) {
···
}
function selectEntries(options) {
options = options || {}; // (A)
var start = options.start || 0;
var end = options.end || -1;
var step = options.step || 1;
···
}
function selectEntries({ start=0, end=-1, step=1 } = {}) {
···
}
arguments
to rest parameters```jsx
function logAllArguments() {
for (var i=0; i < arguments.length; i++) {
console.log(arguments[i]);
}
}
```
function logAllArguments(...args) {
for (const arg of args) {
console.log(arg);
}
}
function format(pattern, ...args) {
···
}
function format(pattern) {
var args = [].slice.call(arguments, 1);
···
}
Rest Parameters (나머지 매개변수)
Rest parameters는 코드를 읽기 쉽게 만듭니다. 함수의 매개변수 정의만 보아도 함수의 매개변수 개수가 가변적임을 알 수 있습니다.
나머지 연산자( ...
)를 마지막 형식 매개변수 앞에 놓는 것은 배열의 나머지 실제 매개변수를 모두 수신한다는 의미입니다.
**`function** f(x, ...y) {···}f('a', 'b', 'c'); *// x = 'a'; y = ['b', 'c']*`
남은 매개변수가 없으면 나머지 매개변수는 빈 배열로 설정됩니다.
`f(); *// x = undefined; y = []*
*** The spread operator 는 나머지 연산자와 똑같아 보이지만 함수 호출 및 배열 리터럴(구조 분해 패턴 내부가 아님) 내에서 사용됨
apply()
to the spread operator (...
)ES5에서는 apply()를 통해 배열을 매개 변수로 변환합니다. 이를 위해 ES6에는 spread연산자가 있습니다.
ES5 – apply()
:
Math.max.apply(Math, [-1, 5, 11, 3])
11
ES6 – spread operator:
Math.max(...[-1, 5, 11, 3])
11
ES5 – apply()
:
**var** arr1 = ['a', 'b'];**var** arr2 = ['c', 'd'];arr1.push.apply(arr1, arr2);
*// arr1 is now ['a', 'b', 'c', 'd']*
ES6 – spread operator:
const arr1 = ['a', 'b'];
const arr2 = ['c', 'd'];
arr1.push(...arr2);
// arr1 is now ['a', 'b', 'c', 'd']
concat()
to the spread operator (...
)ES5 – apply()
:
var arr1 = ['a', 'b'];
var arr2 = ['c'];
var arr3 = ['d', 'e'];
console.log(arr1.concat(arr2, arr3));
// [ 'a', 'b', 'c', 'd', 'e' ]
ES6 – spread operator:
const arr1 = ['a', 'b'];
const arr2 = ['c', 'd'];
arr1.push(...arr2);
// arr1 is now ['a', 'b', 'c', 'd']
자바스크립트에서 메서드는 값이 함수인 속성입니다.
메소드들은 ES5 객체 리터럴에서 다른 속성들과 같이 생성되며, 속성 값들은 함수식들을 통해 제공됩니다.
var obj = {
foo: function () {
···
},
bar: function () {
this.foo();
}, // trailing comma is legal in ES5
}
ES6에는 Methods 정의, Methods생성을 위한 특별한 구문이 있습니다:
const obj = {
foo() {
···
},
bar() {
this.foo();
},
}
ES6 클래스는 대부분 컨스트럭터 함수에 더 편리한 구문입니다.
ES5에서는 constructor 기능을 직접 구현합니다:
function Person(name) {
this.name = name;
}
Person.prototype.describe = function () {
return 'Person called '+this.name;
};
class Person {
constructor(name) {
this.name = name;
}
describe() {
return 'Person called '+this.name;
}
}
methods 정의에 대한 간결한 구문을 확인하십시오. 키워드 기능은 필요 없습니다. 또한 class의 각 부분 사이에는 쉼표가 없습니다.ES5에서 Subclassing은 특히 super-constructor와 super-properties를 언급할 때 복잡하다.
아래에는 super-constructor를 만드는 일반적인 방법입니다:
function Employee(name, title) {
Person.call(this, name); // super(name)
this.title = title;
}
Employee.prototype = Object.create(Person.prototype);
Employee.prototype.constructor = Employee;
Employee.prototype.describe = function () {
return Person.prototype.describe.call(this) // super.describe()
+ ' (' + this.title + ')';
};
ES6는 확장 조항을 통해 Subclassing을 기본적으로 지원합니다:
class Employee extends Person {
constructor(name, title) {
super(name);
this.title = title;
}
describe() {
return super.describe() + ' (' + this.title + ')';
}
Error
ES6에서는 모든 내장형 컨스트럭터를 서브클래싱할 수 있으므로 다음 코드는 ES5 코드가 시뮬레이션만 할 수 있는 것을 달성합니다:
function MyError() {
// Use Error as a function
var superInstance = Error.apply(null, arguments);
copyOwnPropertiesFrom(this, superInstance);
}
MyError.prototype = Object.create(Error.prototype);
MyError.prototype.constructor = MyError;
function copyOwnPropertiesFrom(target, source) {
Object.getOwnPropertyNames(source)
.forEach(function(propKey) {
var desc = Object.getOwnPropertyDescriptor(source, propKey);
Object.defineProperty(target, propKey, desc);
});
return target;
};
class MyError extends Error {
}
throw new MyError('Something happened!');
instance에서 길이를 적절하게 처리하는 Array의 하위 클래스를 만들 수도 있습니다:class Stack extends Array {
get top() {
return this[this.length - 1];
}
}
var stack = new Stack();
stack.push('world');
stack.push('hello');
console.log(stack.top); // hello
console.log(stack.length); // 2
일반적으로 Subclassing Array는 최선의 해결책이 아닙니다. 자신의 class(컨트롤 인터페이스)를 생성하고 개인 속성의 Array에 위임하는 것이 더 나은 경우가 많습니다.
서브클래싱 내장형 컨스트럭터는 엔진이 기본적으로 지원해야 하는 기능으로, 트랜스필러를 통해서는 이 기능을 제공할 수 없습니다.
이 섹션에서는 ES6 클래스의 개인 데이터를 관리하는 네 가지 방법에 대해 설명합니다:
클래스 생성자의 환경에 개인 데이터 유지, 명명 규칙(예: 접두사 밑줄)을 통해 개인 속성 표시,
WickMaps에 개인 데이터 보관,기호를 개인 속성의 키로 사용 접근법 #1과 #2는 ES5에서 이미 일반적이었고, 접근법 #3과 #4는 ES6에서 새로운 것입니다. 각각의 접근법을 통해 동일한 예를 4번 구현해 봅시다.
실행 중인 예로는 카운터(초기 값이 카운터)가 0에 도달하면 call-back 액션을 호출하는 class Countdown이 있습니다. 두 파라미터 액션과 카운터는 개인 데이터로 저장되어야 합니다.
첫 번째 구현에서, 우리는 액션과 카운터를 class constructor 환경에 저장합니다. 환경은 자바스크립트 엔진이 새로운 범위가 입력될 때마다 (함수 호출이나 constructor 호출을 통해) 존재하는 파라미터와 지역 변수를 저장하는 내부 데이터 구조입니다. 이것이 코드입니다:
class Countdown {
constructor(counter, action) {
Object.assign(this, {
dec() {
if (counter < 1) return;
counter--;
if (counter === 0) {
action();
}
}
});
}
}
Using Countdown
looks like this:
> const c = new Countdown(2, () => console.log('DONE'));
> c.dec();
> c.dec();
var dict = Object.create(null);
function countWords(word) {
var escapedWord = escapeKey(word);
if (escapedWord in dict) {
dict[escapedWord]++;
} else {
dict[escapedWord] = 1;
}
}
function escapeKey(key) {
if (key.indexOf('__proto__') === 0) {
return key+'%';
} else {
return key;
}
}
const map = new Map();
function countWords(word) {
const count = map.get(word) || 0;
map.set(word, count + 1);
}
map의 또 다른 장점은 문자열이 아닌 임의의 값을 key로 사용할 수 있다는 것이다.ES6 표준 라이브러리는 문자열에 대한 몇 가지 새로운 방법을 제공합니다.
indexOf
to startsWith
:
if (str.indexOf('x') === 0) {} // ES5
if (str.startsWith('x')) {} // ES6
indexOf
to endsWith
:function endsWith(str, suffix) { // ES5
var index = str.indexOf(suffix);
return index >= 0
&& index === str.length-suffix.length;
}
str.endsWith(suffix); // ES6
indexOf
to includes
:if (str.indexOf('x') >= 0) {} // ES5
if (str.includes('x')) {} // ES6
join
to repeat
(문자열을 반복하는 ES5 방식은 해킹에 가깝다):new Array(3+1).join('#') // ES5
'#'.repeat(3) // ES6
ES6에는 몇 가지 새로운 Array methods도 존재한다.
Array.prototype.indexOf
to Array.prototype.findIndex
```jsx
const arr = ['a', NaN];
arr.indexOf(NaN); // -1
arr.findIndex(x => Number.isNaN(x)); // 1
```
```jsx
sNaN('abc')
true
Number.isNaN('abc')
false
```
Array.prototype.slice()
to Array.from()
or the spread operator```jsx
var arr1 = Array.prototype.slice.call(arguments); // ES5
const arr2 = Array.from(arguments); // ES6
```
지금까지 모든 Array-like DOM 데이터 구조와 같이 값이 반복 가능한 경우 spread 연산자(...)를 사용하여 Array로 변환 햇다.
```jsx
const arr1 = [...'abc'];
// ['a', 'b', 'c']
const arr2 = [...new Set().add('a').add('b')];
// ['a', 'b']
```
indexOf
to includes
:if (str.indexOf('x') >= 0) {} // ES5
if (str.includes('x')) {} // ES6
join
to repeat
(문자열을 반복하는 ES5 방식은 해킹에 가깝다):new Array(3+1).join('#') // ES5
'#'.repeat(3) // ES6
ES5에서도 AMD로 구성된 또는 CommonJS 구문을 기반으로 하는 모듈 시스템은 대부분 노출된 모듈 패턴으로 코드를 작성하고 solution을 대체했습니다.
ES6에는 모듈이 내장되어 있습니다. 슬프게도 자바스크립트 엔진은 아직 모듈을 기본적으로 지원하지 않습니다. 그러나 browserify, webpack, jspm과 같은 도구를 사용하면 ES6 구문을 사용하여 모듈을 만들 수 있으므로 작성한 코드를 미래에 대비할 수 있습니다.
CommonJS에서는 다음과 같이 여러 Entity를 내보냅니다:
//------ lib.js ------
var sqrt = Math.sqrt;
function square(x) {
return x * x;
}
function diag(x, y) {
return sqrt(square(x) + square(y));
}
module.exports = {
sqrt: sqrt,
square: square,
diag: diag,
};
//------ main1.js ------
var square = require('lib').square;
var diag = require('lib').diag;
console.log(square(11)); // 121
console.log(diag(4, 3)); // 5
또는 전체 모듈을 개체로 가져와 이를 통해 사각형 및 다이어그램에 액세스할 수 있습니다:
var lib = require('lib');
console.log(lib.square(11)); // 121
console.log(lib.diag(4, 3)); // 5
//------ lib.js ------
export const sqrt = Math.sqrt;
export function square(x) {
return x * x;
}
export function diag(x, y) {
return sqrt(square(x) + square(y));
}
//------ main1.js ------
import { square, diag } from 'lib';
console.log(square(11)); // 121
console.log(diag(4, 3)); // 5
import * as lib from 'lib'; // (A)
console.log(lib.square(11)); // 121
console.log(lib.diag(4, 3)); // 5
//------ myFunc.js ------
module.exports = function () { ··· };
//------ main1.js ------
var myFunc = require('myFunc');
myFunc();