2. 알아두어야 할 자바스크립트

const, let

변수 타입인 var를 대체하는 새로운 타입

const는 상수, let은 변수로 쓰인다.
(const : 주소값을 바꾸지 못할 뿐 내부값은 수정이 가능하다.)

varconst, let
스코프함수 레벨 스코프블록 레벨 스코프
호이스팅 과정선언 및 undefined 초기화선언

템플릿 문자열

백틱(`)을 이용하여 문자열을 감싸주는 방법

string 안에 ${변수} 형식으로 변수를 넣을 수 있다.

const num1 = 1;
const num2 = 2;
console.log(`num1 = ${num1}, num2 = ${num2}`);

객체 리터럴

ES6에서는 객체 리터럴에 다음과 같은 기능이 추가되었다.

  1. K:V 형태를 사용할 때 속성명과 변수명이 같으면 변수명처럼 표현할 수 있다.

    const a = 1;
    const obj = {
        a : a, // 기존 방식
        a,     // 속성명과 변수명이 같을 경우 변수명으로만 표현 가능
    }
    
  2. 객체 리터럴 안에서 속성명을 동적으로 생성할 수 있다.

    const es = 'ES';
    const obj = {
        [es + 6]: 'This is ES6',
    }
    console.log(obj.ES6) // This is ES6
    

화살표 함수

기존의 function과 다른 점은 화살표 함수는 this가 없다.

const func1 = () => {};

그래서 this를 호출하면 가장 가까이에 있는 this를 찾는다.
이러한 특징을 이용하여 객체의 메서드 안에서 화살표 함수를 사용하면 this를 이용하여 객체의 프로퍼티를 가져올 수 있다.

const group = {
    title: "1조",
    students: ['기원', '보람', '호진'],

    getList() {
        // this -> group을 가리킴
        this.students.forEach(
            // this -> group을 가리킴
            student => alert(this.title + ':' + student);
        )
    }
}
  • 화살표 함수는 자신만의 this가 없기 때문에 new와 함께 실행할 수 없다.

  • 화살표 함수엔 super도 없다. 그래서 super로 부모 클래스에 접근할 수 없다.

즉, 클래스의 프로퍼티로 화살표함수를 사용하는 것은 좋지 않다.


구조분해 할당

구조분해 할당을 사용하면 객체나 배열로부터 필요한 속성만 골라서 빼낼 수 있다.
아래와 같이 깊이가 다른 프로퍼티 또한 빼낼 수 있다.

const people = {
    info: {
        name: 'giwon',
        age: 28,
        view: 0,
    },
    getView() {
        this.info.view++;
        return this.info.view
    },
};
const { getView, info: { view } } = people;

배열에도 사용할 수 있다. 값을 가져오지 않을거라면 변수명을 작성하지 않으면 된다.
const arr = ['nodejs', {}, 10, true];
const [node, obj, , bool] = arr;

클래스

프로토타입 기반 문법을 클래스 형식으로 사용할 수 있게 꾸며놨다고 보면 될 듯 하다.

  • constructor : 생성자를 뜻한다.
  • static 키워드 : 메서드에 사용하며 인스턴스를 생성하지 않고 바로 Class.method() 같은 형식으로 가져다 쓸 수 있게 해준다.
  • extends 키워드 : 클래스를 상속 받을 수 있다.
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(); // 부모의 breathe()메서드를 실행
        alert(`${this.firstName} ${this.lastName}`);
    }
}

비동기 로직 처리 방법

Javascript는 한줄씩 코드를 처리하며 읽어내려간다. 하지만 비동기 코드는 코드를 완료시키지 않고 백그라운드에서 따로 동작한다.
그래서 실행 순서를 맞춰주기 위해 콜백함수를 사용하여 실행 순서를 정해준다.

setTimeout((name) => {
    let list = name;
    console.log(list);

    setTimeout((name) => {
        list += ', ' + name;
        console.log(list);

        setTimeout((name) => {
            list += ', ' + name;
            console.log(list);
        }, 500, '라떼');
    }, 500, '모카');
}, 500, '아메리카노');
// '아메리카노'
// '아메리카노, 모카'
// '아메리카노, 모카, 라떼'

콜백의 단점은 콜백이 중첩될수록 점점 보기가 힘들어진다.

가독성이 떨어지는만큼 예외처리같은 로직들을 짜기 힘들어진다.

이러한 비동기 처리를 해결하기 위해 Promise가 도입되었다.

Promise

Promise는 콜백함수를 .then()과 .catch()와 같은 방식을 이용하여 가독성을 증가시켰다.

그리고 Promise는 상태라는것을 갖는다.

  • 이행 : fulfilled [Promise <fulfilled>]
  • 대기 : pending [Promise <pending>]
  • 실패 : rejected [Promise <rejected>]

Promise의 상태가 fulfilled가 되어야 원하는 결과값을 반환한다.

Promise는 파라미터로 resolve, reject를 받는데 두 파라미터를 통해서 성공,실패에 관한 로직을 작성한다.
또는 .then(), .catch()로 다음 콜백의 성공여부에 관한 로직을 실행시킬 수 있다.

const promise1 = (result) => {
    return new Promise((resolve, reject) => {
        if (result) {
            resolve("성공");
        } else {
            reject("실패");
        }
    });
}

// 첫 번째 방법 (파라미터 2개 사용하기)
promise1(true).then(
    (res) => {
        console.log(res); // "성공" 출력
    },
    (err) => {
        console.log(err); // 파라미터가 false면 "실패" 출력
    }
);

// 두 번째 방법 (then or catch)
promise1(true).then(
    (res) => {
        console.log(res); // "성공"
    });

promise1(false).catch(
    (err) => {
        console.log(err); // "실패"
    }
);

하지만 Promise도 .then()과 .catch()가 계속해서 이어지기에 코드가 깔끔하진 못하다. (=프로미스 체이닝)

promise1()
.then((res) => new Promise((resolve, reject) => {}))
.then((res1) => new Promise((resolve, reject) => {}))
// ......

async, await

유저의 이름을 가져오는 비동기 함수를 짜보자.
이번엔 Promise를 리턴하는 fetch함수를 사용해보겠다.
아래와 같이 then을 이용하여 유저의 정보를 가져올 수 있다.

function getName() {
    let user = {};

    let promise1 = fetch('domain.com/users/1')
    .then((resp) => resp.json())
    .then((resp) => {
        user = resp;
        console.log(user);
    });

    promise1();

}

여기서 async, await을 이용하면 동기식 코드 짜듯이 코드 형태를 바꿔줄 수 있다.

async function getName() {
    let user = await fetch('domain.com/users/1')
    
    user = await user.json();

    console.log(user); // {id: 1}
}

마치 동기식으로 코드를 짠 듯한 모양새가 나온다.
async, await은 이렇게 비동기 로직을 동기 로직처럼 짤 수 있게 해준다.

async, await은 스코프 최상단에서는 사용할 수 없다!
이런 경우에는 then으로 promise를 처리해주는 것이 가장 좋을듯


AJAX (Asynchronous Javascript And XML)

명칭에 써있다시피 주로 XML..로 응답을 받는다.
거의 JSON으로 통신하는 마당에 AJAJ라 불러야 하지 않나 싶기도...

AJAX는 비동기적 웹 서비스를 개발할 때 사용하는 기법이다.

기본적으로 웹페이지는 데이터가 바뀌면 서버에서 HTML파일을 받아서 문서 자체를 새로 갱신해준다.

그치만 만약 데이터가 조금만 바뀌는데 문서 전체를 리로딩하는것은 낭비다.

그래서 비동기 통신을 이용하여 데이터만 받아와서 Client단을 조작해주고는 한다.

보통 AJAX 요청은 jQuery, Axios, fetch 같은 라이브러리를 이용한다.


FormData

HTML form 태그의 데이터를 동적으로 제어할 수 있는 기능이다.
주로 AJAX와 사용되며 데이터 형식은 K:V 이다. 아래와 같은 방식으로 사용한다.

const formData = new FormData();
formData.append('name', 'giwon');
formData.append('item', 'orange');
formData.append('item', 'melon');
formData.has('money'); // false
formData.get('item'); // orange
formData.getAll('item'); // ['orange', 'melon'];
formData.delete('item');
formData.set('name', 'Allen');

FormData는 K:V 형태이기에, 통신할 때 json을 자주 사용하고 FormData는 잘 사용하지 않는다.
하지만 이미지를 전송할 때는 FormData를 사용해야 한다.


encodeURIComponent, decodeURIComponent

서버에 요청을 보낼 때 서버가 한글이 포함된 주소를 이해하지 못하는 경우가 있는데, 이럴 때 window 객체의 메서드인 encodeURIComponent를 사용한다.

const str = '노드';
const encodedStr = encodeURIComponent(str);
const decodedStr = decodeURIComponent(encodedStr);

console.log(encodedStr); // %EB%85%B8%EB%93%9C
console.log(decodedStr); // 노드
Last Updated: