Javascript는 기본적으로 prototype 기반 언어이지만, class를 사용할 수 있다.
// 흔히 아는 배열 데이터 생성 방법
const fruits = ['apple','banana','cherry']
// new라는 키워드로 시작하는 함수를 생성자 함수라고 함.
// 그 함수의 인자로 원하는 내용을 집어넣기
// 이렇게 만들어진 걸 인스턴스(instance)라고 부른다.
const fruits = new Array('apple','banana','cherry')
// Array객체에서 프로토타입으로 carllis라는 메소드를 등록한 것.
Array.prototype.carllis = function(){
console.log(this)
}
// 배열데이터에서 쓸수 있는 하나의 메소드가 된 것
fruits.carllis(); //['apple','banana','cherry']
// 다른 객체 안에 있는 메소드 재활용 하기
const carllis = {
firstName: 'Carllis',
lastName:'kim',
getFullname: function(){
// 객체 데이터 내부에서 일반 함수를 통해 메소드를 만들게 되면
// this라는 키워드를 통해서 해당하는 객체에 접근할 수 있다.
// 호출되는 대상에 접근하는 것
return `${this.firstName} ${this.lastName}`
}
}
const neo = {
firstName: 'Neo',
lastName:'Anderson',
}
console.log(carllis.getFullname()) // Carllis kim
console.log(carllis.getFullname.call(neo)) // Neo Anderson
// neo라는 객체 데이터가 carllis객체의 getFullname 메소드를 빌려서 호출
prototyper과 생성자 함수를 이용해 메소드와 인스턴스 객체를 만들어서 사용하면 훨씬 간편하고 효율적이게 만들 수 있다.
// 주의 할 점, 반드시 첫글자는 대문자로
// 위의 getFullName 메소드를 함수만 가지고 구현
function User(first, last){
this.firstName = first;
this.lastName = last;
}
// 이 부분에선 화살표 함수를 사용하면 안됨. this가 가리키는 방향이 달라지기 때문
// prototype의 메소드를 만들땐 반드시 일반함수로
// 이제 User를 생성자 함수로 만들어진 인스턴스 객체는 getFullName 메소드를 사용할 수 있다.
User.prototype.getFullName = function(){
return `${this.firstName} ${this.lastName}`
}
// 단순히 호출만 하는것이 아닌 new 키워드를 통해 호출해야 함.
// 인스턴스 객체 생성
const carllis = new User('Carllis', 'Kim')
const neo = new User('neo', 'Anderson')
console.log(carllis) // User {firstName: 'Carllis', lastName: 'Kim'}
console.log(neo) // User {firstName: 'neo', lastName: 'Anderson'}
console.log(carllis.getFullName()) // Carllis Kim
console.log(neo.getFullName()) // neo Anderson
// prototype을 이용해 객체 만들기
function User(first, last){
this.firstName = first;
this.lastName = last;
}
User.prototype.getFullName = function(){
return `${this.firstName} ${this.lastName}`
}
const carllis = new User('Carllis', 'Kim')
const neo = new User('neo', 'Anderson')
console.log(carllis) // User {firstName: 'Carllis', lastName: 'Kim'}
console.log(neo) // User {firstName: 'neo', lastName: 'Anderson'}
console.log(carllis.getFullName()) // Carllis Kim
console.log(neo.getFullName()) // neo Anderson
// Class를 이용해 객체 만들기
// 위의 prototype을 이용한것과 동일한 기능을 한다
class User{
// constructor 키워드가 기존에 우리가 만든 User 함수 역할을 해줌
constructor(first, last){
this.firstName = first;
this.lastName = last;
}
getFullName(){
return `${this.firstName} ${this.lastName}`
}
}
const carllis = new User('Carllis', 'Kim')
const neo = new User('neo', 'Anderson')
console.log(carllis) // User {firstName: 'Carllis', lastName: 'Kim'}
console.log(neo) // User {firstName: 'neo', lastName: 'Anderson'}
console.log(carllis.getFullName()) // Carllis Kim
console.log(neo.getFullName()) // neo Anderson
// Getter
class User{
// constructor 키워드가 기존에 우리가 만든 User 함수 역할을 해줌
constructor(first, last){
this.firstName = first;
this.lastName = last;
}
// get 키워드는 메소드 앞에 붙여서 사용하는 것
// get 키워드를 붙이면 값을 얻어내는 용도의 함수인 Getter가 되는것
// 그렇게 되면 그 메소드는 마치 속성처럼 사용할 수 있다.
get fullName(){
return `${this.firstName} ${this.lastName}`
}
}
const carllis = new User('Carllis', 'Kim')
console.log(carllis.fullName) // Carllis Kim
carllis.firstName ='alex'
console.log(carllis.fullName) // alex Kim
// Setter
class User{
// constructor 키워드가 기존에 우리가 만든 User 함수 역할을 해줌
constructor(first, last){
this.firstName = first;
this.lastName = last;
}
// get 키워드는 메소드 앞에 붙여서 사용하는 것
// get 키워드를 붙이면 값을 얻어내는 용도의 함수인 Getter가 되는것
// 그렇게 되면 그 메소드는 마치 속성처럼 사용할 수 있다.
get fullName(){
return `${this.firstName} ${this.lastName}`
}
// set 키워드도 메소드 앞에 붙여서 사용, 그렇게 되면 그 메소드는 Setter가 된다.
// 값을 지정할때 동작하는 메소드
set fullName(value){
console.log(value);
// 기준을 정해 그 기준으로 문자열을 나눠서 배열로 반환하는 메소드 split()
[this.firstName, this.lastName] = value.split(' ')
}
}
const carllis = new User('Carllis', 'Kim')
console.log(carllis.fullName) // Carllis Kim
carllis.fullName = 'neo anderson'
console.log(carllis) // neo anderson
간단히 말하면 클래스 자체에서 사용할 수 있는 메소드.
class User{
constructor(first, last){
this.firstName = first;
this.lastName = last;
}
// 이러한 타입의 메소드는 prototype 메소드
// 별도의 인스턴스에서 호출해야 한다.
getFullName(){
return `${this.firstName} ${this.lastName}`
}
// 이 메소드는 정적 메소드라고 표시해주는 static 키워드
// 이 메소드는 이제 인스턴스가 아닌 클래스에서 사용할 수 있다.
static isUser(user){
if(user.firstName && user.lastName){
return true;
}else{
return false;
}
}
}
const carllis = new User('Carllis', 'Kim')
const neo = new User('neo', 'Anderson')
// prototype 메소드는 인스턴스에서 사용하는 것.
console.log(carllis.getFullName())
console.log(neo)
// 클래스 자체에서 사용할 수 있는 정적 메소드
console.log(User.isUser(carllis)) //true
class Vehicle{
constructor(acceleration = 1){
this.speed = 0;
this.acceleration = acceleration
}
accelerate(){
this.speed += this.acceleration
}
decelerate(){
if(this.speed <= 0){
console.log('정지')
return
}
this.speed -= this.acceleration
}
}
// extends 키워드를 통해서 Vehicle 클래스의 기능을 상속하는 것(가져와서 사용할 수 있게)
class Bicycle extends Vehicle{
constructor(price = 100, acceleration){
// 1. super(): 부모-class의 생성자(constructor)를 참조한다.
// 2. super.method() : 부모-class의 prototype-method를 참조한다.
// super의 기술적 의미
// -> 상속된(자식) class에 요소 추가 시 새로 추가되는 parameter를 정의하려면
// 기존(부모)-class constructor를 다시 정의해 주어야 한다.
// 이 과정에서 생기는 중복되는 코드가 발생해, error발생 확률 증가, 메모리 낭비 등 매우 비효율적인 낭비가 생긴다.
// 이러한 부분을 super로 해결할 수 있다.
// 부모 클래스의 속성 값을 불러와 초기값을 세팅하는 역할인 super
super(acceleration)
this.price = price
this.wheel = 2;
}
}
// 생성자 함수를 통해 인스턴스 생성
const bicycle = new Bicycle(300, 2)
// bicycle 객체가 Vehicle 클래스를 상속한 Bicycle을 통해 만들어 져서
// Bicycle 클래스에는 없던 speed와 acceleration 속성도 가지고 있음
console.log(bicycle) // Bicycle{acceleration: 2 price: 300 speed: 0 wheel: 2}
// instanceof => 앞의 데이터가 뒤쪽의 클래스에서 인스턴스로 만들어져있는지 확인하는 키워드
console.log(bicycle instanceof Bicycle) // true
// Bicycle 클래스 자체가 Vehicle 클래스를 상속햇기 때문에 true
console.log(bicycle instanceof Vehicle) // true
class Car extends Bicycle{
constructor(license, price, acceleration){
// 생성할때 아무런 매개변수도 없다면
// 기본값으로 price=100, acceleration=1 이라는 값을 넣어준다
super(price, acceleration)
this.license = license
this.wheel = 4;
}
accelerate(){
if(!this.license){
console.error('무면허')
return
}
this.speed += this.acceleration
console.log('가속', this.speed)
}
}
const carA = new Car(true, 7000, 10)
const carB = new Car(false, 4000, 6)
console.log(carA) // Car {speed: 0, acceleration: 10, price: 7000, wheel: 4, license: true}
console.log(carB) // Car {speed: 0, acceleration: 6, price: 4000, wheel: 4, license: false}
class Boat extends Vehicle{
constructor(price, acceleration){
super(acceleration)
this.price = price
this.motor = 1
}
}
const boat = new Boat(10000, 5)
console.log(boat) // Boat {speed: 0, acceleration: 5, price: 10000, motor: 1}
class A{
constructor(){
}
}
class B extends A{
constructor(){
super();
}
}
class C extends B{
constructor(){
super();
}
}
// 인스턴스 생성
const a = new A()
const b = new B()
const c = new C()
// 데이터가 특정 클래스의 인스턴스인지 확인하는 키워드 instanceof
// 클래스의 부모 클래스와 비교해도 true가 나온다
console.log(a instanceof A) // true
console.log(a instanceof B) // false
// 특정 인스턴스의 구조를 다른 클래스와 비교하기
console.log(c.constructor === A) // false