프로토타입이란?
- 자바스크립트은 기반을 두고 있는 언어입니다.
- 기본 데이터 타입을 제외한 모든 객체는 프로토타입이라는 객체를 가지고 있습니다.
- 프로토타입으로부터 프로퍼티와 메서드를 상속 받습니다.
constructor를 사용하면 내가 사용하는 객체가 어디서 파생된것인지 알아낼 수 있습니다.(instanceof로도 확인 가능)
__proto__
__proto__
는 비표준이기 때문에 프로토타입을 확인하고 싶으면
표준 문법인getPrototypeOf
,setPrototypeOf
를 사용해서 확인하는 것이 좋습니다.
위 이미지를 보시면 dog는 아무것도 존재하지 않지만, 체이닝이 되어 sayName 메서드를 사용할 수 있습니다.
제일 하단
console.log
부분에서dog
와cat
이 작동을 하지 않는 모습을 보여줍니다.
이유가 뭘까요?
오류에 나와있듯dog.getInfo
는 function이 아니기 때문입니다.
그럼 새로운 의문이 들게 됩니다.function Pet
의 새로운 인스턴슨데 왜 안될까요?
프로토 타입을 상속받지 못했기 때문입니다.
프로토 타입을 상속한 후 예제들 다시 보겠습니다.
프로토 타입을 상속시키고 나서야 잘 작동하는 모습이 보입니다.
이처럼 프로토타입의 동작 방식은 이해하기 어려운면이 있습니다.
함수와 클래스의 다른점 중 하나는 인자를 받는 위치가 다릅니다.
new
연산자를 사용하는데, 이 객체를 인스턴스라고 부릅니다.(상단 프로토타입 1️⃣ constructor(생성자) 참고)참고 링크
생성자 함수를 이용해 코드를 작성하였습니다.
클래스를 이용하여 작성해 볼까요?
동일한 코드를 클래스로 변경하여 작성하였습니다.
생성자 함수보다 가독성이 좋습니다.
이렇게 사용하게 되면 새로운 인스턴스를 만들 때, 따로 들어오기 때문에 따로 프로토타입을 추가할 필요가 없습니다.
getter, setter 도 동일하게 사용가능합니다.
생성자 함수보다 클래스 사용을 적극적으로 권장합니다.
extends
라는 키워드를 사용하여 확장합니다.문법
class A extends B
constructor(인자) {
super(인자) // 부모 생성자(B) 함수 호출
}
B를 확장하여, A라는 클래스를 만든다는 의미 입니다.
자신이 선언될 당시의 환경을 기억하는 함수라고 이해하시면 편합니다.
클로저 만들기(중첩 함수)
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;
}
}
(function a(){
let b = 'hi';
})();
const result = a(); // 실행
console.log(b); // 오류
위 예제를 확인하시면 result안에 있는 a()는 실행이 되지만, console.log는 실행이 안됩니다.
그 이유는 바로 외부에서 내부로 접근을 막고 있기 때문입니다.
그럼 외부로 노출시키면 어떨까요? 정상적으로 접근이 가능합니다.
addEventListener
를 통하여 사용자의 동작을 받아왔을 때만 그 결과를 바로 출력함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라는 함수 안에 익명의 함수를 넣어 구문 내에서 동작하고 있습니다.
비동기처리란?
특정 코드의 연산인 끝날때 까지 코드 실행을 멈추지 않고 다음 코드를 먼저 실행하는 것
callback은 callback함수 안에서만 처리가 가능하고, callback함수 밖에서 온 값을 확인할 수 없습니다.
promise는 비동기에서 온 값이 promise객체에 저장되기 때문에 코드 작성이 용이해 집니다.
예시
물건을 구매하려고 가게에 방문했는데, 사고자하는 물건이 없을때
주인한테 10초마다 물건 왔나요? 아니오 를 반복할 수 없습니다.
가끔 이 물건은 이제 들어오지 않습니다. 라고 말하는 경우도 있겠죠.
이런 모든 경우를 대비해 대부분의 소비자는 물건 들어오면 연락해주세요 라고 번호를 남기는 편이 가장 좋습니다.
이렇게 되면 상품이 준비되는 동안 다른 일들을 볼 수 있겠죠.
이것을 프로미스라고 합니다.
문법
const promise = new Promise((resolve, reject) => {});
//프로미스는 클래스이기 때문에 new 키워드를 이용해서 만들 수 있다
//함수를 전달받는데 인수는 resolve와 reject가 있다
//resolve는 성공 reject는 실패 했을때 사용되는 함수
new
키워드를 사용하여 객체를 생성한다.new Promise
가 생성되는 즉시 인자로 받아지는 함수도 즉시 실행되며,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"
})
처리된 결과값이 저장됩니다.
비동기 처리를 위해 get함수를 호출하게 되는데 get 함수의 후속처리를 해주는 콜백함수를 사용하게 됩니다.
이때 콜백함수를 통하여 비동기 함수가 비동기 처리 결과를 가지고 비동기함수를 또 다시 호출하게 된다면
호출이 중복되어 복잡도가 높아지는 현상이 발생하게 되는데 이 현상을 callback hell(콜백 지옥)이라고 합니다.
☝🏻 프로미스는 성공 또는 실패만 합니다.
예시
서버에서 숫자를 받아오는 새로운 프로미스를 만든다.
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);
}
)
참고 예제[MDN]
function resolveAfter2Seconds() {
return new Promise(resolve => {
setTimeout(() => {
resolve('resolved');
}, 2000);
});
}
async function asyncCall() {
console.log('calling');
const result = await resolveAfter2Seconds();
console.log(result);
}
asyncCall();