ES2015 핵심 정리
History
- ES1 : 1997
- ES2 : 1998
- ES3 : 1999
- ES5 : 2009
- ES6 : 2015 (ES2015)
- ES2016
let, const
- var : 기존 변수 선언, 함수 스코프, 호이스팅(hoisting)
- let : 변수 선언, 블록 스코프, no hoisting(선언 전 검사 불가), window 객체의 property로 추가 안됨, 반복문에서 closure 생성시 반복문 조건 구문에서 생성된 변수의 경우 생성시점 값 유지
- const : 상수 선언, 블록 스코프, no hoisting(선언 전 검사 불가), window 객체의 property로 추가 안됨
- 권장 : 기본적으로 const를 사용하고 변수값을 변경해야 하는 경우만 let을 사용
var
clouser 생성시 마지막 값 공유
var funcs = [];
for(var i=0;i<10;i++) {
funcs.push((function(v){
return function() {
console.log(v);
}
}(i)));
}
funcs.forEach(function(func) {
func(); // 0, 1, 2, … 9
}
let
반복문에서 closure 생성시 반복문 조건 구문에서 생성된 변수의 경우 생성시점 값 유지
var funcs = [];
for(let i=0;i<10;i++) {
funcs.push(function() {
console.log(i);
});
}
funcs.forEach(function(func) {
func(); // 0, 1, 2, … 9
}
Unicode
- ECMAScript 6 이전에는 UCS16방식의 2byte Unicode만 지원
- ES6에서는 Surrogate Pair을 이용한 4byte Unicode도 지원
- charCodeAt, fromCharCode에 대응되는 codePointAt, fromCodePoint 함수 제공
- normalize함수를 제공하여 코드 정규화 지원(NFC, NFD, NFKC, NFKD 등)
- UCS16이 아닌 유니코드를 위한 u플래그가 정규식에 추가됨
codePointAt1, fromCodePoint2
var text = '古a';
console.log(text.charCodeAt(0)); //55362
console.log(text.charCodeAt(1)); //57271
console.log(text.charCodeAt(2)); //97
console.log(text.codePointAt(0)); //134071
console.log(text.codePointAt(1)); //57271
console.log(text.codePointAt(2)); //97
console.log(String.fromCodePoint(134071)); //古
console.log(String.fromCodePoint(57271)); //�
console.log(String.fromCodePoint(97)); //a
normalize3, regular expression
var text = "인";
console.log(text.normalize("NFD")); //인
console.log(text.normalize("NFD").length) // 3
console.log(text.normalize("NFC")); //인
console.log(text.normalize("NFC").length) // 1
var text = '𠮷';
console.log(text.length); //2
console.log(/^.$/.test(text)); //false
console.log(/^.$/u.test(text)); //true
template literal
- 따옴표 대신 백틱(`) 사용
- 멀티라인 지원
- 치환자 지원 : 자바스크립트 표현식을 치환자로 사용.
${name}.
- 태그 지원 : 템플릿 리터럴 데이터와 함께 호출되는 함수
template literal
let count = 10,
price = 0.25,
message = litTag`${count} items cost $${(count * price).toFixed(2)}.`;
function literalTag(literals, ...substitutions) {
let result = '';
for(let i = 0; i < substitutions.length ; i++) {
result += literals[i] + substitutions[i];
}
result += literals[literals.length - 1];
return result;
}
console.log(message); // 10 items cost $2.50.
default parameter, rest parameter
- default parameter :
function test(url, timeout = 2000 )
- rest parameter : 나머지 매개변수는 앞에 세 개의 점(…)을 붙여서 표시
function test(object, ...keys) {
for(let i = 0 ; i < keys.length; i++) {
console.log(keys[i]);
}
}
function - spread operator4
- 배열을 나누어 함수에 개별적인 인자로 전달
- apply()로 구현하던 기능을 대체할 수 있음
- rest parameter를 전달할 때 사용 가능함
let values = [1,2,3,4,5];
console.log(Math.max.apply(Math, values)); // 5
console.log(Math.max(...values); // 5
let values1 = [0, ...values, 6]; // [0,1,2,3,4,5,6]
function func1(...values) {
Math.max(...values);
}
function name
- name : 자바스크립트 함수 이름을 식별할기 위해 추가된 프로퍼티
- 디버깅을 위한 기능으로 함수 참조를 찾아오는 방법은 제공안함
function func1() {}
var func2 = function() {};
console.log(func1.name); // func1
console.log(func2.name); // func2
arrow function5
- () => {}
- prototype 없음
- this 변경 불가
- arguments 객체 없음
- (param1 = defaultValue1, param2, …rest) => { statements }
function func1(a) {return a * 2;}
a => a*2;
tail call optimization
다음 조건을 만족할 때 새로운 호출 스택을 사용하지 않고 현재 스택을 재활용. 재귀함수 사용시 성능 개선에 도움이 됨
- strict 모드
- 클로저가 아닌 경우
- tail call의 결과를 즉시 반환
- tail call이후 추가 작업이 없는 경우
"use strict"
function func() {
return func1(); // optimize됨
}
function func() {
var ret = func1(); // optimize 안됨 (3)
return ret;
}
function func() {
return 1 + func1(); // optimize 안됨(4)
}
tail call optimization
function factorial(n) {
if(n <= 1 ) {
return 1;
} else {
return n * factorial(n - 1); // optimize 안됨
}
}
function factorial(n, p = 1) {
if(n <= 1 ) {
return 1 * p;
} else {
let result = n * p;
return factorial(n - 1, result); // optimize 됨
}
}
확장된 객체 리터럴 문법
function createPerson(name) {
return {
name: name,
sayName: function() {
console.log(name);
}
}
}
function createPerson(name, age) {
return {
name, // property initializer shorthand
sayName() { // concise methods
console.log(name);
}
}
}
Object.is()
아래 예제를 제외하면 === 와 유사함
console.log(+0 === -0); // true
console.log(Object.is(+0, -0)); // false
console.log(NaN === NaN); // false
console.log(Object.is(NaN, NaN)); // true
Object.assign()
source objects에서 target oject로 property 복사. mixin 구현에 사용
function mixin(target, source) {
Object.keys(supplier).forEach(function(key) {
target[key] = source[key];
});
return target;
}
var ret = mixin({}, {prop:'a'});
var ret1 = Object.assign({}, {prop:'a'});
prototype
- Object.setPrototypeOf() : prototype 변경
- Object.getProtytpyeOf() : prototype 조회
- super : 현재 객체의 prototype를 참조하는 포인터로 간결한 메소드(concise methods)에서만 사용할 수 있다. Object.getPrototypeOf(this)와 유사
method(메서드)6
- [[HomeObject]] property를 가진 함수. super 사용 가능
- concise method
PropertyName( parameters ) { ... }
- generator Method, getter, setter
let friend = {
getGreeting() { // 메서드임 (concise method)
return super.getGreeting() + " hello"; // 오류 발생 안함
},
getGreeting1: function() { // 메서드가 아님
return super.getGreeting() + " hello"; // 오류 발생
}
}
object destructuring(구조분해)
let node = {
type : "identifier",
name : "foo"
}
let { type, name } = node;
console.log(type); // identifier
console.log(name); // foo
node.name = "bob";
({ type, name } = node); // ()로 감싸야 함
console.log(name); // bob
array descructuring
let colors = ["red", "green", "blue"];
let [ firstColor, secondColor ] = colors
console.log(firstColor); // red
console.log(secondColor); // greeen
default value, local variable
let node = {
type : "identifier",
name : "foo"
}
let { type, name:userName, value = true } = node;
console.log(type); // identifier
console.log(userName); // foo
console.log(value); // true
destruturing - array clone
var colors = ["red", "green", "blue"];
var clonedColor = colors.concat(); // ECMAScript 5
let colors1 = ["red", "green", "blue"];
let [...clonedColor1] = colors1; // ECMAScript 6
let clonedColor2 = [...colors1]; // ECMAScript 6
destruturing - parameter
function setCookie(name, value,
{secure, path, domain, expries}) {
console.log(secure); // true
console.log(expire); // 60000
}
setCookie("type", "js", {secure:true, expire:60000});
setCookie("type", "js"); // error 발생
function setCookie1(name, value,
{secure, path, domain, expries} = {}) {
...
}
setCookie1("type", "js"); // 정상 동작
심벌
- Symbol은 유일하고 변경 불가능한(immutable) 기본값 (primitive value)
- 객체 속성의 key 값으로 사용 가능
- Primitives : Boolean, Null, Undefined, Number, String, Symbol (new in ES2015)
심벌 정의
let firstName = Symbol("frist name");
let person = {};
person[firstName] = "Nicolas";
console.log(person[firstName]); // "Nicolas"
console.log(firstName); // "Symbol(first name)"
심벌 공유
let firstName = Symbol("frist name");
let firstName2 = Symbol("frist name");
let uid = Symbol.for("uid");
let uid2 = Symbol.for("uid");
console.log(firstName === firstName2); // false
console.log(uid === uid2); // true
console.log(Symbol.keyFor(firstName)); // undefined
console.log(Symbol.keyFor(uid)); // "uid"
심벌 프로퍼티 탐색
- Object.getOwnPropertySymbols() : 객체가 소유한 프로퍼티 심벌을 반환
- Object.keys(), Object.getOwnPropertyNames()는 심벌 프로퍼티 반환하지 않는다.
well-known symbols
JavaScript 내부 언어 동작을 나타내기 위한 built-in Symbol
- Iteration symbols
- Symbol.iterator : 이터레이터 반환
- Regular expression symbols
- Symbol.match, Symbol.replace, Symbol.search, Symbol.split
- Other symbols
- Symbol.hasInstance : instanceof 연산자와 동일한 메서드
- Symbol.isConcatSpreadable, Symbol.unscopables, Symbol.species, Symbol.toPrimitive, Symbol.toStringTag
Set, Map
Set : 중복되지 않는 값의 리스트 Map : 특정 값에 연결된 키의 컬렉션
ES5의 Set과 Map
var set = Object.create(null);
set["5"] = true;
if( set["5"] ) {
...
}
var map = Object.create(null);
map["5"] = "bar";
var value = map["5"];
/* [문제점] 객체의 프로퍼티는 문자열만 허용되어
* 같은 문자열로 평가되는 두개의 키를 사용할 수 없다.
console.log(map[5] === map["5"]); // true.
ES6의 Set
let set = new Set();
set.add(5);
console.log(set.has("5")); // false
set.add("5");
console.log(set.size); // 2
set.add(5);
console.log(set.size); // 2
set.delete(5);
console.log(set.size); // 1
let array = [...set];
let set2 = new Set(array);
let array2 = [...new Set([1,2,2,3])]; // [1,2,3]
ES6의 Map
let map = new Map();
map.set(5, "55");
console.log(map.has("5")); // false
map.set("5", "500");
console.log(map.size); // 2
console.log(map.get(5)); // "55"
map.delete(5);
console.log(map.size); // 1
map.forEach(function(value, key, ownerMap) {
console.log(key + " " + value); // 5 500
console.log(ownerMap === map); // true
});
Iterator(이터레이터)
- 이터레이터는 반복을 위해 설계된, 특별한 인터페이스를 가진 객체
- next : 아래 2개의 속성들을 가진 object 를 반환하는 arguments 없는 함수
- done (boolean) : 이터레이터가 마지막 반복 작업을 마쳤을 경우 true.
- value : 이터레이터로부터 반환되는 값. done이 true일 경우 생략 가능
var array = [2, 4, 6];
var arrayEntries = array.entries();
console.log(arrayEntries.next()); // {value: [0,2], done: false}
console.log(arrayEntries.next()); // {value: [1,4], done: false}
for-of
for-of문은 반복문이 실행될 때마다 이터러블의 next()를 호출하고 반환된 객체의 value를 변수에 저장
var array = [2, 4, 6];
for(let num of array) {
console.log(num);
}
// 2
// 4
// 6
for-in vs for-of
for-in : 객체의 열거형 속성들을 모두 적절한 순서에 의해 반복 for-of : 이터러블의 next()를 호출하고 반환된 객체를 전달
var obj = {a:1, b:2, c:3};
for (let prop in obj) {
console.log(prop + " = " + obj[prop]);
}
for (let prop of obj) {} // 오류 발생. obj is not iterable
var array = [2, 4, 6];
for (let num in array) {
console.log(num); // 0, 1, 2
}
for(let num of array) {
console.log(num); // 2, 4, 6
}
Generator(제너레이터)
이터레이터를 반환하는 함수로 별표(*)를 사용하여 표현하고 yield를 사용한다. iterator의 next() 메서드가 호출되면, generator 함수가 실행되고 첫 번째 yield expression 을 만날 때까지 진행되고 yield expression 이 가리키는 값이 iterator 로부터 리턴된다. 이후 next() 메서드가 호출되면 진행이 멈췄던 부분에서부터 다시 실행된다.
function *createIterator() {
yield 1;
yield 2;
}
let iter = createIterator();
console.log(iter.next()); //{value: 1, done: false}
console.log(iter.next()); //{value: 2, done: false}
console.log(iter.next()); //{value: undefined, done: true}
let array = [... createIterator()]; // [1, 2]
Generator - yield*
실행 도중 yield* expression 을 만나면 다른 generator 함수로 진행이 넘어가게 된다.
function* anotherGenerator(i) {
yield i + 1;
}
function* generator(i){
yield i;
yield* anotherGenerator(i*2);
yield i + 1;
}
var gen = generator(10);
console.log(gen.next().value); // 10
console.log(gen.next().value); // 21
console.log(gen.next().value); // 11
Generator - next()
next() 메서드를 인자 값과 함께 호출 하게 되면 진행이 멈췄던 부분의 yield 문을 next() 메서드에서 받은 인자로 치환하고 그 부분부터 다시 실행
function* logGenerator() {
console.log(yield "a"); // 나
console.log(yield "b"); // 다
}
var gen = logGenerator();
console.log(gen.next('가')); // {value: "a", done: false}
console.log(gen.next('나')); // {value: "b", done: false}
console.log(gen.next('다')); // {value: undefined, done: true}
// {value: "a", done: false}
// 나
// {value: "b", done: false}
// 다
// {value: undefined, done: true}
Generator - 비동기 작업
let task = taskDef(); // iterator 반환
let result = task.next();
step();
function step() {
if(!result.done) {
if(typeof result.value === "function") {
result.value(function(err,data) {
if(err) {
result = task.throw(err);
return;
}
result = task.next(data);
step();
});
} else {
result = task.next(result.value);
step();
}
}
}
ES5 - 클래스
function Person(name) {
this.name = name;
}
Person.prototype.sayName = function() {
console.log(this.name);
}
var person = new Person("Nicholas");
person.sayName(); // "Nicholas"
console.log(person instanceof Person); // true
console.log(person instanceof Object); // true
ES6 - 클래스
class Person {
constructor(name) {
this.name = name;
}
sayName() {
console.log(this.name);
}
}
let person = new Person("Nicholas");
person.sayName(); // "Nicholas"
console.log(person instanceof Person); // true
console.log(person instanceof Object); // true
console.log(typeof Person); // "function"
console.log(typeof Person.prototype.sayName); // "function"
first-class citizen
- 함수의 파라미터로 사용 가능
- 함수가 반환 가능
- 변수에 할당 가능
- JavaScript에서는 function, class도 first-class citizen임
function createObject(classDef) {
return new classDef();
}
let obj = createObject( class {
sayHi() {
console.log("Hi!");
}
});
obj.sayHi(); // "Hi!"
Generator method
class MyClass {
*createIterator() {
yield 1;
yield 2;
}
}
let instance = new MyClass();
let iterator = instance.createIterator();
iterator.next(); // {value: 2, done: false}
iterator.next(); // {value: 2, done: false}
computed property
let methodName = "sayName";
class Person {
constructor(name) {
this.name = name;
}
[methodName]() {
console.log(this.name);
}
}
let person = new Person("Nicholas");
person.sayName(); // "Nicholas"
static method
class Person {
constructor(name) {
this.name = name;
}
sayName() {
console.log(this.name);
}
static create(name) {
return new Person(name);
}
}
let person = Person.create("Nicholas");
person.sayName(); // "Nicholas"
derived class - extends
class Rectangle {
constructor(length, width) {
this.length = length;
this.width = width;
}
getArea() {
return this.length * this.width;
}
}
class Square extends Rectangle {
constructor(length) {
super(length, length);
}
}
var square = new Square(3);
console.log(square.getArea()); // 9
console.log(square instanceof Square); // true
console.log(square instanceof Rectangle); // true
super()
- 파생클래스 생성자에서만 사용 가능
- this 접근하기 전에 반드시 super() 호출해야 한다.
Array.of()
Array 생성자의 동작이 혼란스러워서 새로 추가된 함수
let items = new Array(2); // [undefined, undefined]
items = new Array("2"); // ["2"]
items = new Array(10, 20); // [10, 20]
items = Array.of(2); // [2]
console.log(items.length); // 1
console.log(items[0]); // 2
Array.from()
arguments와 같은 유사 Array를 Array로 변환하는 함수
function func1() {
var array = Array.from(arguments);
}
typed array
typed array(타입 배열)은 배열같은 객체이고 원시(raw) 이진 데이터에 액세스하기 위한 메커니즘을 제공. 숫자 타입과 동작하도록 설계됨
- Signed 8-bit integer (int8)
- Unsigned 8-bit integer (uint8)
- Signed 16-bit integer (int16)
- Unsigned 16-bit integer (uint16)
- Signed 32-bit integer (int32)
- Unsigned 32-bit integer (uint32)
- 32-bit float (float32)
- 64-bit float (float64)
Typed array views
var buffer = new ArrayBuffer(8);
var int8View = new Int8Array(buffer);
var int16View = new Int16Array(buffer);
var dataView = new DataView(buffer);
console.log(buffer.byteLength + " " + dataView.byteLength); // 8 8
console.log(int8View.length + " " + int16View.length); // 8 4
for (var i = 0; i < int16View.length; i++) {
int16View[i] = i * 2;
}
console.log(int8View); // Int8Array(8) [0, 0, 2, 0, 4, 0, 6, 0]
console.log(int16View); // Int16Array(8) [0, 2, 4, 6]
Typed array archtecture
Typed array과 일반 배열의 유사점
- 공통 메서드 : copyWith, entries, fill, filter, find, findIndex, forEach, indexOf, join, keys, lastIndexOf, map, reduce, reduceRight, reverse, slice, some, sort, values
- 동일한 이터레이터 : keys(), entries(), values() 메서드 제공
- of(), from() 메서드
Typed array과 일반 배열의 차이점
- Typed array는 크기가 고정
- 이용할 수 없는 메서드 : concat, pop, push, shift, splice, unshift
- 추가적인 메서드 : set, subarray
let ints = new Int16Array([25,50]);
console.log(ints instanceof Array); // false
console.log(Array.isArray(ints)); // false
Promise 기초
Promise 객체는 비동기 계산을 위해 사용된다. Promise는 아직은 아니지만 나중에 완료될 것으로 기대되는 연산을 표현한다. Promise는 다음 중 하나의상태를 가진다.
- 대기중(pending): 이행 또는 거부되지 않은 초기 상태
- 이행됨(fulfilled): 연산이 성공리에 완료되었음을 의미함
- 거부됨(rejected): 연산이 실패했음을 의미함
Promise 메소드
- Promise.all(iterable) : 모든 프로미스가 결정된 때 결정되며 하나의 프로미스라도 거부된 경우 즉시 거부하는 프로미스를 반환
- Promise.race(iterable) : 프로미스 중 하나를 결정 또는 거부하자마자 결정 또는 거부하는 프로미스를 반환
- Promise.reject(reason) : 거부된 Promise 객체를 반환
- Promise.resolve(value) : 결정된 Promise 객체를 반환
Promise prototype 메소드
- Promise.prototype.then(onFulfilled, onRejected) : then() 메서드는 Promise를 리턴하고 두개의 콜백 함수를 인수로 받는다.하나는 Promise가 성공(success)했을 때를 위한 콜백 함수이고, 다른 하나는 실패(failure)했을 때를 위한 콜백 함수이다.
- Promise.prototype.catch(onRejected) : Promise.prototype.then(undefined, onRejected)와 동일
Promise
var p1 = new Promise(function(resolve, reject) {
resolve("Success!");
// 또는
// reject ("Error!");
});
p1.then(function(value) {
console.log(value); // "Success!"
}, function(reason) {
console.log(reason); // "Error!"
});
Proxy
기정의된 기본적인 동작을 변경하는데 사용됨 (예: property lookup, assignment, enumeration, function invocation 등)
var handler = {
get: function(t, n){ return n in t? t[n] : 37; }
};
var o = {a : 1, b: undefined};
var p = new Proxy(o, handler);
console.log(p.a, p.b, 'c' in p, p.c); // 1, undefined, false, 37
console.log(o.a, o.b, 'c' in o, o.c); // 1, undefined, false, undefined
import, export
- import 문은 외부 모듈이나 다른 스크립트 등으로부터 export 된 기능을 가져오는데 사용된다.
- export 문은 지정된 파일(또는 모듈)에서 함수 또는 오브젝트, 원시 타입들을 export 하는데 사용된다.
// module "my-module.js"
export function cube(x) {
return x * x * x;
}
const foo = Math.PI + Math.SQRT2;
export { foo };
import { cube, foo } from 'my-module.js';
console.log(cube(3)); // 27
console.log(foo); // 4.555806215962888
-
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/codePointAt ↩
-
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/fromCodePoint ↩
-
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/normalize ↩
-
https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Operators/Spread_operator ↩
-
https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Functions/애로우_펑션 ↩
-
https://www.ecma-international.org/ecma-262/7.0/#sec-method-definitions ↩