-
ES6 기초와 함수형 자바스크립트 코드 예제Javascript 2017. 3. 19. 20:17
ES 6 의 새로운 문법과 함수형 자바스크립트에 대한 코드 예제
함수형 자바스크립트를 작성하는 법에 대해서 일반적으로 쓰는 OOP 개념의 코드와 다른 점을
예제 코드로 적어보겠습니다.
* 본 글은 유튜브 https://youtu.be/HvMemAgOw6I 를 바탕으로 작성되었습니다.
> ES6 의 배열인자
const array = (...elements) => { return elements; }; array(1,2,3); // [1, 2, 3] const log = (...args) => { console.log(...args); } log('hello', 'Seoul'); // hello Seoul
* const : es6 의 새로운 문법으로 const 로 선언된 값은 외부에서 직접적으로 변경할 수 없습니다.
* arrow function : () => {} 로 실행하며 () 의 값은 인자로 받고 , {} 은 함수의 실행구문을 넣습니다.
ex) function( value ) { return value } === ( value ) => { return value }
코드 설명
1) const 로 선언된 array 는 (...elements) 인자를 받아서 elements 를 리턴합니다.
* ...elements 에서 앞에 붙은 ... 은 인자를 강제적으로 배열로 받는 다는 뜻 입니다.
2) array(1, 2, 3) 으로 array 함수를 실행 했다면 결과값은 배열로 변경되어 [1, 2, 3] 이 됩니다.
3) 마찬가지로 const 로 선언된 log 는 ...args 를 인자로 받게됩니다.
4) log 함수를 실행하면 'hello' , 'Seoul' 이 배열로 변경되어 출력되는 것을 확인 할 수 있습니다.
> ES6 의 배열식으로 변수선언
const langs = ['JavaScript', 'Ruby', 'Haskell']; const [js, ...rest] = langs; js === 'JavaScript' rest[0] === 'Ruby'; rest[1] === 'Haskell'; const head = ([x]) => x; head([1,2,3]) === 1;
이번엔 변수 선언을 배열처럼 하는 문법입니다.
1) const langs 는 일반적인 배열을 선언하였고 내부에는 'JavaScript', 'Ruby', 'Haskell' 을 배열로 선언하였습니다.
2) const [js, ...rest] = langs; 에서 변수 역시 배열처럼 선언하여 js 변수에는 langs 의 첫번째 값인
'JavaScript' 가 들어가고 ...rest 에는 앞서 배운듯이 나머지 값들이 배열형식으로 들어갑니다.
3) const head 에서는 함수의 인자로 배열내부의 x 값을 받아 리턴하게 되었습니다.
4) head([1,2,3]) 을 실행하면 인자로 배열의 값을 하나만 받기 때문에 1 이 결과로 나오게 됩니다.
> ES6 함수의 인자로 기본값 선언
const greet = (name, greeting = 'Hi') => { console.log(greeting, name); } greet('Seoul', 'Hello'); // Hello Seoul greet('Alex'); // H1 Alex
이번엔 함수의 인자값에 기본값을 설정할 수 있는 문법입니다.
1) const greate 는 name, 과 greeting 를 인자로 받는 함수로서 , 결과값으로
greeting , name 순으로 log 를 출력합니다.
여기서 greeting = 'HI' 를 사용해 두번 째 인자값이 존재하지 않으면
greeting 은 자동으로 'HI' 가 들어가게 됩니다.
2) greet('Seoul', 'Hello') 실행 결과와 greet('Alex') 실형결과를 보면 인자의 기본값이 적용된 것을
확인 할 수 있습니다.
> ES6 Object Merge
Object.assign( {}, { hello: 'Alex'}, { hi: 'Scenic City Summit'} ); // { // hello: 'Alex // hi: 'Scenic City Summit // }
이번엔 굉장히 유용한 Object Assign 문법입니다.
1) Object.assign 명령은 다수의 Object 를 하나로 묶어주는 역활을 합니다.
2) Object.assign ( 대상오브젝트 , ... 추가,병합할 오브젝트) 형식으로 사용됩니다.
3) 위 코드에서는 {} 빈 객체에 두개의 객체 를 병합하여 하나의 객체로 결과가 나오게 되었습니다.
* 주의 할 점은 Object.assign 은 대상오브젝트에 오브젝트를 병합할때 병합되는 오브젝트의 참조를 복사하게 됩니다.
병합되어진 객체의 값을 변경하면 병합당한 객체의 값도 같이 변하게 됩니다.
> ES6 Class
class Point { constructor(x, y) { this.x = x; this.y = y; } moveBy(dx,dy) { this.x += dx; this.y += dy; } } // function Point(x, y) { this.x = x; this.y = y; } Point.prototype.moveBy = function(dx,dy) { this.x += dx; this.y += dy; }
기존 언어에서 볼 수 있었던 class 가 도입되었습니다.
1) class Point 는 생성자를 가지고 있고 moveBy 라는 함수 역시 포함하고 있습니다.
2) 이를 기존 자바스크립토 변경해보면 Point 라는 함수와 Point 의 프로토타입으로 moveBy 를 설정 해 둔 것과
같은 것을 볼 수 있습니다.
>> 함수형 자바스크립트
PURE 함수를 작성합니다.
같은 값을 넣으면 언제나 같은 결과가 나와야 합니다.
간단한 예
const add = (x,y) => x + y; add(2, 3) === 5;
여기서 add(2, 3) 을 실행하면 나오는 값은 5 라는 것을 누구나 예측할 수 있고 변하지 않습니다.
이것이 순수함수 입니다.
해당 함수의 결과를 예측 할 수 있고, 테스트 하기 쉽습니다.
그럼 잘못된 예를 보겠습니다.
let name = 'Jeremy'; const getName = () => name; const setName = (newName) => { name = newName; } const printUpperName = () => { console.log(name.toUpperCase()); }
* let : let 으로 선언된 함수는 scope 가 해당 지역으로 한정됩니다.
const 와 다르게 값을 외부에서 변경할 수 있습니다.
위 코드의 잘못된 점이 보이나요?
얼핏보면 잘못된 점 없이 실행도 잘되고 결과도 잘 나옵니다. 맞습니다. 위 코드의 문제점은 일반적으로는 없습니다.
다만 함수형으로 생각한다면 변경점이 생기게 됩니다.
1) let 으로 name 변수를 선언하고 값은 'Jeremy' 를 주었습니다.
2) const getName 은 인자없이 name 을 리턴합니다.
3) const setName 은 newName 을 인자로 받아서 name 변수의 값을 newName 으로 변경합니다.
4) const printUpperName 은 인자없이 현재 name 값을 대문자로 변경하여 출력합니다.
자 여기서 잘못된 점은 everything 입니다.
먼저 let name 의 선언은 해당값이 변할 수가 있다는 점이 생깁니다. 첫번째로 문제가 생겼구요.
getName 은 name 값을 리턴합니다. 엥? 이게 뭐가 잘못된거죠?
함수형으로 생각해봅시다.
getName 의 결과를 예상할 수 있나요? 응 'Jeremy' 야 라고 한다면 할 말이 없습니다.
만약 나중에 누군가가 나도 모르게 name 값을 변경한다면 ? 응 'Jeremy' 야 라고 할 수 없습니다.
어디서 변경되었는지, 뭘로 변경되었는지를 알아야 해당함수의 결과를 예측할 수 있습니다.
그 다음 setName 역시 당연히 잘못 되었다는 것이 보이나요?
해당 함수는 newName 을 인자로 받아서 name 값을 바꿔 버립니다.
setName 이 실행되고, getName 이 실행되면 나도 모르게 jeremy 는 사라지고 다른 결과값이 나오게 됩니다.
setName 의 잘못은 외부의 값을 직접적으로 건드린 것 입니다.
마지막으로 printUpperName 의 결과값이 예상되나요?
실행하면 어디 있는지도 모르는 name 을 대문자로 변경하여 실행합니다.
const upperName = (name) => name.toUpperCase();
printUpperName 을 재정의해서 upperName 으로 바꾸고 name 인자를 받아서 대문자로 변경합니다.
이렇게 하면 사용자는 무엇이 대문자로 변경되서 나오는지 결과를 예측할 수 있고, 결과 값이 변하지 않습니다.
getName 과 setName 이요 ? 바꿀려면 억지로 바꿀수는 있지만 햔재로선 의미가 없습니다.
함수형의 중요한 점은 기존의 값을 건드리며 변경하며 계속 사용하는 것이 아닌 새로운 값이 필요하면
새로운 값을 만들어서 할당하게 됩니다.
>> 함수형자바스크립트 - 함수형 배열함수를 사용하자
이번엔 ES6 를 쓰는 분들이라면 자주 애용하는 Map 함수를 씁니다.
알다시피 Map 은 연산후에 리턴되는 값은 기존값의 변경이 아닌 새로운 배열을 리턴합니다.
그럼 예제를 봅시다.
function doubleNumbers(numbers) { const doubled = []; const l = numbers.lenth; for (let i = 0; i < l; i++) { doubled.push(numbers[i] * 2); } return doubled; } doubleNumbers([1,2,3]); // [2, 4, 6]
doubleNumbers 함수의 역활이 보이시나요?
numbers 를 인자로 받아서 (아마 배열이겠지요) doubled 라는 새로운 배열을 만든 뒤 numbers 의
각 값들의 제곱을 구해서 doubled 에 삽입한 후 리턴합니다.
함수형 으로 작성되었습니다. 기존의 numbers 를 변경하지 않고 새로운 배열을 만들어
새로운 값을 담은 뒤 리턴 하니깐요.
다만 map 함수를 활용한다면 위 코드는 확 줄어들겠죠?
function doubleNumbersMap(numbers) { return numbers.map(n => n * 2); } doubleNumbersMap([1,2,3]); // [2, 4, 6]
numbers 를 인자로 받아 map 함수를 활용하여 제곱을 한뒤 리턴 해 줍니다.
여기서는 doubled 라는 새로운 배열을 만들 필요도 없이 map 이 알아서 새로운 배열을 리턴하기 때문에
코드가 굉장히 간결해 졌습니다.
>> 함수형 자바스크립트 - 변수의 값을 변경시키지 말자
const hobbies = [ 'programming', 'reading', 'music' ]; const firstTwo = hobbies.splice(0,2); console.log(firstTwo); // ['programming' , 'reading'] console.log(hobbies); // ['music']
위 코드를 보면 어디가 잘못 되었을까요?
바로 firstTwo 부분이죠.
firstTwo 는 기존 hobbies 배열을 잘라서 삽입시켰습니다.
문제는 이때문에 hobbies 값이 변경되었습니다.
hobbies 는 순수성을 잃고 music 만 가지게 되었습니다. 이는 함수형에서 원하는 형식이 아닙니다.
기존의 값은 불변해야 합니다.
여기서 강제적으로 기존 값을 지켜주는 함수가 있습니다. 바로 Object.freeze 입니다.
const hobbies = Object.freeze([ 'programming', 'reading', 'music' ]); const firstTwo = hobbies.splice(0,2); // TypeError
hobbies 를 Object.freeze 를 사용하여 만들었습니다.
이제 hobbies 를 변경하려고 하면 TypeError 를 발생시키며 변경시킬 수 없도록 합니다.
이와 관련된 또다른 예를 봅시다.
class PointTwo { constructor(x, y) { this.x = x; this.y = y; } moveBy(dx, dy) { this.x += dx; this.y += dy; } } const PointTwo = new Point(0, 0); PointTwo.moveBy(5 ,5); PointTwo.moveBy(-2, 2); console.log([PointTwo.x, PointTwo.y]); // [3, 7]
아까 보았던 Point 클래스 입니다.
PointTwo 클래스는 생성자와 moveBy 라는 함수를 가지고 있고 moveBy 는 dx, dy 를 인자로 받아서
x 와 y 값을 변형시킵니다.
지금까지 글을 봐왔다면 무엇이 잘못되었는지 바로 알 수 있습니다.
moveBy 함수가 직접적으로 x 값과 y 를 변경하기 때문에 const PointTwo 의 값은 moveBy 를 만날때 마다
값이 변하게 됩니다.
그럼 함수형으로 바꿔서 봅시다.
const createPoint = (x, y) => Object.freeze([x, y]); const movePointBy = ([x,y], dx, dy) => { return Object.freeze([x + dx, y + dy]); }; let point = createPoint(0, 0); point = movePointBy(point, 5, 5); point = movePointBy(point, -2, 2); console.log(point); // [3, 7]
무엇이 바뀌었는지 보이나요?
1) 먼저 PointTwo 클래스를 없애고 const createPoint 변수가 PointTwo 의 생성자를 대신하게 되었습니다.
2) Object.freeze 를 사용하여 생성하기 때문에 이제부터 createPoint 로 생성된 값은 변경되지 않습니다.
3) movePointBy 함수는 x,y 가 포함된 배열과 dx ,dy 를 인자로 받습니다. 여기서 이 함수의 목적은
[x,y] 배열은 대상 배열 , dx ,dy 변수는 새롭게 할당 할 값이라는 것을 알 수 있습니다.
4) let point 변수는 createPoint 함수를 사용하여 0 , 0 배열을 만들었습니다.
5) 이제 point 변수에 movePointBy 함수를 두번 적용합니다. 대상은 자기자신인 point 와 변경할 값을
인자로 주었습니다.
6) 두번의 함수 적용 후 최종 값은 3, 7 이 나옵니다.
여기서 기존 코드랑 뭐가 다른거죠?
Object.freeze 를 썼는데 왜 point 는 변경이 되나요 ?
이는 movePointBy 함수를 살펴보면 알 수 있습니다.
movePointBy 함수는 대상으로 받은 Point 를 변경해서 돌려주는 것이 아닌 point 의 값과 dx, dy 의 값을 가지고
연산을 한 값을 새롭계 freeze 시켜서 돌려주게 됩니다.
한마디로 movePointBy 를 거치면 기존의 point 는 사라지고 새로운 값과
freeze 가 적용된 새로운 point 객체를 받는 겁니다.
기존 값의 재활용이 아니라는 거죠.
사용자는 기존값과 변경될 값을 같이 보내서 결과를 예측할 수 있고, movePointBy 는 순수함수가 되는 것 입니다.
>> 함수형 자바스크립트 - Closure 를 이용한 고차함수
Closure 를 이용하여 고차함수를 활용할 수 있습니다.
예제를 봅시다.
const createAdder = (x) => { return (y) => x + y; } const add3 = createAdder(3); add3(2) === 5; add3(3) === 6;
createAdder 함수는 x를 인자로 받아서 다시 (y)를 인자로 받아 x + y 를 리턴하는 함수를 리턴합니다.
add3 는 createAdder 에 3을 인자로 줬습니다. 이 상태에서 add3 은 (y) => 3 + y 형식을 가지는 함수입니다.
이제 add3(2) 를 호출하면 (2) => 3 + 2 즉 5가 나오게 됩니다.
child 함수가 parent 함수의 값을 참조할 수 있는 closure 의 특성때문에 나올 수 있는 함수입니다.
이제 createAdder 는 순수함수가 되었고 , 중복되는 인자는 미리 정해두고 값을 예측할 수 있게 되었습니다.
이를 간단하게 REST API 함수에 활용 해 보겠습니다.
먼저 기본 코드를 봅시다.
const request = (options) => { return fetch(options.url, options) .then(resp => resp.json()); }; const userPromise = request({ url: '/users', headers: { 'X-Custom' : 'mykey'} }); const tasksPromise = request({ url: '/tasks', headers: { 'X-Custom' : 'mykey'} });
여기서 request 함수는 options 를 받아서 다시 options.url 과 options 를 인자로 받아
fetch 시키는 함수를 리턴하고 있습니다.
userPromiose 와 tasksPromise 는 request 함수에 url 과 headers 과 포함된 배열을 인자로 보내
API 의 결과 값을 받고 있습니다.
여기서 headers 의 값이 중복됩니다.
이를 해결해 봅시다.
const request = (options) => { return fetch(options.url, options) .then(resp => resp.json()); }; const createRequest = (options) => { return (otherOptions) => { return request(Object.assign( {}, options, otherOptions )); }; }; const customRequest = createRequest({ headers: { 'X-Custonm' : 'mykey' } }); const userPromise = customRequest({ url: '/users' }); const tasksPromise = customRequest({ url: '/tasks' });
createRequest 라는 고차 함수를 만들었습니다.
두개의 옵션을 받아서 합친 뒤에 request 함수를 호출합니다.
customRequest 는 아까 중복되었던 headers 를 createRequest 에 인자로 줍니다.
이로써 customRequest 는
(otherOptions) => { request ( Object.assign ( {} , { headers } , otherOptions ) ) };
의 형태가 되었습니다.
이제 userPromise 와 tasksPromise 는 customRequest 에게 url 객체를 넘겨주면 자동적으로 request 객체에
headers 와 url 을 넘겨주고 request 가 실행됩니다.
이제 같은 headers 를 사용하면 url 만으로 request 함수를 호출 하게 됩니다.
마지막으로 request 함수에 createRequest 함수를 합쳐봅시다.
const request = defaults => options => { options = Object.assign( {}, defaults, options ); return fetch(options.url, options) .then(resp => resp.json()); };
>> 함수형 자바스크립트 - 함수를 연결하자
바로 예제를 봅시다.
먼저
[{ price : '5' } ,{ price : '10'} ,{ price : '3'}];이런 형식의 데이터 가 있습니다.
const request = defaults => options => { options = Object.assign( {}, defaults, options ); return fetch(options.url, options) .then(resp => resp.json()); }; const map = fn => array => array.map(fn); const multiply = x => y => x * y; const pluck = key => object => object[key]; const discount = multiply(0.98); const tax = multiply(1.0925); const customRequest = request({ headers: { 'X-Custom' : 'mykey'} }); customRequest({ url: '/cart/items' }) .then(map(pluck('price'))) .then(map(discount)) .then(map(tax));
위 코드를 봅시다.
먼저 map 함수를 지정하였습니다.
map 은 함수를 인자로 받고 다시 배열을 인자로 받아 해당 배열에 인자로 받은 함수를 적용하여 리턴합니다.
multiply 는 x 와 y 를 인자로 받는 고차함수 입니다.
pluck 는 key 와 객체를 받아 해당 객체의 key의 값을 표현합니다
discount 는 0.98 을 곱하고 , tax 는 1.0925 를 곱합니다.
이제 customRequest 에는 request 를 부르고
customRequest 를 통해 url 을 전달하여 fetch 를 실행합니다.
이제 코드를 순서대로 실행 해 봅시다.
1) customRequest( { url : '/cart/items' }) 를 실행합니다. 해당 api 주소에서 리턴 받는 값은
위에서 설정 해 둔 값이라고 생각합시다.
2) 해당 응답이 완료되면 먼저 map ( pluck('price')) 를 실행합니다. map 함수는 위에 적었듯이 함수와 배열을
인자로 받아서 해당 배열을 인자 함수로 실행한 뒤 리턴합니다.
pluck('price') 를 통해 해당 배열에서 price 값을 뽑아서 표현합니다.
표현하면
[5,10,3]이런 값이 됩니다.
3) 이제 map(discount) 를 통해 해당 값에 0.98 을 곱하고
[4.9,9.8,2.94]4) 마지막으로 map(tax) 를 통해 1.0925를 곱합니다.
[5.35,10.71,3.21]별 거 없죠?
이런 방식은 아마 기존에 많이 사용하고 있으리라 생각합니다.
>> 함수형자바스크립트 - 재귀함수를 이용하자
함수형에서는 기존값을 지속적으로 변화시키는 for , while 등을 사용하지 않습니다.
대신 새로운 값을 가지고 다시 연산하게 됩니다.
예를 보면 이해가 쉽습니다.
일단 팩토리얼 함수를 사용한다고 생각해봅시다.
4의 팩토리얼 즉 4! = 4 x 3 x 2 x 1 = 24 를 함수로 만들어 봅시다.
먼저 재귀함수 없이 기본함수로 만들면
const factorial = (n) => { let result = 1; while (n > 1) { result *= n; n--; } return result; }
이런 식으로 n 을 받아서 while 문을 돌려서 결과를 생성한 뒤 리턴합니다.
이제 이놈을 재귀함수로 변경 해 봅시다.
const factorial = (n) => { if (n < 2) { return 1; } return n * factorial(n - 1); };
코드가 짧아지고 인자로 받은 n 에 재귀함수를 사용해서 계속 값을 더하고 있습니다.
자 여기서 문제가 무엇일까요?
먼저 함수를 실행했을 때 Javascript 내부에서는 콜 스택이 어떻게 쌓이는지 봅시다.
factorial(4);4 * factorial(3);4 * 3 * factorial(2);4 * 3 * 2 * factorial(1);4 * 3 * 2 * 1;4 * 3 * 2;4 * 6;24;이런식으로 factorial 함수는 n * factorial 이 계속 쌓이게 됩니다.
여기서 먼저 재귀함수에서 중요한 2가지를 알아봅시다.
1 . 재귀함수를 활용하는 부분을 찾습니다.
여기서는 (n * n - 1 , n * n - 2, n * n -3 ....) 이 됩니다.
2. 해당 함수를 중지시키는 부분을 찾습니다.
여기서는 (n < 2) return 1 이 되겠네요.
이제 이 함수의 문제점을 알아봅시다.
현재 return n * factorial(n-1) 에서 가장 먼저 실행되는 부분은 어디입니까?
바로 ( n - 1 ) 부분 입니다. 함수를 실행하려면 인자값을 먼저 알아야 하니깐요.
그뒤에 실행되는 부분은 어디일까요? 당연히 해당 인자를 감싸고 있는 factorial 이 됩니다.
그리고 마지막으로 n * factorial (n-1) 이 실행됩니다.
여기서 Javascript 내부에서는 factorial ( n -1 ) 을 콜 스택에 쌓아서 다 실행하고 난 뒤에
factorial 함수가 더 이상 쌓이지 않으면 마지막으로 n * factorial( n - 1) 을 차차 실행하게 됩니다.
왜냐면 factorial 이 완료되지 않으면 factorial 에 의존성을 가지는 n * factorial ( n - 1 ) 공식을 실행 할 수가 없기 때문이죠.
생각해보세요. factorial ( n - 1) 의 값을 모르는데 어떻게 n * factorial ( n - 1 ) 결과를 냅니까?
그러므로 위 함수는 잘못되었습니다.
결과가 잘 나오는데요 ? 하시는 분은 그럼 factorial(100,000) 을 실행 해보십시오.
call stack 을 초과했다고 나오게 됩니다.
당연합니다 . Javascript 의 Maximum call stack size 는 Chrome 이 약 1MB 입니다.
그럼 call stack 하나의 용량이 약 48B 이면
100,000 x 48 / 1024 / 1024 = 4.58 MB > 1MB 값이 나오니 당연히
maximum call stack size error 가 나오게 됩니다.
그럼 어떡하냐 어떤식으로 바꾸느냐
이는 꼬리물기 재귀함수로 변경하면 간단히 해결됩니다.
const factorial = (n, accum = 1) => { if (n < 2) { return accum; } return factorial(n - 1, n * accum); };
변경된 함수입니다.
뭐가 변경되었는지 보이나요 ?
먼저 인자가 하나 늘어나게 되었습니다. accm 은 해당 재귀함수를 제어하는 값 입니다.
default 값으로 1이 들어가 있고 n 의 값에 따라 점점 줄어들게 됩니다.
그리고 최종적인 결과값이 들어가는 곳이기도 합니다.
위 함수에서 factorial (4) 를 실행하면?
처음 실행시 factorial (4 , 1) 이 되고 if 문을 갔지만 n 은 4이기에 패스.
그리고 return 하게 되는데 여기서 함수자체를 리턴하도록 변경되었습니다.
이렇게 되면 factorial 에 의존성을 가지는 공식이 없고 새로운 값을 가지고 다시 함수를 실행하기 때문에
깔끔하게 call stack 이 리셋되고 해당함수를 실행하게 됩니다.
결국 함수의 실행은 call stack 에 쌓아두지 않고
factorial ( 4 , 1)
factorial ( 3 , 4)
factorial ( 2 , 12)
factorial ( 1 , 24)
이 됩니다.
이제 해당 함수로 factorial (1,000,000) 을 실행하게 되면 maximum call stack error 가 아닌
infinity 가 결과로 나옵니다.
값이 표현하기 힘들정도로 높다고 나오는거죠. 연산이 제대로 실행 된 겁니다.
참 쉽죠?
이로써 간단하게 함수형자바스크립트 예제와 ES6 의 새로운 문법을 살펴 보았습니다.
OOP 에서 함수형으로 변하는 건 쉽지 않다고들 하는데 , 기본적으로 순수함수의 법칙과 값의 변경이 아닌
새로운 값을 만들어 대입시킨 다는 생각으로 차근차근 하다보면 익숙해 지리라 생각합니다.
고차함수와 for, while 을 대신하는 재귀함수의 활용도 잊지 말구요.
잘못된 점이나 잘못된 지식은 언제든지 말해 주세요
추가로 오랜만에 글 쓰다 알아낸 기능이 있습니다.
vscode 를 사용중에 코드를 그대로 복사 붙여넣기 하면
코드가 그대로 붙는군요 . 우오
const value = factorial(100000);console.log(value);점점 글쓰기 편해져서 좋군요 ㅠ
'Javascript' 카테고리의 다른 글
새로운 블로그를 개설했습니다. (1) 2021.02.22 Web Component 에 대하여 간략하게 알아봅시다. (0) 2019.04.24 ES6 2부 - Arrow function, 객체 리터럴 , 2진수, 8진수 (0) 2016.08.18 ES6 1부 - let , const , 배열과 객체 (1) 2016.08.17 Angular.js 의 작동원리 (1) 2016.06.27