프로토 타입의 사전적 정의는 기초 또는 표준이다. '정보시스템의 미완성 버전 또는 중요한 기능들이 포함되어 있는 시스템의 초기 모델'이다. 프로토타입은 원형 객체를 의미하고, 주로 객체를 생성하기 위한 생성자 함수로 사용된다.
function Fruit(name,color,taste){
this.name = name;
this.color = color;
this.taste = taste;
}
Fruit.prototype.sayTaste = function() {
console.log(`나는 맛이 ${this.taste}`);
}
let strawBerry = new Fruit('딸기','빨강색','새콤달콤하다.');
strawBerry.sayTaste(); // 나는 맛이 새콤달콤하다.
프로토 타입 생성자 함수를 사용하여 객체를 생성할 때, 해당 객체는 생성자 함수의 프로토타입을 자동으로 상속 받게 된다.
JavaScript ES6 이전에는클래스가 없었기때문에 클래스 문법이 도입되기전 까지 객체를 생성하기 위해 프로토 타입을 사용하다가 ES6 이후 클래스를 사용한다. 클래스를 사용하게 되면 프로토 타입을 사용할때 보다 코드가 더 간결해지고, 가독성이 좋다.
class Fruit{
constructor(name,color,taste){
this.name = name;
this.color = color;
this.taste = taste;
}
sayTaste(){
console.log(`나는 맛이 ${this.taste}`);
}
}
let melon = new Fruit('멜론','초록색','달콤하다.');
melon.sayTaste(); // 나는 맛이 달콤하다.
상속은 프로토타입을 기반으로 이루어 진다.
function Animal(name,sex) {
this.name = name;
this.sex = sex;
}
Animal.prototype.meal = function() {
console.log(`${this.name}는 식사중이다.`);
};
function Dog(name,sex, breed) {
Animal.call(this, name,sex);
this.breed = breed;
}
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.info = function() {
console.log(`${this.name} 의 성별은 ${this.sex}이고, 견종은 ${this.breed} 이다.`);
};
var myDog = new Dog('버디','수컷' ,'골드 리트리버');
myDog.meal(); // 버디는 식사중이다.
myDog.info(); // 버디 의 성별은 수컷이고, 견종은 골드 리트리버이다.
console.log(myDog instanceof Animal); // true
console.log(myDog instanceof Dog); // true
자식 생성자 함수 Dog에서 부모 생성자 함수의 this 바인딩을 위해 call() 메서드로 상속받을 부모를 호출하여 속성을 상속받는다. 부모 생성자의 프로토 타입을 create() 메서드를 이용하여 자식 생성자의 프로토타입으로 연결한다. myDog은 Dog의 인스턴스이면서 Animal의 인스턴스이다.
class Animal{
constructor(name,sex){
this.name = name;
this.sex = sex;
}
meal(){
console.log(`${this.name}는 식사중이다.`);
}
}
class Dog extends Animal{
constructor(name,sex,breed){
super(name,sex);
this.breed = breed;
}
info(){
console.log(`${this.name} 의 성별은 ${this.sex}이고, 견종은 ${this.breed} 이다.`);
}
}
let myDog = new Dog('미나','암컷','말티즈');
myDog.meal(); // 미나가 식사중이다.
myDog.info(); // 미나 의 성별은 암컷이고, 견종은 말티즈이다.
console.log(myDog instanceof Animal); // true
console.log(myDog instanceof Dog); // true
클래스 문법에서는 extends 키워드를 이용하여 부모 클래스를 상속받고 부모클래스의 변수를 super()를 이용하여 속성을 상속받을수 있다. 클래스 문법 상속에서도 myDog는 Dog의 인스턴스면서 Animal의 인스턴스인것을 확인할수 있다. 클래스 문법 사용시 가독성이 좋은것을 볼수 있다.
클로저는 함수가 정의될 때의 환경을 기억하여, 함수가 다른 범위에서 호출되어도 그 환경에 접근할 수 있게 하는 개념으로 , 상위 함수에서 하위 함수를 반환 함으로써, 상위함수가 먼저 실행이 끝나고 하위 함수를 나중에 실행 할수 있는 기능이다. 클로저는 주로 상태유지(데이터 캐싱),정보의 은닉등에 사용된다.
function outerCacheFunction(newNumb) {
var number = 10 * 10;
function innerCacheFunction(newNumb){
return number * newNumb;
}
return innerCacheFunction;
}
const cacher = outerCacheFunction();
console.log(cacher); // [Function: innerCacheFunction]
console.log(cacher(10)); // 1000
만약 outerCacheFunction의 number를 계산하는 과정이 오래걸리는 작업이라고 가정을 한다면 함수를 호출 할때마다 innerCacheFuntion함수를 호출 할때마다 number를 구하는 과정을 반복해야한다. 그렇게 되면 매번 계산하는 시간은 오래 걸릴 것이다. 따라서, number의 값을 계산한 결과를 기억해두는 casher를 저장한후 newNumb만 넣어서 casher를 호출한다면 효율적인 코드가 될것이다.
function Person(name,age){
this.name = name;
var _age = age;
this.sayInfo = function(){
return `안녕하세요 저는 ${_age}살 ${this.name}입니다. `
}
}
const tom = new Person('톰',25);
console.log(tom.name); // 톰
console.log(tom.age); // undefined
console.log(tom.sayInfo()); // 안녕하세요 저는 25살 톰입니다.
생성자 함수를 통해 tom이라는 객체를 생성하여 name은 this키워드로 저장을 해주고 age는 private 변수로 저장을 해주었다. 그렇기 때문에 객체의 프로퍼티로 age에 접근을 할수는 없지만 데이터 캐시의 number 처럼 객체가 생성되면 age를 기억하여 sayInfo 함수에서 age의 값을 가져올수 있다.
콜백헬 : JavaScript를 이용한 비동기 프로그래밍시 발생하는 문제로 함수의 매개 변수로 넘겨지는 콜백 함수가 반복되어 코드의 들여쓰기 수준이 감당하기 힘들 정도로 깊어져 가독성이 떨어지는 것을 말한다.
setTimeout(() => {
console.log('1번 콜백 끝');
setTimeout(()=>{
console.log('2번 콜백 끝');
setTimeout(() => {
console.log('3번 콜백 끝');
},2000);
},2000);
},2000);
프로미스 : 프로미스는 resolve,reject함수를 통해 비동기 작업이 완료되었을 때 또는 실패했을 때의 결과를 다룰 수 있으며, 콜백 함수 대신 사용하여 가독성을 높이고 콜백헬을 피할수 있다.
const getPromise = (seconds) => new Promise((resolve,reject) => {
setTimeout(() => {
resolve('완료');
// reject('에러');
},seconds * 1000);
});
getPromise(2).then((res) => {
console.log('--- first then ---')
console.log(res)
return getPromise(2);
}).then((res) => {
console.log('--- seconds then ---')
console.log(res);
return getPromise(3);
}).then((res) => {
console.log('--- third then ---')
console.log(res);
return getPromise(3);
}).then((res) => {
console.log('--- last then ---')
console.log(res);
});
프로미스 함수를 생성하여 비동기 작업 성공시 resolve()를 이용하고 , 실패시 reject()를 이용하여 성공 여부에 따라 .then() 메서드 와 .catch() 메서드를 통해 프로미스체이닝을 할수 있다.
Async & await : 프로미스함수를 여러번 이어 사용하는 것은 콜백헬을 사용할때 보다는 좋았지만 , 여전히 직관적이지 않다는 문제점이 있었다. 하지만 Async & Await을 사용한다면 프로미스함수를 async 함수(반환값이 프로미스)에서 awit을(Async 함수에서만 사용가능) 하고 호출만 하여 사용을 하면 되기때문에 훨씬 더 직관적이다.
const fetchData = () => new Promise((resolve,reject) => setTimeout(() => {
resolve('완료')
},2000));
async function getData() {
const resp1 = await fetchData();
console.log(resp1);
const resp2 = await fetchData();
console.log(resp2);
}
getData();