prototype
Java를 사용해본 사람이라면 Class에 대해서 매우 친숙하다.
JavaScirpt도 객체지향 설계를 위해서 이러한 객체들을 prototype이라는 규칙아래에서 사용한다.
What is Prototype?
일반적으로 function 을 사용해서 객체를 정의하게 되면은 함수와 prototype Object가 동시에 생성된다.
그러면 함수내의 prototype이라는 link를 통해 Prototpye Object에 접근이 가능하다.
따라서 Person.prototpye.eyes = 3 을 사용하게되면 Prototype Objejct에 직접적으로 접근가능한것이다.
이처럼 Prototype Object란 JAVA에서 static 영역처럼 객체가 공유하는 데이터처럼 느껴진다.
그렇다면 _proto_는 무엇인가??
_proto_는 일종의 상위객체의 link이다. 저 link를 타고 상위객체에 접근이 가능한것이다.
따라서 kim.eyes 라는 접근이 가능하고 kim.toString 같이 kim에는 toString 같은 메서드가 없지만 최 상위 클래스인 objejct의 메서드를 접근 가능한것이다.
function Rectangle(w, h) {
var width = w;
var height = h;
this.getWidth = function () { return width; };
this.getHeight = function () { return height; };
this.setWidth = function (w) {
if (w < 0) {
throw '길이는 음수일 수 없습니다.';
} else {
width = w;
}
};
this.setHeight = function (h) {
if (h < 0) {
throw '길이는 음수일 수 없습니다.';
} else {
height = h;
}
};
}
Rectangle.prototype.getArea = function () {
return this.getWidth() * this.getHeight();
};
function Square(length) {
this.base = Rectangle;
this.base(length, length);
}
Square.prototype = Rectangle.prototype;
Square.prototype.constructor = Square;
// 변수를 선언합니다.var rectangle = new Rectangle(5,7);
var square = new Square(5);
console.log(rectangle.getArea()+ ' : '+ square.getArea());
console.log(square instanceof Rectangle);
35 : 25
true
위의 예제를 살펴본다면 Rectangle에는 벼누와 메서드가 정의 되어있다.
이러한 Rectangle에 getArea를 prototype을 이용해서 정의한다.
여기서 Square의 객체의 정의를 살펴보면 Rectangle 에다 생성시 length라는 값을 추가적으로 넣는다.
이렇게되면 Square은 new를 할당할시 Rectangle을 생성한다.
그리고 Square의 프로토타입을 Rectangle의 프로토타입과 동일시하게 함으로써 함수를 사용할 수 있게한다.
Square.prototype.constructor = Square; 은 없어도 되는 문구이지만 직접 square 객체의 constructor() 메서드를 출력한다면 생성자 함수 Square가 아니라 생성자 함수 Rectangle을 가리키는것을 알 수 있다.
당연한 점은 square.width는 호출할 수가 없다.
fuction
예시
class Polygon {
constructor() {
[this.name](<http://this.name/>) = 'Polygon';
}
}
const poly1 = new Polygon();
console.log([poly1.name](<http://poly1.name/>));
// expected output: "Polygon"
구문
constructor() { ... }
constructor(argument0) { ... }
constructor(argument0, argument1) { ... }
constructor(argument0, argument1, ... , argumentN) { ... }
설명
constructor를 사용하면 다른 모든 메서드 호출보다 앞선 시점인, 인스턴스 객체를 초기화할 때 수행할 초기화 코드를 정의할 수 있습니다.
class Person {
constructor(name) {
this.name = name;
}
introduce() {
console.log(`Hello, my name is ${this.name}`);
}
}
const otto = new Person('Otto');
otto.introduce();
클래스에 생성자를 정의하지 않으면 기본 생성자를 사용합니다. 아무것도 상속하지 않는 기본 클래스일 때의 기본 생성자는 빈 메서드입니다.
constructor() {}
다른 클래스를 상속하는 경우, 기본 생성자는 자신의 매개변수를 부모 클래스의 생성자로 전달합니다.
constructor(...args) {
super(...args);
}
따라서 다음과 같은 코드를 작성할 수 있습니다.
class ValidationError extends Error {
printCustomerMessage() {
return `Validation failed :-( (details: ${this.message})`;
}
}
try {
throw new ValidationError("Not a valid phone number");
} catch (error) {
if (error instanceof ValidationError) {
console.log(error.name); // ValidationError가 아니라 Error!
console.log(error.printCustomerMessage());
} else {
console.log('Unknown error', error);
throw error;
}
}
ValidationError 클래스는 아무런 초기화 동작도 필요하지 않으므로 생성자를 별도로 명시하지 않았으며, 대신 기본 생성자가 매개변수로 부모 Error 클래스의 초기화를 처리하고 있습니다.
그러나, 파생 클래스에 직접 생성자를 정의할 경우, 부모 클래스의 생성자를 호출하려면 직접 super()를 호출해야 합니다.
class ValidationError extends Error {
constructor(message) {
super(message); // 부모 클래스의 생성자 호출
this.name = 'ValidationError';
this.code = '42';
}
printCustomerMessage() {
return `Validation failed :-( (details: ${this.message}, code: ${this.code})`;
}
}
try {
throw new ValidationError("Not a valid phone number");
} catch (error) {
if (error instanceof ValidationError) {
console.log(error.name); // 이제 ValidationError!
console.log(error.printCustomerMessage());
} else {
console.log('Unknown error', error);
throw error;
}
}
"constructor"라는 이름의 메서드는 하나의 클래스에 오직 하나만 존재할 수 있습니다. 두 개 이상의 constructor 메서드를 정의하면 [SyntaxError]가 발생합니다.
예제
constructor 메서드 사용하기
class Square extends Polygon {
constructor(length) {
// length로 다각형의 넓이와 높이를 정의하기 위해 부모 클래스의 생성자를 호출합니다.
super(length, length);
// 참고: 파생 클래스에서, this를 사용하기 전에는 반드시 super()를 먼저 호출해야 합니다.
// 그렇지 않으면 ReferenceError가 발생합니다.
this.name = 'Square';
}
get area() {
return this.height * this.width;
}
set area(value) {
this.height = value ** 0.5;
this.width = value ** 0.5;
}
}
다른 예제
아래 예제에서, Square 클래스의 프로토타입을 Rectangle의 프로토타입으로 바꾼 후에도, Square의 인스턴스를 생성할 때 부모 클래스인 Polygon 생성자를 호출하는 것을 확인할 수 있습니다.
class Polygon {
constructor() {
this.name = "Polygon";
}
}
class Square extends Polygon {
constructor() {
super();
}
}
class Rectangle {}
Object.setPrototypeOf(Square.prototype, Rectangle.prototype);
console.log(Object.getPrototypeOf(Square.prototype) === Polygon.prototype); //false
console.log(Object.getPrototypeOf(Square.prototype) === Rectangle.prototype); //true
let newInstance = new Square();
console.log(newInstance.name); //Polygon
출처
https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Classes/constructor
https://medium.com/@bluesh55/javascript-prototype-이해하기-f8e67c286b67
'웹 개념 > javascript' 카테고리의 다른 글
arguments 객체 (0) | 2022.04.20 |
---|---|
extends (0) | 2022.04.20 |
Object.create (0) | 2022.04.20 |
apply,call,bind (0) | 2022.04.20 |
__proto__ (0) | 2022.04.20 |