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

다음 조건을 만족할 때 새로운 호출 스택을 사용하지 않고 현재 스택을 재활용. 재귀함수 사용시 성능 개선에 도움이 됨

  1. strict 모드
  2. 클로저가 아닌 경우
  3. tail call의 결과를 즉시 반환
  4. 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
kimwooglae's profile image

kimwooglae

2018-02-24 19:10

Read more posts by this author