웹개발 복습 정리 23 : 프로토타입, new, class, 객체지향

Kimhojin_Zeno·2023년 2월 8일
0

웹개발 복습 정리

목록 보기
23/30

섹션 29 : 프로토타입, new, class

Object prototype

객체 프로토타입

프로토타입이란 자바스크립트 객체가 서로 기능을 상속하는 방식의 메커니즘.

객체는 템플릿 객체 역할을 하는 프로토타입 객체를 가질 수 있다.

자바스크립트에서 배열은 객체이다.

const arr1 = [] //빈 배열을 선언했을때 토글을 열면

__proto__: Array(0) // 이게 뜬다. 이건 뭘까?

프로토타입의 참조. double underscore. 프로토타입을 참조하는 특성이다. 여기에 많은 메서드를 담고 있다.

우리가 배열을 다룰 때 사용하는 Methods. 메서드들.

concat(), entries(), every(), fill(), push(), reduce() 같은 것들이 이 안에 담겨 있다.

배열 프로토타입을 참조하는 특성. 프로토타입이 배열의 템플릿 객체인 것이다.

push라는 모든 배열에 대해 별개의 메서드를 가지는게 아니라 하나의 프로토타입이 있고 (거기에 push가 있고) 각각의 배열이 proto 라는 특별한 특성으로 그 프로토타입을 참조하는 것이다.

기본 메서드들 말고 나만의 메서드를 정의할수도 있다.

arr.sing = function() {
		console.log("LALALA")
}

배열 그 자체에 추가한 메서드인 것이다.

공통 특성과 메서드를 포함하는 하나의 객체를 갖는다. 그게 프로토타입.

다른 문자열이나 배열의 다른 객체가 공통 특성을 찾기 위해 이들 특성과 메서드를 찾는 저장소라고 할 수 있다.

템플릿, 청사진 등 여러 방식이 있지만 JavaScript에서는 프로토타입이라고 한다.

Array.prototype //배열 프로토타입이다.

개별 예시로서 배열이 아니라 대문자 A로 쓰는 배열 프로토타입. 여기에 모든 것이 담겨 있다.

String.prototype //문자열 프로토타입. 문자열 메서드들이 있다.

substring, replace등..

이 프로토타입에다 새로운 메서드를 추가해버리면 일일이 추가할 필요없이 접근가능하다.(그러나 추천되는 패턴이 아니다. 프로토타입을 이해하기 위해)

Array.prototype // 메서드나 특성을 추가하는 실제 객체

__proto__ // 참조. 그 배열이나 문자열의 특성. 'timothy'라는 문자열이라면

'timothy'.__proto__ // 객체 문자열 프로토타입에 대한 참조이다.

뭔가 추가할 수 있는 실제 프로토타입 객체 vs 참조

object-oriented programming(OOP)

객체 지향 프로그래밍

일종의 가이드라인이다.

프로그램을 수많은 객체(object) 기본 단위로 나누고 그 사이의 상호작용으로 서술하는 방식이다. 객체란 하나의 역할을 수행하는 메서드와 데이터의 묶음.

자바스크립트는 프로토타입 객체지향을 사용한다.

객체의 패턴은 객체의 제조법이라고 생각하면 된다. 캡슐화하고 상속한다.

쿠키 틀로 찍어서 같은 모양의 쿠키를 만들듯이 객체도 같다.

객체 지향 프로그래밍에서는 특성이나 메서드 정의를 포함하는 클래스나 객체 템플릿을 생성한다.

팩토리 함수(Factory Function)

팩토리 함수. 공장 함수.

어떤 함수가 객체를 반환할 때, 이 함수를 공장 함수라고 한다. 객체를 찍어내기 때문.

함수 안에 메서드를 추가하고 객체를 반환한다.

function makeColor(r, g, b) {
	const color = {};
	color.r = r;
	color.g = g;
	color.b = b;
	color.rgb = function() {
		const { r, g, b} = this; // 구조 분해 할당
		return `rgb(${r}, ${g}, ${b})`;
	};
	color.hex = function() {
		const { r, g, b } = this;
		return (
			'#' + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1)
		);
	};
	return color;
}

const firstColor = makeColor(35, 255, 150);
firstColor.hex();

그러나 팩토리 함수 패턴은 자주 쓰이지 않는다. 생성자 함수를 더 많이 쓴다.

생성자 함수(Constructor Function)

유사한 객체를 여러개 만들때 팩토리 함수처럼 일일이 만들 필요 없이 생성자 함수를 쓰면 더 쉽게 만들 수 있다.

new 키워드를 붙이고

첫글자는 대문자로 한다.(일반 함수가 아니라는 뜻)

function Color(r, g, b) {
	this.r = r;
	this.g = g;
	this.b = b;
}

const firstColor = new Color(23, 44, 55);

console.log(firstColor.r); // 23

함수 안에 반환 값이 없다.

팩토리 함수에서는 빈 객체를 만들고, 그것을 채우고, 그 객체를 반환하는 작업을 했는데

그것들이 생성자 함수에서 new를 사용하면 자동으로 된다.

function Color(r, g, b) {
	this.r = r;
	this.g = g;
	this.b = b;
	this.rgb = function() {
		const { r, g, b} = this; // 구조 분해 할당
		return `rgb(${r}, ${g}, ${b})`;
	};
}

이렇게 함수를 넣을수도 있지만 이렇게 해서 만들면 만들어진 객체의 프로토타입이 아닌 개별 객체에 rgb함수가 저장된다. 함수로 쓰기 어렵다.

프로토타입 참조에 넣으려면 어떻게 해야할까?

function Color(r, g, b) {
	this.r = r;
	this.g = g;
	this.b = b;
}

Color.prototype.rgb = function() {
		const { r, g, b} = this;
		return `rgb(${r}, ${g}, ${b})`;
};

이렇게 함수 밖에서 새로 선언해준다. 이렇게 하면 프로토타입 객체에서 액세스 할 수 있다. 팩토리 함수보다 더 효율적이다. 팩토리 함수는 호출할 때마다 새 객체를 반환했고 해당 객체에 매번 고유의 개별 메서드를 추가했어야 했다.

생성자 함수를 쓸때는 화살표 함수를 쓰면 안된다.

생성자 함수를 통해 이렇게 찍어낸 객체를 인스턴스(Instance)라고 한다.

팩토리 함수보다는 편리하지만 추가하려는 함수 갯수만큼 따로 빼야하기 때문에 그룹화되지 않은 긴 코드가 나열된다. 그래서 class 키워드와 클래스 구문을 쓴다.

팩토리 함수 → 생성자 함수 → class 구문 // 으로 진화.

Class

class Color {
	constructor(r, g, b, name) {
		this.r = r;
		this.g = g;
		this.b = b;
		this.name = name;
	}
}

const c1 = new Color(255, 67, 89, 'tomato');

c1 
// 객체를 반환. 
// Color { r: 255, g: 67, b: 89, name: "tomato" }

클래스나 생성자 함수를 표시할 때는 보통 대문자를 쓴다.

constructor는 새로운 클래스가 만들어질 때마다 즉시 실행되는 함수.

생성자 함수처럼 빈 객체를 만들고 (this가 자동으로 새로운 객체를 참조한다) 그것을 반환한다.

메서드도 쉽게 추가할 수 있다.

class Color {
	constructor(r, g, b, name) {
		this.r = r;
		this.g = g;
		this.b = b;
		this.name = name;
	}
	greet() {
		return `Hello From ${this.name}!`;
	}
}

이렇게 하면 생성자 함수를 쓸때 밖에다 따로 Color.prototype.greet = 이렇게 선언한 것과 같은 기능을 한다.

이렇게 선언한 함수를 constructor안에 넣으면 클래스가 만들어질때마다 해당 함수가 실행되게 할수도 있다.

this로 메서드를 호출해서 동일한 클래스 내의 다른 메서드에 액세스가 가능하다. 여러개 함수를 넣으면 하나의 함수에 결과로 나온 값을 다른 함수가 받아서 사용하는 것이 가능하다는 뜻.

클래스 안에 넣으면 전부 다 그룹으로 묶인다.

extend

class Pet {
	constructor(name, age) {
		this.name = name;
		this.age = age;
	}
	eat() {
		return `${this.name} is eating!`;
	}
}

class Cat extends Pet {
	meow() {
		return 'MEOW!!!';
	}
}

class Dog extends Pet {
	bark() {
		return 'WOOOF!!';
	}
	eat() {
		return 'Yammy';
}

const wyatt = new Dog('Wyatt', 13);

wyatt // Dog { name: "Wyatt", age: 13 }

Dog 클래스 안에는 age와 name이 없는데도 채워진다.

extends로 Pet의 기능을 Cat과 Dog 모두로 확장시킨 것이다.

wyatt.eat()을 호출하면 무엇이 나올까? ‘Yammy’가 나온다. Dog와 Pet 모두에 있는 것은 Dog가 우선. 없으면 Pet에서 찾는다.

super

상위 클래스에 있는 constructor를 사용할때 쓸 수 있다.

class Pet {
	constructor(name, age) {
		this.name = name;
		this.age = age;
	}
	eat() {
		return `${this.name} is eating!`;
	}
}

class Cat extends Pet {
	constructor(name, age, livesLeft = 9) {
		super(name, age) // Pet에 있는 constructor를 상속받아 적용한다.
		this.livesLeft = livesLeft;
	}
	meow() {
		return 'MEOW!!!';
	}
}

super 키워드가 super 클래스의 참조 항목이 된다는 것이 중요하다.

Pet의 참조인 것이다.

constructor를 따로 정의하지 않으면 자동으로 상위 클래스의 생성자를 호출한다. 몇개 추가하고 나머지는 상위 클래스 생성자를 호출할 때 이렇게 사용한다.

이것이 상속의 내용.

profile
Developer

0개의 댓글