자바스크립트는 명령형, 함수형,
프로토타입
기반, 객체지향 프로그래밍을 지향하는 멀티 패러다임 프로그래밍( 좋아보이는건 다 가져다가 만든 ) 언어이다.
자바스크립트를 이루고 있는 거의 모든것이 객체이다 (원시 타입의 값을 제외하고 나머지)
속성을 통해 여러개의 값을 하나의 단위로 구성한 복잡한 자료구조를 객체라 한다.
객체에 대해 설명할때 마다 메이플스토리 캐릭터를 예시로 든다.
무슨말이냐면 메이플스토리 캐릭터를 처음만들면 다 모험가이다.
그럼 처음 캐릭터들은 모두 모험가라는 객체로 만들어진다고 생각하면 된다.
그 뒤에 전직 할때마다 모험가라는 객체에 계속해서 능력치와 스킬들이 추가되어 우리의 캐릭터들이 변화한다고 생각하면 이해가 쉽다.
❓ 그럼왜 모험가라는 객체를 만들어서 쓸까?
👉 만약 모험가라는 객체를 만들지 않으면 캐릭터 생성할때 마다 똑같은 코드를 계속 쳐서 생셩해야 하기 때문에 생산성이 떨어진다
❗️ 객체는 재사용성을 높여 생산성을 높이기 위해 사용한다고 생각하면 된다.
자바스크립트에서의 객체는 재사용성 없이 바로 선언할 수도 있고 재사용 하도록 생성할 수도있다.
const person = { // 바로 정의 후 사용
name: 'kim',
address: 'seoul'
getFullInfo(){
return this.name + this.address;
}
};
function Person(name, address){ // 재사용하기 위해 정의
this.name = name;
this.address = address;
this.getFullInfo = function(){
return this.name + this.address
}
}
위 처럼 바로 정의후에 사용할 수 있고, 아래처럼 선언해서 재사용할 수 도 있다.
여기서 name과 같은 속성을 프로퍼티라 하고 함수를 메서드라고 한다.
const person1 = new Person('kim', 'seoul');
const person2 = new Person('lee', 'seoul');
console.log(person1.getFullInfo === person2.getFullInfo); // false
이렇게 생성자 함수로 여러개의 객체를 생성해서 사용하게 된다.
여기서 name
이나 address
는 객체별로 고유의 값을 가지니 싱관없지만 gerFullInfo
같은 경우에는 중복되어서 메모리 낭비가 일어나게 된다.
이건 자바스크립트의 프로토타입으로 해결할 수 있는데.
Person.prototype.getFullInfo = function(){
return return this.name + this.address;
}
이렇게 선언해주면 중복되지 않고 하나의 getFullInfo를 다같이 사용하게 된다.
그럼이제 프로토타입을 자세히 살펴보자
프로토타입 객체 (프로토타입) 이란 객체 간 상속을 구현하기 위해 사용된다.
모든 객체는 [[Prototype]]
이라는 내부 슬롯을 가진다.
이 내부슬롯의 값은 프로토타입의 참조이다.
이 값은 객체 생성방식에 의해 결정된다.
객체와 프로토타입과 생성자 함수는 서로 연결되어 있다.
객체.__proto__
생성자 함수.prototype
프로토타입.constructor
위에서 말한것 처럼 person 객체의 프로토타입을 person__proto__
를 사용해서 접근할 수 있다.
__proto__
__proto__
는 접근자 프로퍼티다__proto__
는 앞에서 배운것 처럼 접근자 프로퍼티기 때문에 getter/setter로 이루어져 있다.
그래서 __proto__
로 호출하면 getter, __proto__
로 새로운 프로토타입을 할당하면 setter가 사용된다.
__proto__
접근자 프로퍼티는 상속되는 것이다.모든 객체의 최상위 객체는 Object
이고 객체에서 __proto__
를 호출하면 프로토타입 체인을 타고 올라가 최상위 객체인 Object.__proto__
을 사용하는 것이다.
__proto__
를 사용하는 이유는 프로토타입 체인때문이다.const parent = {};
const child = {};
child.__proto__ = parent;
parent.__proto__ = child;
이렇게 되면 프로토타입체인에 사이클이 생기기 때문에 무한루프에 빠질 수 있다.
__proto__
말고 다른 함수 쓰자__proto__
를 사용할 수 없는 객체도 있으니
Object.getPrototypeOf()
, Object.setPrototypeOf()
사용하자.
함수 객체만이 소유하는 prototype
프로퍼티는 생성자 함수가 생성할 인스턴스의 프로토타입을 가리킨다.
non-constructor인 화살표 함수, 축약표현으로 정의한 메서드는 prototype 프로퍼티를 소유하지 않으며 프로토타입도 생성하지 않는다.
__proto__
, prototype
프로퍼티 차이__proto__
, prototype
이란 말이 자꾸나와서 헷갈리는데 정리해보면
__proto__
는 객체가 프로토타입에 접근할 때 사용하는 프로퍼티이다.__proto__
를 가진다.prototype
은 생성자 함수가 프로토타입에 접근할 때 사용하는 프로퍼티 이다.📌 결국 객체가 가지는 프로토타입에 접근하기 위해 사용하는 프로퍼티 인것이다.
그래서 이렇게 접근하고 싶은 프로토타입은 뭐냐면 그냥 객체의 유전자라고 생각하면 된다.
이 설명은 코딩애플 유튜브로 배웠다
무슨말이냐면 동일한 생성자 함수로 만들어진 객체들은 각각의 고유 속성을 가지지만, 중복되지 않게 공통속성도 가져야 한다.
이는 부모님이 자식에게 고유의 속성을 물려주지만 공통적인 유전자를 물려주는 것과 같다고 생각해 볼 수 있다.
❗️ 따라서 같은 생성자 함수로 만들어진 객체는 공통적인 유전자 즉 프로토타입을 가지고 이 프로토타입은 객체와 프로토타입 체인으로 연결되어 있는 것이다.
앞에서 생성자 함수와 객체에서 프로토타입에 접근하기 위해서는 __proto__
랑 prototype
을 사용한다 했는데 프로토타입에서는 constructor
를 이용해서 생성자 함수에 접근할 수 있다.
function Person(name) {
this.name = name;
}
const me = new Person('kim');
console.log(me.__proto__ === Person.prototype); // true
console.log(me.constructor === Person); // true
me객체와 프로토타입이 연결되어있기 때문에 me.constructor하면 프로토타입.constructor가 호출되는것이다.
그래서 같은 생성자 함수로 만든 객체 me 와 you의 프로토 타입은 같기 때문에 위와 같은 결과가 실제로 나온다.
참고 :
https://www.inflearn.com/course/%EB%AA%A8%EB%8D%98-%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EB%94%A5%EB%8B%A4%EC%9D%B4%EB%B8%8C
https://www.youtube.com/watch?v=wUgmzvExL_E