Created
April 23, 2017 04:29
-
-
Save oiehot/0dba47e9e140a87964d760468097fc86 to your computer and use it in GitHub Desktop.
ES6 Features
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// ES6 Features | |
// | |
// 원본: http://es6-features.org | |
// | |
// 1. 상수 | |
// ======= | |
const PI = 3.141593 | |
PI = 1.0 // Error | |
// 2. 범위 | |
// ======= | |
// 블럭 범위 변수 | |
a = [0,1,2,3,4,5] | |
for (let i=0; i<a.length; i++) { | |
let x = a[i] | |
} | |
// 블럭 범위 함수 | |
{ | |
function foo() { return 1; } | |
if (foo() === 1) { | |
function foo() { return 2; } | |
if (foo() === 2) { console.log("Goal") } | |
} | |
} | |
// 3. 화살표 함수 | |
// ============= | |
evens = [2,4,6,8,10,12] | |
odds = evens.map(v => v + 1) | |
pairs = evens.map(v => ({ | |
even: v, | |
odd: v + 1 | |
})) | |
nums = evens.map( | |
(v,i) => v + i | |
); | |
// ---- | |
let nums = [0,1,5,9,10,14,15,19,20,25] | |
let fives = [] | |
nums.forEach(v => { | |
if (v % 5 === 0) { | |
fives.push(v) | |
} | |
}); | |
// 4. 매개변수 | |
// ========== | |
// 기본 매개변수 값 | |
function f (x,y = 7, z = 42) { | |
return x + y + z | |
} | |
f(1) === 50 | |
// 나머지 매개변수 | |
function f (x, y, ...a) { | |
return (x+y) * a.length | |
} | |
// 스프레드 연산자 | |
var params = ["hello", true, 7] | |
var other = [1, 2, ...params] // Append | |
// 5. 템플릿 리터럴 | |
// =============== | |
var name = { firstName: "Taewoo", lastName: "Lee" } | |
var fullName = `${name.firstName} ${name.lastName}` | |
// ---- | |
let bar = "bar" | |
let baz = "baz" | |
let quux = "quux" | |
console.log( `http://example.com/foo?bar=${bar + baz}&quux=${quux}` ) | |
// Raw 문자열 읽기 | |
function quux (strings, ...values) { | |
console.log( strings[0] === "foo\n" ) // true | |
console.log( strings[1] === "bar" ) // true | |
console.log( strings.raw[0] === "foo\\n" ) // true | |
console.log( strings.raw[1] === "bar" ) // true | |
console.log( values[0] === 42 ) // true | |
} | |
quux `foo\n${ 42 }bar` | |
String.raw `foo\n${ 42 }bar` === "foo\\n42bar" | |
// 6. 확장된 리터럴 | |
// =============== | |
// 2진, 8진 리터럴 | |
0b111110111 == 503 | |
0o767 == 503 | |
// 유니코드 | |
"𠮷".length === 2 | |
"𠮷".match(/./u)[0].length === 2 | |
"𠮷" === "\uD842\uDFB7" | |
"𠮷" === "\u{20BB7}" | |
"𠮷".codePointAt(0) == 0x20BB7 | |
for (let codepoint of "𠮷") console.log(codepoint) | |
// 7. 정규표현식 | |
// ============ | |
let parser = (input, match) => { | |
for (let pos = 0, lastPos = input.length; pos < lastPos; ) { | |
for (let i = 0; i < match.length; i++) { | |
match[i].pattern.lastIndex = pos | |
let found | |
if ((found = match[i].pattern.exec(input)) !== null) { | |
match[i].action(found) | |
pos = match[i].pattern.lastIndex | |
break | |
} | |
} | |
} | |
} | |
let report = (match) => { | |
console.log(JSON.stringify(match)) | |
} | |
parser("Foo 1 Bar 7 Baz 42", [ | |
{ pattern: /^Foo\s+(\d+)/y, action: (match) => report(match) }, | |
{ pattern: /^Bar\s+(\d+)/y, action: (match) => report(match) }, | |
{ pattern: /^Baz\s+(\d+)/y, action: (match) => report(match) }, | |
{ pattern: /^\s*/y, action: (match) => {} } | |
]) | |
// 8. 객체 프로퍼티 | |
// =============== | |
// 프로퍼티 단축 | |
obj = { x, y } | |
// 프로퍼티 이름 | |
let obj = { | |
foo: "bar", | |
[ "baz" + quux() ]: 42 | |
} | |
obj[ "baz" + quux() ] = 42; | |
// 메소드 프로퍼티 | |
obj = { | |
foo (a, b) { | |
// ... | |
}, | |
bar (x, y) { | |
// ... | |
}, | |
*quux (x, y) { | |
// ... | |
} | |
} | |
// 9. 객체와 배열의 매칭 | |
// ==================== | |
// 배열 매칭 | |
var list = [1, 2, 3] | |
var [a, ,b] = list | |
console.log(`${a} ${b}`) // 1 3 | |
[b,a] = [a,b] | |
console.log(`${a} ${b}`) // 3 1 | |
var list = [ 7, 42 ] | |
var [ a=1, b=2, c=3, d ] = list | |
console.log( a === 7 ) | |
console.log( b === 42 ) | |
console.log( c === 3 ) | |
console.log( d === undefined ) | |
// 오브젝트 매칭 | |
var { op, lhs, rhs } = getASTNode() | |
var tmp = getASTNode() | |
var op = tmp.op | |
var lhs = tmp.lhs | |
var rhs = tmp.rhs | |
var { op: a, lhs: { op: b }, rhs: c } = getASTNode() | |
var tmp = getASTNode() | |
var a = tmp.op | |
var b = tmp.lhs.op | |
var c = tmp.rhs | |
// 매칭시 기본값 | |
var obj = { a: 1 } | |
var list = [ 1 ] | |
var { a, b = 2 } = obj // a===1, b===2 | |
var [ x, y = 2 ] = list // x===1, y===2 | |
// 매개변수로 사용 | |
function f ([ name, val ]) { console.log(name, val) } | |
function g ({ name: n, val: v }) { console.log(n, v) } | |
function h ({ name, val }) { console.log(name, val) } | |
f([ "bar", 42 ]) | |
g({ name: "foo", val: 7 }) | |
h({ name: "bar", val: 42 }) | |
// 10. 모듈 | |
// ======== | |
// 추출하기와 가져오기 | |
/* lib/math.js */ | |
export function sum (x, y) { return x + y } | |
export var pi = 3.141593 | |
/* someApp.js */ | |
import * as math from "lib/math" | |
console.log("2π = " + math.sum(math.pi, math.pi)) | |
/* otherApp.js */ | |
import { sum, pi } from "lib/math" | |
console.log("2π = " + sum(pi, pi)) | |
// default 와 *(wildcard) | |
/* lib/mathplusplus.js */ | |
export * from "lib/math" | |
export var e = 2.71828182846 | |
export default (x) => Math.exp(x) | |
/* someApp.js */ | |
import exp, { pi, e } from "lib/mathplusplus" | |
console.log("e^{π} = " + exp(pi)) | |
// 11. 클래스 | |
// ========== | |
// 클래스 정의 | |
class Shape { | |
constructor (id, x, y) { | |
this.id = id | |
this.move(x, y) | |
} | |
move (x, y) { | |
this.x = x | |
this.y = y | |
} | |
} | |
// 클래스 상속 | |
class Rectangle extends Shape { | |
constructor (id, x, y, width, height) { | |
super(id, x, y) | |
this.width = width | |
this.height = height | |
} | |
} | |
class Circle extends Shape { | |
constructor (id, x, y, radius) { | |
super(id, x, y) | |
this.radius = radius | |
} | |
} | |
// 믹스인 [TODO] | |
var aggregation = (baseClass, ...mixins) => { | |
let base = class _Combined extends baseClass { | |
constructor (...args) { | |
super(...args) | |
mixins.forEach((mixin) => { | |
mixin.prototype.initializer.call(this) | |
}) | |
} | |
} | |
let copyProps = (target, source) => { | |
Object.getOwnPropertyNames(source) | |
.concat(Object.getOwnPropertySymbols(source)) | |
.forEach((prop) => { | |
if (prop.match(/^(?:constructor|prototype|arguments|caller|name|bind|call|apply|toString|length)$/)) | |
return | |
Object.defineProperty(target, prop, Object.getOwnPropertyDescriptor(source, prop)) | |
}) | |
} | |
mixins.forEach((mixin) => { | |
copyProps(base.prototype, mixin.prototype) | |
copyProps(base, mixin) | |
}) | |
return base | |
} | |
class Colored { | |
initializer () { this._color = "white" } | |
get color () { return this._color } | |
set color (v) { this._color = v } | |
} | |
class ZCoord { | |
initializer () { this._z = 0 } | |
get z () { return this._z } | |
set z (v) { this._z = v } | |
} | |
class Shape { | |
constructor (x, y) { this._x = x; this._y = y } | |
get x () { return this._x } | |
set x (v) { this._x = v } | |
get y () { return this._y } | |
set y (v) { this._y = v } | |
} | |
class Rectangle extends aggregation(Shape, Colored, ZCoord) {} | |
var rect = new Rectangle(7, 42) | |
rect.z = 1000 | |
rect.color = "red" | |
console.log(rect.x, rect.y, rect.z, rect.color) | |
// 부모 클래스의 메소드 접근 | |
class Shape { | |
// ... | |
toString() { | |
return `Shape(${this.id})` | |
} | |
} | |
class Rectangle extends Shape { | |
constructor (id, x, y, width, height) { | |
super(id, x, y) | |
} | |
toString() { | |
return "Rectangle > " + super.toString() | |
} | |
} | |
class Circle extends Shape { | |
constructor (id, x, y, radius) { | |
super(id, x, y) | |
// ... | |
} | |
toString() { | |
return "Circle >" + super.toString() | |
} | |
} | |
// 정적 멤버 | |
class Rectangle extends Shape { | |
// ... | |
static defaultRectangle () { | |
return new Rectangle("default", 0, 0, 100, 100) | |
} | |
} | |
class Circle extends Shape { | |
// ... | |
static defaultCircle () { | |
return new Circle("default", 0, 0, 100) | |
} | |
} | |
var defRectangle = Rectangle.defaultRectangle() | |
var defCircle = Circle.defaultCircle() | |
// Getter/Setter | |
class Rectangle { | |
constructor (width, height) { | |
this._width = width | |
this._height = height | |
} | |
set width (width) { | |
this._width = width | |
} | |
get width () { | |
return this._width | |
} | |
set height (height) { | |
this._height = height | |
} | |
get height () { | |
return this._height | |
} | |
get area () { | |
return this._width * this._height | |
} | |
} | |
var r = new Rectangle(50, 20) | |
console.log( r.area ) // 1000 | |
// 12. 심볼 | |
// ======== | |
// 심볼 | |
Symbol("foo") !== Symbol("foo") | |
const foo = Symbol() | |
const bar = Symbol() | |
typeof foo === "symbol" | |
typeof bar === "symbol" | |
let obj = {} | |
obj[foo] = "foo" | |
obj[bar] = "bar" | |
JSON.stringify(obj) // {} | |
Object.keys(obj) // [] | |
Object.getOwnPropertyNames(obj) // [] | |
Object.getOwnPropertySymbols(obj) // [ foo, bar ] | |
// 글로벌 심볼 | |
Symbol.for("app.foo") === Symbol.for("app.foo") | |
const foo = Symbol.for("app.foo") | |
const bar = Symbol.for("app.bar") | |
Symbol.keyFor(foo) === "app.foo" | |
Symbol.keyFor(bar) === "app.bar" | |
typeof foo === "symbol" | |
typeof bar === "symbol" | |
let obj = {} | |
obj[foo] = "foo" | |
obj[bar] = "bar" | |
JSON.stringify(obj) // {} | |
Object.keys(obj) // [] | |
Object.getOwnPropertyNames(obj) // [] | |
Object.getOwnPropertySymbols(obj) // [ foo, bar ] | |
// 13. 이터레이터 [TODO] | |
// ==================== | |
let fibonacci = { | |
[Symbol.iterator]() { | |
let pre = 0, cur = 1 | |
return { | |
next () { | |
[ pre, cur ] = [cur, pre + cur ] | |
return { done: false, value: cur } | |
} | |
} | |
} | |
} | |
// 14. 제네레이터 | |
// ============= | |
// Generator Function, Iterator Protocol [TODO] | |
let fibonacci = { | |
*[Symbol.iterator]() { | |
let pre = 0, cur = 1 | |
for (;;) { | |
[ pre, cur ] = [ cur, pre + cur ] | |
yield cur | |
} | |
} | |
} | |
for (let n of fibonacci) { | |
if (n > 1000) | |
break | |
console.log(n) | |
} | |
// Generator Function, Direct Use [TODO] | |
function* range (start, end, step) { | |
while (start < end) { | |
yield start | |
start += step | |
} | |
} | |
for (let i of range(0, 10, 2)) { | |
console.log(i) // 0, 2, 4, 6, 8 | |
} | |
// Generator Matching [TODO] | |
let fibonacci = function* (numbers) { | |
let pre = 0, cur = 1 | |
while (numbers-- > 0) { | |
[ pre, cur ] = [ cur, pre + cur ] | |
yield cur | |
} | |
} | |
for (let n of fibonacci(1000)) | |
console.log(n) | |
let numbers = [ ...fibonacci(1000) ] | |
let [ n1, n2, n3, ...others ] = fibonacci(1000) | |
// 14-4. Generator Control-Flow [TODO] | |
// generic asynchronous control-flow driver | |
function async (proc, ...params) { | |
var iterator = proc(...params) | |
return new Promise((resolve, reject) => { | |
let loop = (value) => { | |
let result | |
try { | |
result = iterator.next(value) | |
} | |
catch (err) { | |
reject(err) | |
} | |
if (result.done) | |
resolve(result.value) | |
else if ( typeof result.value === "object" | |
&& typeof result.value.then === "function") | |
result.value.then((value) => { | |
loop(value) | |
}, (err) => { | |
reject(err) | |
}) | |
else | |
loop(result.value) | |
} | |
loop() | |
}) | |
} | |
// application-specific asynchronous builder | |
function makeAsync (text, after) { | |
return new Promise((resolve, reject) => { | |
setTimeout(() => resolve(text), after) | |
}) | |
} | |
// application-specific asynchronous procedure | |
async(function* (greeting) { | |
let foo = yield makeAsync("foo", 300) | |
let bar = yield makeAsync("bar", 200) | |
let baz = yield makeAsync("baz", 100) | |
return `${greeting} ${foo} ${bar} ${baz}` | |
}, "Hello").then((msg) => { | |
console.log("RESULT:", msg) // "Hello foo bar baz" | |
}) | |
// Generator Methods | |
class Clz { | |
* bar () { | |
… | |
} | |
} | |
let Obj = { | |
* foo () { | |
… | |
} | |
} | |
// 15. 맵과 집합 | |
// ============ | |
// 집합 | |
let s = new Set() | |
s.add("hello").add("goodbyte").add("hellow") | |
s.size === 2 | |
s.has("hello") === true | |
for (let key of s.values()) { | |
console.log(key) | |
} | |
// 맵 | |
let m = new Map() | |
m.set("hello", 42) | |
m.set(s, 34) | |
m.get(s) === 34 | |
m.size === 2 | |
for (let [ key, val ] of m.entries()) { | |
console.log(key + " = " + val) | |
} | |
// WeakSet & WeakMap | |
let isMarked = new WeakSet() | |
let attachedData = new WeakMap() | |
export class Node { | |
constructor (id) { | |
this.id = id | |
} | |
mark () { | |
isMarked.add(this) | |
} | |
unmark () { | |
isMarked.delete(this) | |
} | |
marked () { | |
return isMarked.has(this) | |
} | |
set data (data) { | |
attachedData.set(this, data) | |
} | |
get data () { | |
return attachedData.get(this) | |
} | |
} | |
let foo = new Node("foo") | |
JSON.stringify(foo) === '{"id":"foo"}' | |
foo.mark() | |
foo.data = "bar" | |
foo.data === "bar" | |
JSON.stringify(foo) === '{"id":"foo"}' | |
isMarked.has(foo) === true | |
attachedData.has(foo) === true | |
foo = null | |
attachedData.has(foo) === false | |
isMarked.has(foo) === false | |
// 16. byte 기반 자료 구조 | |
// ====================== | |
class Example { | |
constructor (buffer = new ArrayBuffer(24)) { | |
this.buffer = buffer | |
} | |
set buffer (buffer) { | |
this._buffer = buffer | |
this._id = new Uint32Array (this._buffer, 0, 1) | |
this._username = new Uint8Array (this._buffer, 4, 16) | |
this._amountDue = new Float32Array(this._buffer, 20, 1) | |
} | |
get buffer () { return this._buffer } | |
set id (v) { this._id[0] = v } | |
get id () { return this._id[0] } | |
set username (v) { this._username[0] = v } | |
get username () { return this._username[0] } | |
set amountDue (v) { this._amountDue[0] = v } | |
get amountDue () { return this._amountDue[0] } | |
} | |
let example = new Example() | |
example.id = 7 | |
example.username = "John Doe" | |
example.amountDue = 42.0 | |
// 17. 새로운 빌트인 메소드 | |
// ====================== | |
// Object.assign() | |
var dst = { quux: 0 } | |
var src1 = { foo: 1, bar: 2 } | |
var src2 = { foo: 3, baz: 4 } | |
Object.assign(dst, src1, src2) | |
console.log(dst) // { quux:0, foo: 3, bar: 2, bax: 4 } | |
// 배열에서 항목 찾기 | |
[ 1, 3, 4, 2 ].find(x => x > 3) // 4 | |
// 문자열 반복 | |
" ".repeat(4) | |
"foo".repeat(3) | |
// 문자열 검색 | |
"hello".startsWith("ello", 1) // true | |
"hello".endsWith("hell", 4) // true | |
"hello".includes("ell") // true | |
"hello".includes("ell", 1) // true | |
"hello".includes("ell", 2) // false | |
// 숫자 검사 | |
Number.isNaN(42) === false | |
Number.isNaN(NaN) === true | |
Number.isFinite(Infinity) === false | |
Number.isFinite(-Infinity) === false | |
Number.isFinite(NaN) === false | |
Number.isFinite(123) === true | |
// 숫자 안정성 검사 | |
Number.isSafeInteger(42) === true | |
Number.isSafeInteger(9007199254740992) === false | |
// 숫자 비교 | |
console.log(0.1 + 0.2 === 0.3) // false | |
console.log(Math.abs((0.1 + 0.2) - 0.3) < Number.EPSILON) // true | |
// 반올림/반내림 | |
console.log(Math.trunc(42.7)) // 42 | |
console.log(Math.trunc( 0.1)) // 0 | |
console.log(Math.trunc(-0.1)) // -0 | |
// 숫자 부호 | |
console.log(Math.sign(7)) // 1 | |
console.log(Math.sign(0)) // 0 | |
console.log(Math.sign(-0)) // -0 | |
console.log(Math.sign)-7)) // -1 | |
console.log(Math.sign(NaN)) // NaN | |
// 18. 프로마이즈 [TODO] | |
// ==================== | |
// 프로마이즈 사용 | |
function msgAfterTimeout (msg, timeout) { | |
return new Promise((resolve, reject) => { | |
setTimeout(() => resolve(msg), timeout) | |
}) | |
} | |
msgAfterTimeout("", "Foo", 100).then((msg) => | |
msgAfterTimeout(msg, "Bar", 200) | |
).then((msg) => { | |
console.log(`done after 300ms:${msg}`) | |
}) | |
// 프로마이즈 조합 | |
function fetchAsync (url, timeout, onData, onError) { | |
// … | |
} | |
let fetchPromised = (url, timeout) => { | |
return new Promise((resolve, reject) => { | |
fetchAsync(url, timeout, resolve, reject) | |
}) | |
} | |
Promise.all([ | |
fetchPromised("http://backend/foo.txt", 500), | |
fetchPromised("http://backend/bar.txt", 500), | |
fetchPromised("http://backend/baz.txt", 500) | |
]).then((data) => { | |
let [ foo, bar, baz ] = data | |
console.log(`success: foo=${foo} bar=${bar} baz=${baz}`) | |
}, (err) => { | |
console.log(`error: ${err}`) | |
}) | |
// 19. 메타 프로그래밍 | |
// ================== | |
// 프록시 | |
let target = { | |
foo: "Welcome, foo" | |
} | |
let proxy = new Proxy(target, { | |
get (receiver, name) { | |
return name in receiver ? receiver[name] : `Hello, ${name}` | |
} | |
}) | |
proxy.foo === "Welcome, foo" | |
proxy.world === "Hello, world" | |
// 리플렉션 | |
let obj = { a: 1 } | |
Object.defineProperty(obj, "b", { value: 2 }) | |
obj[Symbol("c")] = 3 | |
Reflect.ownKeys(obj) // [ "a", "b", Symbol(c) ] | |
// 20. 국제화와 지역화 | |
// ================= | |
// Collation | |
// in German, "ä" sorts with "a" | |
// in Swedish, "ä" sorts after "z" | |
var list = [ "ä", "a", "z" ] | |
var l10nDE = new Intl.Collator("de") | |
var l10nSV = new Intl.Collator("sv") | |
l10nDE.compare("ä", "z") === -1 | |
l10nSV.compare("ä", "z") === +1 | |
console.log(list.sort(l10nDE.compare)) // [ "a", "ä", "z" ] | |
console.log(list.sort(l10nSV.compare)) // [ "a", "z", "ä" ] | |
// 숫자 형식 | |
var l10nEN = new Intl.NumberFormat("en-US") | |
var l10nDE = new Intl.NumberFormat("de-DE") | |
l10nEN.format(1234567.89) === "1,234,567.89" | |
l10nDE.format(1234567.89) === "1.234.567,89" | |
// 통화 형식 | |
var l10nUSD = new Intl.NumberFormat("en-US", { style: "currency", currency: "USD" }) | |
var l10nGBP = new Intl.NumberFormat("en-GB", { style: "currency", currency: "GBP" }) | |
var l10nEUR = new Intl.NumberFormat("de-DE", { style: "currency", currency: "EUR" }) | |
l10nUSD.format(100200300.40) === "$100,200,300.40" | |
l10nGBP.format(100200300.40) === "£100,200,300.40" | |
l10nEUR.format(100200300.40) === "100.200.300,40 €" | |
// 날짜-시간 형식 | |
var l10nEN = new Intl.DateTimeFormat("en-US") | |
var l10nDE = new Intl.DateTimeFormat("de-DE") | |
l10nEN.format(new Date("2015-01-02")) === "1/2/2015" | |
l10nDE.format(new Date("2015-01-02")) === "2.1.2015" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment