Node.js 교과서 : 2. 알아두어야 할 자바스크립트

ES2015+

const, let

  • const : 고정된 값 할당할 시 사용
  • let : 다른 값을 할당하는 상황이 생길 경우 사용

템플릿 문자열

  • (`)백틱으로 감싸며 문자열 안에 ${변수}를 넣을 수 있음
    • ${num1} + ${num2} = ${result2} 입니다.

객체 리터럴

  • 속성명과 변수명이 동일한 경우 한 번만 써도 괜찮음
  • 객체의 속성명은 동적으로 생성 가능
var sayNode = function () {
    console.log('Node');
};
var es = 'ES';
var oldObject = {
    sayJS: function () {
        console.log('JS');
    },
    sayNode: sayNode
};
oldObject[es + 6] = 'Fantastic';
oldObject.sayNode(); // Node
oldObject.sayJS(); // JS
console.log(oldObject.ES6); // Fantastic
const newObject = {
    sayJS() {
        console.log('JS');
    },
    sayNode,
    [es + 6]: 'Fantastic',
};
newObject.sayNode(); // Node
newObject.sayJS(); // JS
console.log(newObject.ES6); // Fantastic

화살표 함수

  • 기존의 function() {}을 대신할 수 있는 함수 기능
  • 변수를 대입하면 나중에 재사용 가능
// 화살표 함수 없음
function add1(x, y) {
    return x + y;
}

// 화살표 함수 형태 1
const add2 = (x, y) => {
    return x + y;
};

// 화살표 함수 형태 2
const add3 = (x, y) => x + y; // return할 식

// 화살표 함수 형태 3
const add4 = (x, y) => (x + y);
// 화살표 함수 없음
var relationship1 = {
    name: 'zero',
    friends: ['nero', 'hero', 'xero'],
    logFriends: function () {
        var that = this;
        this.friends.forEach(function (friend) {
            console.log(that.name, friend);
        });
    },
};
relationship1.logFriends();

// 화살표 함수 형태
const relationship2 = {
    name: 'zero',
    friends: ['nero', 'hero', 'xero'],
    logFriends() {
        this.friends.forEach(friend => {
            console.log(this.name, friend);
        });
    },
};
relationship2.logFriends();

구조분해 할당

  • 객체와 배열로부터 속성이나 요소를 꺼낼 수 있음
var candyMachine = {
    status: {
        name: 'node',
        count: 5,
    },
    getCandy: function () {
        this.status.count--;
        return this.status.count;
    },
};
var getCandy = candyMachine.getCandy;
var count = candyMachine.status.count;
  • candyMachine 객체 안의 속성을 찾아 변수와 매칭
  • count 처럼 여러 단계 안의 속성을 찾을 수 있음
  • 구조분해 할당을 사용할 시 값을 가져오기 때문에 함수의 this가 달라짐
    • 달라진 this를 원래대로 바꿔주려면 bind 함수를 함께 사용해주어야 한다.
const candyMachine = {
    status: {
        name: 'node',
        count: 5,
    },
    getCandy () {
        this.status.count--;
        return this.status.count;
    },
};
const { getCandy, status: { count } } = candyMachine;
  • 배열에 대한 구조분해 할당 문법
var array = ['nodejs', {}, 10, true];
var node = array[0];
var obj = array[1];
var bool = array[3];
const array = ['nodejs', {}, 10, true];
const [node, obj, , bool] = array;

클래스

  • 클래스 문법이 추가
  • 프로토타입 상속 코드
    • Human 생성자 함수와 Zero 생성자 함수
    • Zero 생성자 함수가 Human 생성자 함수 상속(Human.apply, Object.create)
var Human = function(type) {
    this.type = type || 'human';
};

Human.isHuman = function(human) {
    return human instanceof Human;
};

Human.prototype.breathe = function() {
    alert('h-a-a-a-m');
};

var Zero = function(type, firstName, lastName) {
    Human.apply(this, arguments);
    this.firstName = firstName;
    this.lastName = lastName;
};

Zero.prototype = Object.create(Human.prototype);
Zero.prototype.constructor = Zero; // 상속 부분
Zero.prototype.sayName = function() {
    alert(this.firstName + ' ' + this.lastName);
};

var oldZero = new Zero('human', 'Zero' 'Cho');
Human.isHuman(oldZero); // true
  • 클래스 기반 코드
    • 클래스 기반으로 동작하는 것이 아닌 프로토타입 기반으로 동작
class Human {
    constructor(type = 'human') {
        this.type = type;
    }

    static isHuman(human) {
        return human instanceof Human;
    }
    
    breathe() {
        alert('h-a-a-a-m');
    }
}

class Zero extends Human {
    constructor(type, firstName, lastName) {
        super(type);
        this.firstName = firstName;
        this.lastName = lastName;
    }

    sayName() {
        super.breathe();
        alert(`${this.firstName} ${this.lastName}`);
    }
};

const newZero = new Zero('human', 'Zero' 'Cho');
Human.isHuman(newZero); // true

프로미스

  • 노드의 API들이 콜백 대신 프로미스(Promise) 기반으로 재구성
    • 콜백 지옥(Callback Hell) 현상을 극복
  • 실행을 바로 하되 결괏값은 나중에 받는 객체
    • new Promise로 생성, resolve와 reject를 매개변수로 갖는 콜백 함수 작성
    • resolve 시 then이 실행, reject 시 catch가 실행
    • finally는 성공 여부 관계없이 실행
const condition = true; // true면 resolve, false면 reject
const promise = new Promise((resolve, reject) => {
    if (condition) {
        resolve('성공');
    } else {
        reject('실패');
    }
});
// 다른 코드가 들어갈 수 있음
promise
    .then((message) => {
        console.log(message); // 성공(resolve)한 경우 실행
    })
    .catch((error) => {
        console.error(error); // 실패(reject)한 경우 실행
    })
    .finally(() => { // 끝나고 무조건 실행
        console.log('무조건');
    });
  • message를 resolve하면 다음 then에서 message2로 받을 수 있음
  • message2를 resolve
promise
    .then((message) => {
        return new Promise((resolve, reject) => {
            resolve(message);
        });
    })
    .then((message2) => {
        return new Promise((resolve, reject) => {
            resolve(message2);
        });
    })
    .then((message3) => {
        return new Promise((resolve, reject) => {
            resolve(message3);
        });
    })
    .catch((error) => {
        console.error(error); // 실패(reject)한 경우 실행
    });
  • then에서 new Promise를 return 해야 다음 message로 이동 가능
promise
    .then((message) => {
        return new Promise((resolve, reject) => {
            resolve(message);
        });
    })
    .then((message2) => {
        return new Promise((resolve, reject) => {
            resolve(message2);
        });
    })
    .then((message3) => {
        return new Promise((resolve, reject) => {
            resolve(message3);
        });
    })
    .catch((error) => {
        console.error(error); // 실패(reject)한 경우 실행
    });
  • 콜백을 여러 번 중첩해서 사용하기 위해 Promise.all을 사용
    • 모두 resolve될 때까지 기다렸다가 then으로 넘어감
    • 중간에 reject될 시 catch로 넘어감
const promise1 = Pormise.resolve('성공1');
const promise1 = Pormise.resolve('성공2');
Promise.all([promise1, promise2])
    .then((result) => {
        console.log(result);
    })
    .catch((error) => {
        console.error(error);
    });

async/await

  • 중첩되는 콜백 함수를 사용하는 코드를 깔끔하게 줄일 수 있음
function findAndSaveUser(Users) {
    Users.findOne({})
        .then((user) => {
            user.name = 'zero';
            return user.save();
        })
        .then((user) => {
            return Users.findOne({ gender: 'm' });
        })
        .then((user) => {
            ...
        })
        catch(err => {
            console.error(err);
        })
}
async funcion findAndSaveUser(Users) {
    let user = await Users.findOne({});
    user.name = 'zero';
    user = await user.save();
    user = await Users.findOne({ gender: 'm' });
    ...
}

프런트엔드 자바스크립트

AJAX(Asynchronous Javascript And XML)

  • 페이지 이동 없이 서버에 요청을 보내고 응답 받는 기술
  • HTML 파일을 하나 만들고 그 안에 script 태그를 추가
<!-- axios : AJAX 요청하는 라이브러리 -->
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script>
    // GET 요청
    (async () => {
        try {
            const result = await axios.get('인수로 요청을 보낼 주소');
            console.log(result);
            console.log(result.data);
        } catch (error) {
            console.error(error);
        }
    })();
    
    // POST 요청
    (async () => {
        try {
            const result = await axios.post('데이터를 보낼 서버 주소', {
                name: 'zerocho',
                birth: 1994,
            });
            console.log(result);
            console.log(result.data);
        } catch (error) {
            console.error(error);
        }
    })();
</script>

FormData

  • HTML form 태그의 데이터를 동적으로 제어할 수 있는 기능
const formData = new FormData();
formData.append('키', '값'); // 키-값 추가
formData.delete('키'); // 해당 키 삭제
formData.set('키', '값'); // 해당 키의 값 설정
formData.has('키'); // 키가 있는 지 확인
formData.get('키'); // 해당 키의 값 하나를 불러옴
formData.getAll('키'); // 해당 키의 모든 값을 불러옴

encodeURIComponent, decodeURIComponent

  • encodeURIComponent : 한글을 %XX 형태로 변환
encodeURIComponent('한글');
  • decodeURIComponent : 인코딩된 문자열을 한글로 변환
decodeURIComponent('%ED%95%9C%EA%B8%80');

데이터 속성과 dataset

  • 노드를 웹 서버로 사용하는 경우 프론트엔드에 보여주지 않으면서 저장하는 곳
    • 자바스크립트로 쉽게 접근할 수 있음

참고 문헌

조현영, 『Node.js 교과서』, 개정 2판, 길벗출판사, 2020

이 글이 도움이 되었나요?

0 minutes ago
작성된 댓글이 없습니다. 첫 댓글을 달아보세요!
    댓글을 작성하려면 로그인이 필요합니다.