1.클래스 기능을 가진 subClass 함수
- 구현 방법
· 함수의 프로토타입 체인
· extend 함수
· 인스턴스를 생성할 때 생성자 호출(여기서 생성자를 _init 함수로 정한다.)
1)subClass 함수 구조
subClass는 상속받을 클래스에 넣을 변수 및 메서드가 담긴 객체를 인자로 받아 부모 함수를 상속받는 자식 클래스를 만든다. 여기서 부모 함수는 subClass() 함수를 호출할 때 this 객체를 의미한다.
var SuperClass = subClass(obj);
var SubClass = SuperClass.subClass(obj);
이처럼 SuperClass를 상속받는 subClass를 만들고자 할 때, SuperCalss.subClass()의 형식으로 호출하게 구현한다.
참고로 최상위 클래스인 SuperClass는 자바스크립트의 Function을 상속받게 한다.
- 함수 subClass의 구조
function subClass(obj){
/* (1) 자식 클래스 (함수 객체) 생성 */
/* (2) 생성자 호출 */
/* (3) 프로토타입 체인을 활용한 상속 구현 */
/* (4) obj를 통해 들어온 변수 및 메서드를 자식 클래스에 추가 */
/* (5) 자식 함수 객체 반환 */
}
2) 자식 클래스 생성 및 상속
function subClass(obj){
var parent = this;
var F = function(){};
var child = function(){
};
/* 프로토타입 체이닝 */
F.prototype = parent.prototype;
child.prototype = new F();
child.prototype.constructor = child;
child.parent = parent.prototype;
child.parent_constructor = parent;
return child;
}
3)자식 클래스 확장
for(var i in obj){
if(obj.hasOwnProperty(i)){
child.prototype[i] = obj[i];
}
}
※ hasOwnProperty 메서드
Object.prototype 프로퍼티에 정의되어 있는 메서드로서, 인자로 넘기는 이름에 해당하는 프로퍼티가 객체 내에 있는지를 판단한다. 여기서 프로퍼티를 찾을 때, 다음 예제와 같이 프로토타입 체인을 타고 올라가지 안혹 해당 객체 내에서만 찾는다는 것에 유의해야 한다.
4)생성자 호출
var child = function(){
if(parent._init){
parent._init.apply(this, arguments);
}
if(child.prototype._init){
child.prototype._init.apply(this, arguments);
}
};
--> _init을 찾을 때 _init 프로퍼티가 없으면 프로토타입 체인으로 상위클래스의 _init을 찾아서 호출할 수 있다.
- hasOwnProperty 함수 사용
var child = function(){
if(parent.hasOwnProperty("_init")){
parent._init.apply(this, arguments);
}
if(child.prototype.hasOwnProperty("_init")){
child.prototype._init.apply(this, arguments);
}
};
- 자식을 또 다른 함수가 다시 상속받았을 경우
var SuperClass = subClass();
var SubClass = SuperClass.subClass();
var Sub_SubClass = SubClass.subClass();
var instance = new Sub_SubClass();
--> 부모 클래스의 생성자를 호출하는 코드는 재귀적으로 구현할 필요가 있다.
- child.parent_constructor에 부모의 생성자 함수를 참조시키면 문제가 없다.
var child = function(){
var _parent = child.parent_constructor;
if(_parent && _parent !== Function){
//현재 클래스의 부모 생성자가 있으면 그 함수를 호출한다.
//다만 부모가 Function인 경우는 최상위 클래스에 도달했으므로 실행하지 않는다.
_parrent.apply(this, arguments); // 부모 함수의 재귀적 호출
}
if(child.prototype.hasOwnProperty("_init")){
child.prototype._init.apply(this, arguments);
}
};
5)subClass 보완
- parent를 단순히 this.prototype으로 지정해서는 안된다.
· parent = this
if(this === window){
var parent = Function;
}
else{
var parent = this;
}
- 이를 더 깔끔하게
var parent = this === window? Function : this; // Node.js의 경우에는 global을 사용한다.
// subClass 안에서 생성하는 자식 클래스의 역할을 하는 함수는 subClass 함수가 있어야 한다.
child.subClass = arguments.callee;
만들어진 subClass 함수의 전체 코드
function subClass(obj){
var parent = this === window ? Function : this;
//Node.js의 경우에는 global을 사용한다.
var F = function(){};
var child = function(){
var _parent = child.parent;
if(_parent && _parent !== Fucntion){
_parent.apply(this, arguments);
}
if(child.prototype._init){
child.prototype._init.apply(this, arguements);
}
};
F.prototype = parent.prototype;
child.prototype = new F();
child.prototype.constructor = child;
child.parent = parent;
child.subClass = arguments.callee;
for(var i in Obj){
if(obj.hasOwnProperty(i)){
child.prototype[i] = obj[i];
}
}
return child;
}
6)subClass 활용
var person_obj = {
_init : function(){
console.log("person init");
},
getName : function(){
return this._name;
},
setName : function(name){
tihs._name = name;
}
};
var student_obj = {
_init : function(){
console.log("student init");
},
getName : function(){
return "Student Name: " + this.name;
}
};
var Person = subClass(person_obj); //Person 클래스 정의
var person = new Person(); // person init 출력
person.setName("zzoon");
console.log(person.getName()); // 출력값 : zzoon
var Student = Person.subClass(student_obj); // Student 클래스 정의
var student = new Student(); // person init, student init 출력
student.setName("iamhjoo");
console.log(student.getName()); // 출력 결과 : Student Name : iamhjoo
console.log(Person.toString()); // Person이 Function을 상속받는지 확인
- 체크 포인트
· 생성자 함수가 호출되는가?
· 부모의 메서드가 자식 인스턴스에서 호출되는가?
· 자식 클래스가 확장 가능한가?
· 최상위 클래스인 Person은 Function을 상속받는가?
7)subClass 함수에 클로저 적용
var subClass = function(obj){
var parent = this === window ? Function : this;
//Node.js의 경우에는 global을 사용한다.
var F = function(){};
var subclass = function(obj){
var _parent = child.parent;
if(_parent && _parent !== Fucntion){
_parent.apply(this, arguments);
}
if(child.prototype._init){
child.prototype._init.apply(this, arguements);
}
};
F.prototype = parent.prototype;
child.prototype = new F();
child.prototype.constructor = child;
child.parent = parent;
child.subClass = arguments.callee;
for(var i in Obj){
if(obj.hasOwnProperty(i)){
child.prototype[i] = obj[i];
}
}
return subClass;
}();
- 즉시 실행 함수로 새로운 컨텍스트를 만들어서 F() 함수 객체를 생성하였다. 그리고 이 F() 함수 객체를 참조하는 안쪽의 subClass() 함수를 반환받는다. 이렇게 하면 F() 함수 객체는 클로저에 엮여서 가비지 컬렉션의 대상이 되지 않고, subClass()함수를 호출할 때 마다 사용된다.
2. subClass 함수와 모듈 패턴을 이용한 객체지향 프로그래밍
- 정보를 은닉할 때 모듈패턴은 상당히 유용하다.
var person = function(arg){
var name = undefined;
return {
_init : function(arg){
name = arg ? arg : "zzoon";
},
getName : function(){
return name;
},
setName : function(arg){
name = arg;
}
};
}
Person = subClass(person());
var iamhjoo = new Person("iamhjoo");
console.log(iamhjoo.getName());
Student = Person.subClass();
var student = new Student("student");
console.log(student.getName());
person 함수 객체는 name의 정보를 캡슐화시킨 객체를 반환받는 역할을 한다. 이렇게 받환받은 객체는 subClass() 함수의 인자로 들어가 클래스의 역할을 하는 Person 함수 객체를 완성시킬 수 있다.
'Language > Java Script' 카테고리의 다른 글
jQuery (0) | 2020.03.05 |
---|---|
함수형 프로그래밍 (0) | 2020.03.05 |
객체지향 프로그래밍 (0) | 2020.03.04 |
자바스크립트 클로저 (0) | 2020.02.24 |
자바스크립트 스코프 체인 (0) | 2020.02.24 |