prototype method는 인스턴스에서 직접 호출이 가능하나, static method는 생성자 함수를 this로 해야만 호출할 수 있다.
var Person = function (name, age) {
this.name = name;
this.age = age;
};
// prototype method -> prototype chaining에 의한 참조
Person.prototype.getIntroduce = function () {
return `hello my name is ${this.name}, and i'm ${this.age}`;
};
// static method
Person.getNameAndAge = function (name, age) {
return name + " : " + age;
};
var p = new Person("seoin", 27);
console.log(p.getIntroduce());
// console.log(p.getNameAndAge("seoin", 27)); -> error
console.log(Person.getNameAndAge("seoin", 27));
내장 명령으로 손쉽게 클래스 구현이 가능하다
class 키워드를 이용하고 상위 클래스는 extends 키워드를 이용해 상속한다.
class Person {
constructor(name, age) {
this.name = name || "이름없음";
this.age = age || "나이모름";
}
getName() {
return this.name;
}
getAge() {
return this.age;
}
}
class Saram extends Person {
constructor(name, age, address) {
super(name, age);
this.address = address || "지역모름";
}
getAddress() {
return this.address;
}
}
ES5까지 클래스가 없었고, ES6에 도입됐다. ES5에서 클래스를 구현하려면 어떻게 해왔을까를 예로 들어 봤다. (면접 질문으로 나올 거 같진 않다.)
var Person = function (name, age) {
this.name = name || "이름없음";
this.age = age || "나이모름";
};
// prototype method
Person.prototype.getName = function () {
return this.name;
};
Person.prototype.getAge = function () {
return this.age;
};
function Saram(name, age, address) {
this.name = name || "이름없음";
this.age = age || "나이모름";
this.address = address || "지역모름";
}
// 인스턴스의 프로토타입에 상위 객체의 인스턴스를 할당
// 기존에 있던 Saram.prototype은 사실상 새로 대체
// 프로토타입 객체는 js 엔진이 기본적으로 constructor 프로퍼티를 생성해주고, 그 안에 생성자 함수가 담김
// -> constructor 재정의 필요
Saram.prototype = new Person();
Saram.prototype.constructor = Saram;
Saram.prototype.getAddress = function () {
return this.address;
};
var s1 = new Saram("seoin", 27, "seoul");
console.dir(s1);
문제 -> 프로토타입 체인 상에 프로퍼티가 아닌 메소드만 존재하게 하는게 나음
→ 인스턴스에서 name, age 프로퍼티 삭제하고 getName, getAge 호출 시 체인을 타고 원하지 않은 결과를 출력
// 불필요한 프로퍼티 삭제하고 싶음 -> 중간에 비어 있는 생성자 함수를 넣어 연결
function Bridge() {}
Bridge.prototype = Person.prototype;
Saram.prototype = new Bridge();
Saram.prototype.constructor = Saram;
Saram.prototype.getAddress = function () {
return this.address;
};
var s2 = new Saram("seoin", 27, "seoul");
console.dir(s2);
위의 방식이 ES5에서 클래스 상속을 구현하려 할 때 많이 등장하는 패턴이라고 함
Bridge 함수는 매개체 역할만 할 뿐, 실제 코드 상에서는 영향을 주지 않음
더글라스 크락포드 → 함수화 추천
var extendClass = (function () {
function Bridge() {}
return function (Parent, Child) {
Bridge.prototype = Parent.prototype;
Child.prototype = new Bridge();
Child.prototype.constructor = Child;
};
})();
위와 같이 클로저를 이용해 Bridge 생성자 함수는 한 번만 생성해 계속 재활용 하고, super와 sub 클래스로 쓰일 생성자 함수를 매개변수로 넘겨주면, 자동으로 둘 사이의 상속 구조를 구현할 수 있음
extendClass(Person, Saram);
Saram.prototype.getAddress = function () {
return this.address;
};
var s3 = new Saram("seoin", 27, "seoul");
console.dir(s3);
메서드 상속에 이어 인스턴스의 value까지 상속을 이용한다면, 아래와 같이 쓸 수 있다.
var extendClass = (function () {
function Bridge() {}
return function (Parent, Child) {
Bridge.prototype = Parent.prototype;
Child.prototype = new Bridge();
Child.prototype.constructor = Child;
Child.prototype.superClass = Parent;
};
})();
function Saram(name, age, address) {
this.superClass(name, age);
this.address = address || "지역모름";
}