DevFest WebTech CodeLab

DevFest WebTech CodeLab

ES6 & ES7

classes

  • JS에 새로운 Object Oriented Pattern을 제시한 건 아님에 주의
    • 사실 함수
    • 그러나 Function declaration처럼 hoisted되지 않음
어떻게 사용할 수 있나요?
class 선언
1
2
3
4
5
6
class Rectangle {
constructor(height, width) {
this.height = height;
this.width = width;
}
}
class 표현식
  • 이름을 가질 수도 있고, 갖지 않을 수도 있다

  • 이름을 가진 class 표현식의 이름은 클래스의 body에 대해 local scope에 한해 유효

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    // unnamed
    let Rectangle = class {
    constructor(height, width) {
    this.height = height;
    this.width = width;
    }
    };

    console.log(Rectangle.name);
    //output : "Rectangle"

    // named
    let Rectangle = class Rectangle2 {
    constructor(height, width) {
    this.height = height;
    this.width = width;
    }
    };

    console.log(Rectangle.name);
    //output: "Rectangle2"
예시
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class nameOfClass extends existingClass {
constructor() {
// ...
}

someFunction() {
// ...
}

get someVariable() {
// ...
}

set someVariable(variable) {
// ...
}

static someStaticFunction() {
// ...
}
}
  • new 생성자가 하나의 객체를 만드는 것이 아니라 연결된 무언가를 만드는 것이라 이해해야 한다
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
class GDGEvent {
constructor(eventName, eventDate) {
this.eventName = eventName
this.eventDate = eventDate
}

updateEvent(eventName, eventDate) {
// ...
}
}

class GDGWebTechEvent extends GDGEvent {
constructor(eventName, eventDate, focusingTopic) {
super(eventName, eventDate)
this.focusingTopic = focusingTopic
this.eventPlace = GDGWebTechEvent.defaultEventPlace()
}

updateEvent(eventName, eventDate, focusingTopic) {
// do something with focusingTopic
super.updateEvent(eventName, eventDate)
}

get eventInformation() {
return `${this.eventName} will be held at ${this.eventDate} focusing on ${this.focusingTopic}`
}

static defaultEventPlace() {
return 'Google for Startups located in Seoul, Korea'
}
}

const devFestWebTech2019 = new GDGWebTechEvent(
'DevFest WebTech', '21 Nov 2019', 'web technologies'
)
console.log(devFestWebTech2019.eventInformation)
// 'DevFest WebTech will be held at 21 Nov 2019 focusing on web technologies'

array API

Array.from()

  • 유사 배열 객체나 순회 가능 객체를 복사해 새로운 배열을 만드는 메서드
    • 유사 배열 객체
      • length 속성과 인덱싱된 요소를 가진 객체
    • 순회 가능 객체
      • map, set 등 객체의 요소를 얻을 수 있는 객체
1
2
Array.from('foo'); 
// ["f", "o", "o"]
1
2
3
const s = new Set(['foo', window]); 
Array.from(s);
// ["foo", window]

Array.of()

인자의 수나 유형에 관계없이 가변 인자를 갖는 새 Array 인스턴스를 생성

1
2
Array.of(7);       // [7] 
Array.of(1, 2, 3); // [1, 2, 3]

Array.fill()

1
2
3
4
5
6
7
8
9
10
11
12
13
const array1 = [1, 2, 3, 4];

// 2번 째 인덱스부터 4-1번째 인덱스까지 0으로 채우기
console.log(array1.fill(0, 2, 4));
// expected output: [1, 2, 0, 0]

// 1번 째 인덱스부터 5로 채우기
console.log(array1.fill(5, 1));
// expected output: [1, 5, 5, 5]

// 모든 배열을 6으로 채우기
console.log(array1.fill(6));
// expected output: [6, 6, 6, 6]

Array.includes

기존의 indexOf 는 특정 요소가 있는지 검사하고 0 또는 1을 반환했지만, includes는 동일하게 요소를 검사하고 boolean을 반환

1
2
[1, 2, 3].includes(-1)                   // false
[1, 2, 3].includes(1) // true

**

수를 제곱

1
2
3
4
5
// 5의 세제곱을 구할때 기존의 방법
Math.pow(5, 3)

// 이제는 operand ** operand 이렇게 사용할 수 있어요
5 ** 3 // 125

ES8 & ES9

Object entries, values

Object의 enumerable property pair를 꺼내오거나 value만 배열로 꺼내올 수 있다

1
2
3
4
5
6
7
8
9
10
11
12
13
// Object.entries()
const obj = { eventName: 'DevFest WebTech', eventPlace: 'Google for Startups' }
console.log(Object.entries(obj))
// [ ['eventName', 'DevFest WebTech'], ['eventPlace', 'Google for Startups'] ]

// Object.values()
const obj = { foo: 'foo', bar: [100, 200], baz: 55 }
console.log(Object.values(obj))
// ['foo', [100, 200], 55 ]

const myStr = 'Lufthansa'
console.log(Object.values(myStr))
// ["L", "u", "f", "t", "h", "a", "n", "s", "a"]

ES10

Array flat & flatMap

Array에 배열의 배열을 flat 시킬 수 있는 conversion helper가 추가

1
2
3
4
5
6
7
8
9
10
11
// Array flat
let arr = ['a', 'b', ['c', 'd']]
let flattened = arr.flat()
console.log(flattened) // ["a", "b", "c", "d"]

// Array flatMap
const arr = [4.25, 19.99, 25.5]
console.log(arr.map((value) => [Math.round(value)]))
// [[4], [20], [26]]
console.log(arr.flatMap((value) => [Math.round(value)]))
// [4, 20, 26]

Object fromEntries

Object의 entries()가 리터럴 객체의 property pair를 배열로 가져올 수 있는 반면, 반대로 그 배열로 리터럴 객체로 만들 수 있는 함수

1
2
3
4
const myArray = [['one', 1], ['two', 2], ['three', 3]]
const obj = Object.fromEntries(myArray)

console.log(obj) // {one: 1, two: 2, three: 3}

RxJS의 주요 개념

Observable

Observable

시간을 축으로 연속적인 데이터를 저장하고 있는 객체

검색 기능을 만든다고 가정할 때, input에 유저가 검색어를 입력하기 시작하면 입력한 순서대로(ㄱ, ㅏ, ㄴ, ㅏ) 데이터가 넘어간다. 해당 객체는 이렇게 시간순으로 오는 데이터를 의미

Operator

Observable이 변화하는 데이터 흐름 사이특정한 작업을 해야만 할 때 사용

Observable을 만들어내기도 함.

Operator는 Observable을 받아 어떤 작업을 하고 새로운 Observable을 넘기고, 또 다른 다음 Operator가 받는 식

Observer

가공된 데이터를 활용하는 역할

next, error, complete 함수를 프로퍼티로 갖는 객체

1
observableInstance.subscribe(Observer)

이렇게 subscribe 함수 안에 넣어주면 데이터를 꺼냄

Subscription

데이터를 활용하지 않아 사용한 메모리 자원을 다시 반환해야 할 때 사용할 객체

1
subscription.unsubscribe()

Observable 인스턴스의 subscribe 함수는 subscription 객체를 반환

예제

함수들은 rxjs/operator 안에 있다

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
const inputStream = fromEvent(searchInput, 'input')
// fromEvent
// DOM EventTarget과 이 타겟에서 데이터로 삼을 이벤트명을 인자로 받고
// 그 이벤트명의 이벤트를 데이터 스트림으로 표현하는 Observable 객체를 반환
.pipe(
// 새로운 Observable 객체를 반환
// 데이터 스트림이 어떻게 변화하는지를 모두 표현하고 있는 새로운 Observable 객체가 할당
// 데이터가 흐르기 시작
map((event) => event.target.value),
debounceTime(1000),
// 1초 동안 아무런 이벤트가 발생하지 않았을 때, 최종적으로 발생한 이벤트만을 대상으로 호출
distinctUntilChanged(),
// 만약 같은 데이터가 들어왔다면
// 해당 이벤트를 무시하며 흐름을 중지한다
tap(() => recipeList.innerHTML = '<h3>Loading...</h3>'),
// 도착한 데이터에 어떠한 변경도 하지 않음
// 데이터와 무관한 활동을 해야할 때 사용
switchMap((inputValue) =>
// 옵져버블 안에 있는 값을 꺼내야 할 경우
// 중첩 파이프라인의 값을 가져옴
// 팬딩된 요청에 대해서는 무시. 왜냐하면 유저 입장에서는 첫 요청보단 두 번째 요청을 먼저 실행하길 원하므로
// 파이프라인 두 개를 합치는 역할

// 프로미스를 리턴하지 않음
ajax(`${apiEndPoint}?f=${inputValue}`, { method: 'GET' })
.pipe(
// 새로운 파이프 라인 시작
map(({ response }) => response ? response.meals : []),
),
),
)
)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
inputStream.subscribe({
next: (meals) => {
// 받고 나서 할 일
recipeList.innerHTML = meals
.map((meal) => new Meal(meal))
.map((mealInstance) => mealInstance.renderToString())
.join('')
},
error: () => {
// 데이터 스트림 과정에 에러가 있을때 호출
recipeList.innerHTML = '<h3>An error has occurred when fetching data...</h3>'
},
})
// complete는 Observable의 구독이 완료되었을때 호출