ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Node.js 스터디 1주차
    BackEnd/Node.js 2022. 1. 18. 06:12

     

    동아리에서 시작한 node.js 스터디 기록 및 인증용 포스팅

    node.js 교과서 (길벗출판사, 조현영 저)책을 이용해서 동아리원 분들과 스터디를 시작했다. 

     

    <1주차 스터디 목표>

    3장 노드 기능 알아보기

    3.1절 REPL사용하기 ~ 3.5절 노드 내장 모듈 사용하기

     


     

    3.1절 REPL 사용하기

    - REPL : read eval print loop - 입력한 코드를 읽고 해석하고 결과물을 반환하며 종료시까지 반복한다. 

    간단하게 vscode상에서 node를 입력하면 js코드를 입력할 수 있다. 웹페이지의 콘솔탭처럼 사용가능해서 간단한 코드 칠때는 괜찮아도 코드 길이가 길어지면 js파일 만드는 편이 훨씬 낫다. 

     


    3.2절 JS 파일 실행하기

    - js파일을 만든 뒤 vscode의 터미널에서 node [파일명]의 형태로 실행가능하다. 

    - /, \, |, <, :, ?, ", *등등 파일 및 폴더명에 사용 불가한 문자들도 있다. 가능하면 특수기호 사용하지 말고 꼭 필요한 경우는 _(언더바)쓰자


    3.3절 모듈로 만들기

    모듈이란 ?

    - 애플리케이션을 구성하는 개별적 요소로써 재사용 가능한 코드 조각.

    - 기능을 기준으로 파일 단위 분리가 일반적. 
    - 모듈은 자신만의 스코프를 가지며 기본적으로 캡슐화되어 있다(비공개) 공개가 필요한 자산에 한정하여 명시적으로 선택적 공개 -> export키워드를 통해서! 
    - 공개된 자산중 일부를 선택해 자신의 스코프로 불러서 재사용 -> import키워드를 통해서! 
    평소엔 애플리케이션과 분리되어 개별로 존재하다 필요에 따라 재사용 할 수 있다. 따라서 재사용성이 좋으며 코드의 단위 분리가 명확해지는 장점이 있다

    (출처 : 모던자바스크립트 DEEP DIVE) 

     

    간단하게 어떤 기능을 하는 함수, 변수들의 집합을 의미한다. 여러 프로그램에 모듈들을 재사용할 수 있으므로 관리가 편리하다. 

    - var.js에서 module.exports에 odd, even 변수를 담은 객체를 대입했다. 그래서 var.js를 불러온 index.js와 func.js에서 module.exports에 대입된 odd, even값을 사용이 가능하다. 

    - 객체 뿐 아니라 변수, 함수 등도 module.exports에 대입이 가능.


    3.4절 노드 내장 객체 알아보기

    - global : 브라우저의 window같은 전역 객체를 의미한다. 모든 파일에서 접근이 가능하며 global생략이 가능. (위에서 사용했던 require, console도 사실 global이 생략된 것이다) 노드에는 window,, document객체는 사용할 수 없다. 

    ( 참고 : https://cbw1030.tistory.com/46 DOM, BOM에 관한 설명이 잘 나와있는 블로그)

    -> 전역 객체인 만큼 globalB에서 대입한 global.message 값을 globalA에서도 접근이 가능


    - console : window의 console과 유사, 변수의 값 확인 및 디버깅 등의 용도로 주로 사용

    const string = 'abc';
    const number = 1;
    const boolean = true;
    const obj = {
        outside: {
            inside : {
                key : 'value',
            },
        },
    };
    console.time('전체 시간'); //timeEnd()와 대응, ()안이 같은 time~timeEnd 그 사이 시간 측정
    console.log('평범한 로그입니다 쉼표로 구분해 여러 값을 찍을 수 있습니다. '); //일반적인 로그를 콘솔에 출력
    console.log(string, number, boolean);
    console.error('에러 메시지는 console.error에 담아주세요'); //에러 내용 콘솔에 출력
    
    console.table([{ name : '제로', birth : 1994}, { name : 'hero', birth : 1988 }]); // []안에 배열로 객체 넣음 -> 테이블 형식 출력
    console.dir(obj, { colors : false, depth : 2});
    console.dir(obj, { colors : true, depth : 1}); 
    // 첫번째 인수로 객체, 두번째 인수로 옵션. color : 색상여부 depth : 객체 내의 객체 몇단계까지 출력할지.
    
    console.time('시간 측정');
    for (let i = 0; i < 100000; i++) {}
    console.timeEnd('시간 측정');
    
    function b() {
        console.trace('에러 위치 추적'); //자주 사용안하지만 일반적으로 에러 발생시에 사용.
    }
    function a() {
        b();
    }
    a();
    
    console.timeEnd('전체 시간');


    - Timer : 함수가 실행되는 시간을 조정하고 싶을 때 주로 사용

    아래 전체 코드의 주석을 확인해보면 이해하기 쉽다. 

    타이머 함수는 밀리초 단위를 사용하는데, 1000밀리초 == 1초이다. 

    const timeout = setTimeout(() => {
        console.log('1.5초 후 실행')
    }, 1500); // 1500밀리초 == 1.5초 
    /* setTimeout(콜백 함수, 밀리초) : 주어진 밀리초 이후 콜백함수 실행 */
    
    const interval = setInterval(() => {
        console.log('1초마다 실행');
    }, 1000); 
    /* setInterval(콜백 함수, 밀리초) : 주어진 밀리초마다 콜백함수 실행 */
    
    const timeout2 = setTimeout(() => {
        console.log('실행되지 않습니다. ');
    }, 3000); //3000초가 지나기 전에 밑에 clear함수가 먼저 실행
    
    setTimeout(() => {
        clearTimeout(timeout2);
        clearTimeout(interval);
    }, 2500);
    /**
     * clearTimeout(아이디) : setTimeout 취소
     * clearInterval(아이디) : setInterval 취소
     * clearImmediate(아이디) : setImmediate 취소
     * */ 
    
    const immediate = setImmediate(() => {
        console.log('즉시 실행');
    });
    
    const immediate2 = setImmediate(() => {
        console.log('실행되지 않습니다.') // 바로 아래에서 취소해서 실행 X
    });
    
    /* setImmediate(콜백 함수) : 콜백함수 즉시 실행 */
    clearImmediate(immediate2);
    
    /**
     * immediate실행, immediate2는 즉시 취소
     * 1초의 interval실행(1초마다)
     * 1.5초가 되어서 timeout실행
     * 2초의 interval
     * 2.5초가 되어 interval, timeout2모두 종료
     */

    파일 경로 출력을 위한 코드

    -> 주로 path모듈과 함께 사용한다. 운영체제별로 /냐 \(역슬래시)이냐 달라서 path모듈과 사용한다고 한다. 


    exports 객체로 모듈 만들기

    - odd, even처럼 단순 객체인 경우에는 exports.형태로 각각 대입이 가능하다. (함수는 exports불가)

    - exports -> module.exports이런식으로 참조가 이뤄지기 때문에 동시 사용은 지양하는 편이 좋다. 

    - exports사용시 속성명 + 속성값까지 대입해야 한다. 


     

    - this는 자신이 속한 객체 or 자신이 생성할 인스턴스 가리키는 자기참조 변수이다.

    - 2~3줄의 콘솔은 exports객체 가리킨다. (최상위 스코프)

    - 일반 함수에서 this호출되면 전역객체 global이 바인딩된다. 따라서 함수 내의 콘솔문에서는 false true가 나온다.

     


    require로 모듈 불러오기

    - require.main은 노드 실행시의 첫 모듈을 의미한다. 

    - require.cache에는 한번 require했던 파일들이 저장되어 있다. (새로 불러오지 않고 cache에 있는 것이 재사용)

     


    모듈 사용시의 주의사항

    -> 반복되는 참조현상(순환참조) 발생 시 예고없이 빈 객체로 만들어버리므로 주의할 것

     


    - process : 현재 실행되고 있는 노드 프로세스 정보를 담고 있는 객체. 여러가지 정보가 있지만, process.env, process.nextTick, process.exit()만 추가 설명이 포함되어져 있다. 

    REPL에서 실행한 화면

    - process.env : 시스템의 환경변수들을 저장, 각종 서비스의 중요한 키 저장용도로 사용한다. (DB비밀번호, API 키 등등!) 아래 코드의 경우 토큰 발급시에 사용한 키값을 env에 넣어뒀다. 

    혹시 보안상 민감한....정보일까봐 가림

    const token = jwt.sign({ email: email }, process.env.JWT_SECRET);

     

    - process.nextTick : 이벤트 루프가 다른 콜백 함수들보다 nextTick의 콜백함수를 우선적으로 처리하게끔 만든다. 

     

    - process.nextTick과 promsie : 마이크로태스크라는 이름으로 따로 구분지어 부르며, 다른 콜백 함수들보다 먼저 실행

    - setTimeout(콜백함수, 0)과 setImmediate : I/O작업이 있는 콜백함수에서의 호출은 setImmediate가 먼저 실행. 하지만 그 외에 immediate가 먼저 실행된다는 보장은 없으므로 주의할 것


    - process.exit() : 프로세스 종료

    서버는 특별한 일이 아니라면 24시간 가동이므로 대부분 어플리케이션 쪽에서 사용. 

    let i = 1;
    setInterval(() => {
        if (i===5) {
            console.log('종료!');
            process.exit(); //실행중 프로세스 종료. 매개변수 0이거나 없다면 정상, 1은 비정상 종료
        }
        console.log(i);
        i += 1;
    }, 1000); // 1초 주기로 반복 (setInterval)


    3.5절 노드 내장 모듈 사용하기

    - OS 모듈 : 운영체제 정보에 접근이 가능하다. 

    const os = require('os');
    console.log('운영체제 정보------------------------------------------');
    console.log('os.arch() : ', os.arch()); //아키텍처 정보
    console.log('os.platform() : ', os.platform()); // 운영체제 플랫폼(윈도우, 리눅스 등)
    console.log('os.type() : ', os.type()); //운영체제 종류
    console.log('os.uptime() : ', os.uptime()); // 운영체제 부팅 이후 흐른 시간(process.uptime은 노드 실행시간!)
    console.log('os.hostnmae() : ', os.hostname()); //컴퓨터 이름
    console.log('os.release() : ', os.release()); //운영체제 버전
    
    console.log('경로---------------------------------------------');
    console.log('os.homedir() : ', os.homedir()); //홈 디렉터리 경로
    console.log('os.tmpdir() : ', os.tmpdir()); //임시 파일 저장 경로
    
    console.log('cpu 정보---------------------------------------------');
    console.log('os.cpus() : ', os.cpus()); //코어 정보
    console.log('os.cpus().length : ', os.cpus().length); //코어 개수(노드의 싱글 스레드 프로그래밍 하면 대부분 하나 사용)
    
    console.log('메모리 정보-------------------------------------------');
    console.log('os.freemem() : ', os.freemem()); // 사용가능한 메모리(램)
    console.log('os.totalmem() : ', os.totalmem()); // 전체 메모리 용량
    /**추가로 os.constants객체 : 에러 및 신호 정보 담겨있음 */

     


    - path : 폴더와 파일의 경로를 조작하도록 도와주는 모듈, (윈도우 운영체제와 유닉스 기반 운영체제의 경로 구분 문자가 다르다. 이런 문제 등을 해결하는데 필요)

    const path = require('path');
    const string = __filename; //string에 파일 이름 저장
    
    console.log('path.sep : ', path.sep); // 경로의 구분자, 윈도우라서 \
    console.log('path.delimiter : ', path.delimiter); // 환경변수의 구분자(delimiter), 윈도우라서 ;
    console.log('---------------------------------------'); 
    console.log('path.dirname() : ', path.dirname(string)); // 파일이 위치한 경로
    console.log('path.extname() : ', path.extname(string)); //파일의 확장자 (.js)
    console.log('path.basename() : ', path.basename(string)); //파일 이름 + 확장자 
    console.log('path.basename - extname : ', path.basename(string, path.extname(string))); //파일이름만 추출
    console.log('---------------------------------------');
    console.log('path.parse() : ', path.parse(string)); // 파일 경로를 분리
    console.log('path.format() : ', path.format({ // parse된 객체를 파일 경로로 합침
        dir : 'C:\\users\\최다연',
        name : 'path',
        ext : 'js',
    }));
    
    console.log('path.normalize() : ', path.normalize('C://users\\\\최다연\\\path.js')); // 경로 구분자가 여러개 사용되었을 때 정상경로로 변환
    console.log('---------------------------------------');
    console.log('path.isAbsolute(C://) : ', path.isAbsolute('C://')); //절대 경로인지 확인(false일 경우 상대경로)
    console.log('path.isAbsolute(./home) : ', path.isAbsolute('./home'));
    console.log('---------------------------------------');
    console.log('path.relative() : ', path.relative('C:\\users\\최다연\\path.js', 'C:\\')); 
    /*
        첫번째 인수 경로에서 두번째로 어떻게 가는지 알려줌. 3단계 상위로 올라가야한다. 
    */
    console.log('path.join() : ', path.join(__dirname, '..', '/users', '.', '/최다연')); // 여러 인수들을 하나의 경로로 합쳐준다. 
    console.log('path.resolve() : ', path.resolve(__dirname, '..', 'users', '.', '/최다연'));
    /**
     < '/a', '/b', 'c'를 매개변수로 넣었을 때 >
     * join : '/'를 만날 경우 상대경로로 처리 : '/a/b/c'
     * resolve : '/'를 만날 경우 절대경로로 처리 : /b/c' ('/' 앞의 경로가 사라진다.)
     * 
     * 절대경로 : 루트 폴더 기준으로 경로 표시
     * 상대경로 : 현재 위치 기준으로 경로 표시
     */

     


     

    - url : 인터넷 주소를 쉽게 조작하도록 도와주는 모듈

    const url = require('url');
    const { URL } = url;
    const myURL = new URL('http://www.gilbut.co.kr/book/bookList.aspx?sercate1=001001000#anchor');
    // url 생성자에 주소를 넣어서 객체로 만든다. WHATWG의 URL로, username, password, origin등 속성이 존재 
    
    console.log('new URL() : ', myURL);
    console.log('url.format() : ', url.format(myURL));
    console.log('-----------------------------------------------');
    
    const parsedUrl = url.parse('http://www.gilbut.co.kr/book/bookList.aspx?sercate1=001001000#anchor');
    console.log('url.parse() : ', parsedUrl);
    console.log('url.format() : ', url.format(parsedUrl));
    /**
     * 기존 노드 방식에서 사용하는 메서드
     * url.parse(주소) : 주소를 분해하는 방식, username과 password대신 auth속성, searchParams대신 query
     * url.format(객체) : WHATWG방식과 기존 노드 방식 모두 사용가능. 분해된 url객체를 원래대로 조립
     *  */

    위 코드를 vscode에 쳐보면, url.parse와 url.format이 deprecated되었다고 나온다.

    책 저자님이 인프런에서도 강의하시는데 누가 이에 관해서 질문을 해서 답변을 보니까 newURL방식을 사용하라고 답변하셨다. 

    -> WHATWG방식은 search부분을 searchParams라는 객체로 반환한다. 

    -> searchParams객체도 getAll, get, has, set, append, delete등으로 조작이 가능하다. 

    기존 방식의 query(문자열)는 querystring모듈을 한번 더 사용해야 해서 WHATWG방식의 searchParams가 더 유용하다.

    (그리고 기존 방식이 deprecated되기도 했고...)

    사진에서 보면&amp;nbsp; deprecated된 것을 확인할 수 있다.&amp;nbsp;

     


     

    - crypto : 암호화를 도와주는 모듈

    -> ex) 실제 서비스에서 사용하는 고객의 비밀번호 등은 암호화시켜서 저장한다. 

    비밀번호를 암호화할 때에는 단방향 암호화 (복호화 불가능)방식을 주로 사용한다. DB에 저장할 때도 암호화해서 저장하고, 클라이언트 쪽에서 로그인 등의 요청이 오면 pw를 같은 방식으로 암호화하고 DB에 저장된 값과 비교하면 된다.  

     

    -> 해시기법 : 고정된 길이의 다른 문자열로 바꾸는 방법. 

    사진의 아랫부분을 보면 base64로 인코딩한 애들의 길이가 같은걸 확인할 수 있다. 

    최근에는 주로 pbkdf2, bcrypt, scrypt등의 알고리즘으로 비밀번호를 암호화하고 있다고 한다.

    -> pbkdf2는 기존 문자열에 salt라고 불리는 문자열을 붙이고 해시 알고리즘을 반복적으로 적용하는 방식이다. 

    -> https://velog.io/@kylexid/%EC%99%9C-bcrypt-%EC%95%94%ED%98%B8%ED%99%94-%EB%B0%A9%EC%8B%9D%EC%9D%B4-%EC%B6%94%EC%B2%9C%EB%90%98%EC%96%B4%EC%A7%88%EA%B9%8C : sha2, pbkdf2, bcrypt, scrypt등의 차이점 찾다가 발견했다. 토이플젝같은거 할때는 보안규정이나 이런거 없이 구현 쉽고 강력한게 bcrypt라서 사람들이 자주 사용하는 듯 하다. 

     

    주석에도 작성했지만 실행할 때마다 결과가 달라지는것을 확인할 수 있다. 


    - 양방향 암호화 : 암호화된 문자열을 복호화할 수 있음

    복호화 코드는 암호학..쪽을 좀 더 공부해야 이해가 가능하다고 한다.

     

    - util : 각종 편의 기능을 모아둔 모듈 

    const util = require('util');
    const crypto = require('crypto');
    
    const dontUseMe = util.deprecate((x,y) => {
        console.log(x+y);
    }, 'dontUseMe함수는 deprecate되었으니 더 이상 사용하지 마세요!');
    dontUseMe(1,2);
    /** util.deprecate : 함수가 deprecated(더 좋은 기능이 나왔을 때 기존 기능을 deprecated처리, 없앨 예정이니 더이상 사용하지 말자. ) */
    
    const randomBytesPromise = util.promisify(crypto.randomBytes);
    randomBytesPromise(64)
        .then((buf) => {
            console.log(buf.toString('base64'));
        })
        .catch((error) => {
            console.error(error);
        });
    /**util.promisify : 콜백 패턴을 프로미스 패턴으로 바꾼다.  */

    deprecate : 더 좋은 기능이 나와서 곧 사라질 예정이므로, 사용하지 말 것

    콜백함수 : 함수의 매개변수를 통해 다른 함수의 내부로 전달되는 함수

     


     

    - worker-threads : 싱글 스레드 기반인 노드를 멀티 스레드 방식으로 작업

    const {Worker, isMainThread, parentPort, } = require('worker_threads');
    
    if(isMainThread) { //부모 스레드일때(기존에 동작하던 싱글스레드를 메인 or 부모 스레드라 부른다. )
        const worker=  new Worker(__filename); // 현재 파일을 워커 스레드에서 실행시킴
        worker.on('message', message => console.log('from worker', message));
        worker.on('exit', () => console.log('worker exit'));
        worker.postMessage('ping');
    } else { //워커일 때 (우리가 생성한 스레드)
        parentPort.on('message', (value) => { 
            console.log('from parent', value);
            parentPort.postMessage('pong');
            parentPort.close(); //워커 스레드 종료. 
        });
    }

    메인스레드 (노드의 기존 싱글 스레드)에서 워커 스레드를 생성해서 일을 시키고, 종료 시키는 방식으로 수행된다. 

    아래는 여러개의 워커 스레드에 workerData속성으로 데이터를 넘기는 예제이다. 

    const { worker } = require('cluster');
    const {
        Worker, isMainThread, parentPort, workerData,
    } = require('worker_threads');
    
    if (isMainThread) { //부모 스레드 일때
        const threads = new Set();
        threads.add(new Worker(__filename, {
            workerData: {start:1}, // new worker호출시 workerData속성으로 원하는 데이터를 보낸다. 
        }));
        threads.add(new Worker(__filename, {
            workerData: {start : 2},
        }));
        for (let worker of threads) {
            worker.on('message', message => console.log('from worker', message));
            worker.on('exit', () => {
                threads.delete(worker);
                if(threads.size == 0) {
                    console.log('job done');
                }
            });
        }
    } else { //워커 스레드 일때
        const data = workerData;
        parentPort.postMessage(data.start + 100); //부모에게 돌려주고 종료. 
    }

    -> 실행결과 

     


    마지막으로 소수의 개수 구하는 작업이다. 

    워커 스레드를 사용하냐 안하느냐 따라 얼마나 시간차이가 나는지 계산해보자. 

    사용하지 않은 단순 계산

    const min = 2;
    const max = 10000000;
    const primes = [];
    
    function generatePrimes(start, range) {
        let isPrime = true;
        const end = start + range;
        for (let i = start; i < end ; i++) {
            for (let j = min; j < Math.sqrt(end); j++) {
                if(i !== j && i % j === 0) {
                    isPrime = false;
                    break;
                }
            }
            if (isPrime) {
                primes.push(i);
            }
            isPrime = true;
        }
    }
    
    console.time('prime');
    generatePrimes(min,max);
    console.timeEnd('prime');
    console.log(primes.length);

    -> 실행결과 

    워커 스레드를 사용한 경우 

    const { Worker, isMainThreadm, parentPort, workerData, isMainThread } = require('worker_threads');
    
    const min = 2;
    let primes = [];
    
    function findPrimes(start, range) {
        let isPrime = true;
        let end = start + range;
        for (let i = start; i < end ; i++) {
            for (let j = min; j < Math.sqrt(end); j++) {
                if(i !== j && i % j === 0) {
                    isPrime = false;
                    break;
                }
            }
            if (isPrime) {
                primes.push(i);
            }
            isPrime = true;
        }
    }
    
    if(isMainThread) {
        const max = 10000000;
        const threadCount = 8;
        const threads = new Set();
        const range= Math.ceil((max - min) / threadCount);
        let start = min;
        console.time('prime');
    
        for(let i = 0; i < threadCount -1; i++) {
            const wStart = start;
            threads.add(new Worker(__filename , {workerData : {start : wStart, range}}));
            start += range;
        } //워커 스레드 8개로 범위를 나눠서 계산
        threads.add(new Worker(__filename, {workerData:{start, range: range + ((max-min + 1) %threadCount)} } ));
        for (let worker of threads) {
            worker.on('error', (err) => {
                throw err;
            });
            worker.on('exit', () => {
                threads.delete(worker);
                if(threads.size === 0) {
                    console.timeEnd('prime');
                    console.log(primes.length);
                }
            });
            worker.on('message', (msg) => {
                primes = primes.concat(msg);
            });
        }
    } else {
        findPrimes(workerData.start, workerData.range);
        parentPort.postMessage(primes);
    }

    실행 결과 : 비교해보면 4배정도 빨라졌다. 컴퓨터마다 좀 차이가 있을 듯 하다. 

     

     

    - child_process

    노드에서 다른 프로그램 및 명령어 실행시 사용한다. 노드 프로세스 외에 새로운 프로세스를 띄워서 명령을 수행한 후 노드 프로세스에 결과를 알려준다. 

    책에서는 파이썬과 CMD명령어를 수행해보는 예제가 실려있어서 따라해봤다. 

    cmd 명령어 dir사용인데 글자가 다 깨진다..

    python 설치된 상태에서 실행이 가능하다. 

    exec같은 경우는 셸을 실행해서 명령어를 수행하고, spawn은 새로운 프로세스를 띄우면서 명령어를 실행한다. 셸을 실행해서 명령어를 수행하고 싶다면 const process = spawn ('python', ['test.py'], { shell : true })로 사용하면 exec처럼 사용된다. (VScode상에서는 .. 별다른 차이를 모르겠다. )

     

    그 외 모듈들 

    aseert : 프로그램이 제대로 동작하는지 테스트시 사용

    dns : 도메인 이름에 대한 IP주소 얻을 때

    net : TCP /IP통신시 사용한다. 

    string_decoder : 버퍼 데이터를 문자열로 바꿀때

    tls : TLS, SSL관련 작업시 사용

    tty : 터미널과 관련된 작업시 사용

    dgram : UDP와 관련된 작업시 사용

    v8 : v8엔진 접근 시 사용

    vm : 가상머신 접근 시 사용

     


     

    추가로 JS기초에 있던 내용들 몇가지

    -> var, const, let

    - 변수 선언에는 기본적으로 const사용, 재할당이 필요한 경우에 한정하여 let사용. (가능한 좁은 스코프에서 let을 사용하길 권장)
    const가 의도치않은 재할당을 방지해줘서 상대적으로 let, var보다 안전
    - 대부분 var사용을 줄이려는 추세 ES6부터는 var키워드 사용 지양하고 있다. 

     

    -> 화살표 함수 

    function키워드 대신 =>를 사용하여 기존의 함수 정의 방식보다 간략히 함수 정의가 가능
    this가 전역객체를 가리키는 문제를 해결하기 위한 대안으로 유용하다

    특징 

    - 매개변수 1개인 경우에만 소괄호 생략 가능
    - 함수 몸체가 하나의 문일 경우에만 { }생략이 가능 const a =1;처럼 표현식 아닌 애들은 다 에러난다. 표현식 ex ) x**2; (x의 제곱)
    - 객체를 반환하는 경우 소괄호로 한번더 감싸줄 것 ex : ( { id , content });

    - 인스턴스 생성 불가
    - 중복된 매개변수 불가
    - 함수 자체의 this, arguments, super,new.target바인딩 갖지 않는다. 

Designed by Tistory.