✅ 프로토타입

프로토타입이란?

  • 자바스크립트은 기반을 두고 있는 언어입니다.
  • 기본 데이터 타입을 제외한 모든 객체는 프로토타입이라는 객체를 가지고 있습니다.
  • 프로토타입으로부터 프로퍼티와 메서드를 상속 받습니다.

1️⃣ constructor(생성자)

  • 정해진 key, value를 가진 객체를 편리하게 생성할 수 있게 도와주는 역할을 합니다.
  • 비슷한 객체를 여러개 생성할 때 유용하게 사용합니다.
  • 생성자는 new 다음 대문자로 시작합니다.
  • 자주 쓰는 속성과 함수를 미리 만들어 둔 뒤, 필요할 때마다 인스턴스를 만들어 코드를 재사용 할 수 있습니다.

constructor를 사용하면 내가 사용하는 객체가 어디서 파생된것인지 알아낼 수 있습니다.(instanceof로도 확인 가능)

2️⃣ __proto__

  • proto 타입을 알고 싶을 때 사용합니다.
  • 브라우저에서 비표준으로 제공 했었습니다.
  • 사용하지 않는 것이 좋습니다.

__proto__는 비표준이기 때문에 프로토타입을 확인하고 싶으면
표준 문법인 getPrototypeOf, setPrototypeOf를 사용해서 확인하는 것이 좋습니다.

3️⃣ 프로토타입 체인

  • 자바스크립트는 특정 객체의 프로퍼티나 메서드에 접근할 시 객체 자신의 프로토타입 뿐만 아니라,
    자신의 부모 역할을 하는 프로토타입 객체의 프로퍼티나 메서드에 접근할 수 있다.
  • 모든 프로토타입 체이닝의 종점은 Object.prototype

위 이미지를 보시면 dog는 아무것도 존재하지 않지만, 체이닝이 되어 sayName 메서드를 사용할 수 있습니다.

4️⃣ 프로토타입 확장 (상속)

  • A 객체의 프로토타입을 B 객체도 상속받아 사용합니다.
  • 상속을 받게 되면 기존 객체의 모든 프로퍼티와 메소드를 사용할 수 있습니다. (수정과 재사용 가능)
  • 예제를 보고 이해하는 것이 쉬우니 예제를 먼저 보여드리겠습니다.

제일 하단 console.log 부분에서 dogcat 이 작동을 하지 않는 모습을 보여줍니다.
이유가 뭘까요?
오류에 나와있듯 dog.getInfo는 function이 아니기 때문입니다.
그럼 새로운 의문이 들게 됩니다. function Pet의 새로운 인스턴슨데 왜 안될까요?
프로토 타입을 상속받지 못했기 때문입니다.
프로토 타입을 상속한 후 예제들 다시 보겠습니다.

프로토 타입을 상속시키고 나서야 잘 작동하는 모습이 보입니다.
이처럼 프로토타입의 동작 방식은 이해하기 어려운면이 있습니다.


✅ 클래스

1️⃣ 클래스란?

  • 객체를 생성하기 위한 템플릿입니다.(붕어빵 = 인스턴스, 붕어빵틀 = class)
  • 특별한 함수라고 생각하면 됩니다.
    (함수도 함수 표현식과 함수 선언을 할 수 있듯, class도 class표현식과 class 선언 두가지 방법을 사용할 수 있습니다.)
  • 생성자 함수를 클래스로 변경한 예제를 보도록 하겠습니다.

함수와 클래스의 다른점 중 하나는 인자를 받는 위치가 다릅니다.

2️⃣ 인스턴스란?

  • 생성자 함수를 만들어 사용할 때 new 연산자를 사용하는데, 이 객체를 인스턴스라고 부릅니다.(상단 프로토타입 1️⃣ constructor(생성자) 참고)
  • class도 동일한 방법으로 사용합니다.
  • 실제 메모리에 올라갑니다. 참고 링크

3️⃣ 클래스와 인스턴스

  • 메모리를 낭비하지 않고 사용하는 방법에 대해 알려드리겠습니다.

생성자 함수를 이용해 코드를 작성하였습니다.
클래스를 이용하여 작성해 볼까요?

동일한 코드를 클래스로 변경하여 작성하였습니다.
생성자 함수보다 가독성이 좋습니다.
이렇게 사용하게 되면 새로운 인스턴스를 만들 때, 따로 들어오기 때문에 따로 프로토타입을 추가할 필요가 없습니다.
getter, setter 도 동일하게 사용가능합니다.
생성자 함수보다 클래스 사용을 적극적으로 권장합니다.

4️⃣ 클래스 상속(확장)

  • extends 라는 키워드를 사용하여 확장합니다.

문법

class A extends B
	constructor(인자) {
    	super(인자) // 부모 생성자(B) 함수 호출
    }

B를 확장하여, A라는 클래스를 만든다는 의미 입니다.


✅ 클로저

1️⃣ 클로저란?

자신이 선언될 당시의 환경을 기억하는 함수라고 이해하시면 편합니다.

  • 함수와 함수가 선언된 어휘적 환경의 조합입니다.
    • 클로저는 함수를 지칭하고, 그 함수가 선언된 환경과 관계라는 개념이 합쳐짐
  • 스코프를 이용하여, 변수의 접근 범위를 닫는 것입니다.
    • 외부 함수 스코프에서 내부 함수 스코프로 접근이 불가함
    • 내부 함수에서는 외부 함수 스코프에서 선언된 변수에 접근 가능
  • 함수가 호출되는 환경과 별개로 기존에 선언되어 있던 환경을 기준으로 변수를 조회합니다.
    • 외부 함수의 실행이 종료된 후에 클로저 함수는 외부 함수의 스코프(함수가 선언된 어휘적 환경)에 접근할 수 있다.
    • 외부 함수 스코프가 내부 함수에 의해 언제든지 참조될 수 있다.
    • 남발할 경우 퍼포먼스 저하가 발생

클로저 만들기(중첩 함수)

function outerFunc(num1) {
  return function innerFunc(num2) { // 클로저 함수 생성
    return num1 + num2;
  }
}

let a = outerFunc(5); // a는 outerFunc의 인자 num1에 들어가 있는 상태로 바인딩

클로저 만들기(전역에 선언한 변수를 박스 안에 함수로 정의한 뒤 전역 호출)

let globalFunc;

{
  let x = 10;
  globalFunc = function(y) { // globalFunc 함수는 클로저
    return x = x + y;
  }
}

2️⃣ 은닉화

  • 직접적으로 변경되면 안 되는 변수에 대한 접근을 막는 것입니다.
  • 예제를 통해 자세히 알아보겠습니다.
(function a(){
	let b = 'hi';
})();

const result = a(); // 실행
console.log(b); // 오류

위 예제를 확인하시면 result안에 있는 a()는 실행이 되지만, console.log는 실행이 안됩니다.
그 이유는 바로 외부에서 내부로 접근을 막고 있기 때문입니다.
그럼 외부로 노출시키면 어떨까요? 정상적으로 접근이 가능합니다.

3️⃣ 활용법

  • 클로저가 가장 많이 사용 되는 상황은 debounce와 throttle에 가장 많이 사용됩니다.
  • debounce
    • 이벤트가 실행될 때, 그 이벤트가 과하게 실행되지 않도록 지연 시간을 주는 기법 입니다.(무한 스크롤, 여러번 클릭)
    • 이벤트를 그룹화 하여 특정 시간이 지난 후 하나의 이벤트만 발생하도록 하는 기법
  • throttle
    • 이벤트가 실행될 때, 그 이벤트가 과하게 실행되지 않도록 지연 시간을 주는 기법 입니다.(무한 스크롤, 여러번 클릭)
    • 이벤트를 일정한 주기마다 발생하도록 하는 기법

✅ 비동기

1️⃣ 비동기와 동기

  • 동기는 순차적으로 진행되는 것
    • 1이 끝나면 2, 2가 끝나면 3...
    • 코드 실행이 위에서부터 아래로 진행됨
  • 비동기 방식은 반대로 요청을 보냈을 때 응답 상태와 상관없이 다음 동작을 수행
    • addEventListener 를 통하여 사용자의 동작을 받아왔을 때만 그 결과를 바로 출력함

2️⃣ Callback 함수

  • 파라미터로 함수를 전달받아, 함수의 내부에서 실행하는 함수입니다.
  • 콜백 함수는 자주 사용하고 있습니다.
    예를 들어 forEach문을 예시로 들어보겠습니다.
const person = ["Mike", "Stacy", "Andy", "Rick"];

person.forEach(function (eachName, index) {
     console.log(index + 1 + ". " + eachName); // 1. Mike, 2. Stacy, 3. Andy, 4. Rick
});

forEach라는 함수 안에 익명의 함수를 넣어 구문 내에서 동작하고 있습니다.

3️⃣ promise

  • 미래(비동기 작업이 종료된 후)에 반환해주겠다고 약속 해주는 객체
  • 자바스크립트에서 제공하는 비동기를 간편하게 처리할 수 있도록 도와주는 오브젝트(object)
  • 정해진 장시간의 기능을 수행한 후 정상적으로 수행이 완료 되었다면 성공의 메시지와 함께 처리된 결과값을 전달해줌
  • 기능을 수행하다가 예상치 못한 문제가 발생했다면 에러를 전달해줌

비동기처리란? 특정 코드의 연산인 끝날때 까지 코드 실행을 멈추지 않고 다음 코드를 먼저 실행하는 것

💡 callback과 promise의 차이

callback은 callback함수 안에서만 처리가 가능하고, callback함수 밖에서 온 값을 확인할 수 없습니다.
promise는 비동기에서 온 값이 promise객체에 저장되기 때문에 코드 작성이 용이해 집니다.

예시

물건을 구매하려고 가게에 방문했는데, 사고자하는 물건이 없을때
주인한테 10초마다 물건 왔나요? 아니오 를 반복할 수 없습니다.
가끔 이 물건은 이제 들어오지 않습니다. 라고 말하는 경우도 있겠죠.
이런 모든 경우를 대비해 대부분의 소비자는 물건 들어오면 연락해주세요 라고 번호를 남기는 편이 가장 좋습니다.
이렇게 되면 상품이 준비되는 동안 다른 일들을 볼 수 있겠죠.
이것을 프로미스라고 합니다.

문법

const promise = new Promise((resolve, reject) => {});
//프로미스는 클래스이기 때문에 new 키워드를 이용해서 만들 수 있다
//함수를 전달받는데 인수는 resolve와 reject가 있다
//resolve는 성공 reject는 실패 했을때 사용되는 함수

상태확인

  • 우리가 설정한 오퍼레이션이 수행중 일때는 팬딩(pending) 상태
  • 성공적으로 끝내게 되면 풀필드(fulfilled) 상태
  • 만약 파일을 찾지 못하거나 네트워크 문제가 생겼을 때 리젝티드(rejected) 상태

Promise 객체 생성법

  • new 키워드를 사용하여 객체를 생성한다.
    • 객체이기 떄문에 변수 등에 할당하여 사용이 가능합니다.
  • 콜백함수 (비동기 콜백함수 X) 인자를 받습니다.
    • new Promise 가 생성되는 즉시 인자로 받아지는 함수도 즉시 실행되며,
      이 함수는 executor (실행자 함수)라고 부릅니다.
  • 실행자 함수(executor) 함수는 2개의 함수(resolve,reject)를 인자로 받습니다.
    • executor가 실행되면 비동기 작업이 이루어지고
      성공했을 시 resolve 함수를 호출, 실패했을 시 reject 함수를 호출합니다.

콜백으로 사용 했을 시

function async(callback) {
  var result;
    
  setTimeout(() => {
    result = callback("결과값");
  },1000);
    
  return result;
}

var b = async((res) => {
  return res;
})

결과 값은 undefined 로 나옵니다.

프로미스로 사용 시

var p = new Promise((res, rej) => {
    setTimeout(() => {
      res("a")
    }, 1000)
    
})

var result = p.then(res => {
  return res;
})

console.log(result) // Promise {<fulfilled>: "a"}

result.then(res => {
    console.log(res); // "a"
})

처리된 결과값이 저장됩니다.

❓ callback 함수를 사용하지 않는 이유

비동기 처리를 위해 get함수를 호출하게 되는데 get 함수의 후속처리를 해주는 콜백함수를 사용하게 됩니다.
이때 콜백함수를 통하여 비동기 함수가 비동기 처리 결과를 가지고 비동기함수를 또 다시 호출하게 된다면
호출이 중복되어 복잡도가 높아지는 현상이 발생하게 되는데 이 현상을 callback hell(콜백 지옥)이라고 합니다.

☝🏻 프로미스는 성공 또는 실패만 합니다.

Promise 연결하기

예시 서버에서 숫자를 받아오는 새로운 프로미스를 만든다.

const fetchNumber = new Promise((resolve, reject) => {
	setTimeout(() => resolve(1), 1000); //1초뒤 resolve값 1을 전달함
});

fetchNumber
.then(num => num*2) //성공적으로 작동하면 *2
.then(num => num*3) //그리고 그 숫자를 *3
.then(num => { // 그리고 그 숫자를 다른 서버로 보낸 뒤 변환된 값을 받아온다.
	return new Promise((resolve, reject) => { // 새로운 프로미스를 리턴한다.(새로운 서버와 통신함)
		setTimeout(() => resolve(num - 1), 1000);
});
})
.then(num => console.log(num));

콜백함수를 프로미스로 바꾸기

class UserStorage {
    loginUser(id, password, onSuccess, onError) {
        setTimeout(()=>{
            if (
                (id == 'id' && password === 'pass')||
                (id == 'idid' && password === 'passpass')
            ) {
                onSuccess(id);
            } else {
                onError(new Error('not found'));
            }
        }, 2000);
    }
}

getRoles(user, onSuccess, onError) {
    setTimeout(() => {
        if (user === 'id') {
            onSuccess({ name : 'name'});
        } else {
            onError(new Error('다시 시도해주세요.'));
        }
    }, 2000);
}

const UserStorage = new UserStorage();
const id = prompt('아이디를 입력하세요.');
const password = prompt('비밀번호를 입력하세요.');
UserStorage.loginUser(
    id, password, user => {
        UserStorage.getRoles(
            user, userWhitRole => {
                alert (`환영합니다! ${userWhitRole.name}`);
            },
            error => {
                console.log(error);
            }
        );
    },
    error => {
        console.log(error);
    }
)

3️⃣ async & await

  • async 함수
    • async 함수는 객체를 반환하는 하나의 비동기 함수를 정의합니다.(프로미스를 사용하여 반환)
    • 참고 예제[MDN]
  • await 식
    • async 함수에는 await식이 포함될 수 있습니다.
    • async 함수의 실행을 일시 중지하고 전달 된 Promise의 해결을 기다린 후 async 함수의 실행을 다시 시작하고 완료후 값을 반환합니다.
function resolveAfter2Seconds() {
  return new Promise(resolve => {
    setTimeout(() => {
      resolve('resolved');
    }, 2000);
  });
}

async function asyncCall() {
  console.log('calling');
  const result = await resolveAfter2Seconds();
  console.log(result);
}

asyncCall();

profile
#UXUI #코린이

0개의 댓글