javascript객체 생성
전통적인 방법
var person = new Object();
person.name = "nick";
person.age = 29;
person.job = "software engineer";
person.doSomething = function(){
alert("hello");
};
-> 객체를 생성할 때 마다 동일한 코드를 추가해야함.
그래서,
factory pattern 등장
function createPerson( name, age, job ){
var o = new Object();
o.name = name;
o.age = age;
o.job = job;
o.doSomething = function(){
alert("hello");
};
return o;
}
var person1 = createPerson( "nick", 29, "software engineer" );
var person2 = createPerson( "jack", 30, "designer" );
-> 코드 중복은 해결했지만, 객체의 아이덴티피케이션(어떤 타입의 객체인가하는) 문제를 해결하지 못함.
그래서,
constructor pattern등장
function Person( name, age, job ){
this.name = name;
this.age = age;
this.job = job;
this.doSomething = function(){
alert("hello");
};
}
var person1 = new Person( "nick", 29, "software engineer" );
var person2 = new Person( "jack", 30, "designer" );
person1 instanceof Object // true;
person1 instanceof Person // true;
person2 instanceof Object // true;
person2 instanceof Person // true;
-> 객체의 타입 또한 알아낼 수 있게되었지만, 문제는 함수 객체가 동일한 기능을 수행하는데 각 인스턴스마다 생성되는 문제가 있다. 실제로 위 코드는 다음과 같다.
function Person( name, age, job ){
this.name = name;
this.age = age;
this.job = job;
this.doSomething = new Function("alert('hello')");
}
이로인해,
person1.doSomething == person2.doSomething // false
가 된다.
이를 다음과 같이 수정할 수 도 있다.
function Person( name, age, job ){
this.name = name;
this.age = age;
this.job = job;
this.doSomething = doSomething;
}
function doSomething(){
alert("hello");
}
하지만, 함수가 증가할 때마다 해당 함수에 대한 정의를 추가해줘야 한다는 문제가 있다.
이를 위해
Prototype Pattern이 등장
prototype은 특정한 타입의 레퍼런스의 인스턴스에서 사용할 수 있는 속성과 메소드를 담고있다.
function Person(){
}
Person.prototype.name = "nick";
Person.prototype.age = 29;
Person.prototype.job = "software engineer";
Person.prototype.doSomething = function(){
alert("hello");
}
var person1 = new Person();
person1.doSomething(); //hello
var person2 = new Person();
person2.doSomething(); //hello
person1.doSomething == person2.doSomething //true
person1, person2 모두 동일한 인스턴스(Person의)의 속성과 메소드를 공유한다.
이를 좀 정리해보면,

Person.prototype.isPrototypeOf(person1); //true
유의사항
function Person(){
}
Person.prototype.name = "nick";
Person.prototype.age = 29;
Person.prototype.job = "software engineer";
Person.prototype.doSomething = function(){
alert("hello");
}
var person1 = new Person();
var person2 = new Person();
person1.name = "tom";
alert(person1.name); //tom, from instance
alert(person2.name); //nick, from prototype
-> 객체의 인스턴스로 부터 프로토타입의 값을 읽어들이는 것은 가능하지만, 프로토타입의 값을 덮어쓰는 것은 불가능하다. 인스턴스에 속성을 추가하면 프로토타입 상에 속성과 동일한 이름을 같는 속성을 추가하는 것이 아니라, 인스턴스에 속성을 추가하는 것이다.
위 코드에 아래 코드를 이어서 추가하면,
delete person1.name;
alert(person1.name); //nick, from prototype
-> 객체 인스턴스 속성에 null을 추가하는 것은 해당 속성의 참조를 null로 만들고 해당 링크를 프로토타입의 속성으로 재연결하지 않는다. 하지만 delete연산자는 해당 속성을 삭제하고, prototype의 속성으로 재연결한다.
hasOwnProperty() // instance에 속한 속성인지, prototype에 속한 속성인지 구분하는 함수.
위의 샘플 코드에서,
person1.hasOwnProperty("name"); // true -> from instance
person2.hasOwnProperty("name"); // false -> from property
in 연산자 // instance나 prototype 중 둘 중하나에 포함된었는지 여부
function hasPrototypeProperty( object, name ){
return !object.hasOwnProperty(name) && ( name in object);
}
-> 위 메소드는 인스턴스 속성이 아닌, 오로지 프로토타입에만 정의되어 있는 속성인지를 판별
prototype의 또 다른 표현 방식
function Person(){
}
Person.prototype = {
name: "nick",
age:29,
job:"software engineer",
doSomething:function(){
alert("hello");
}
};
프로토타입을 오브젝트 리터럴 방식으로 생성한 방법으로 생성. 한 가지 다른 점은 생성자가 Person이 아니라서 위 프로토타입인 상태에서 new로 객체를 생성하면 Object생성자를 호출한다는 점.
var person = new Person();
person instanceof Object //true;
person instanceof Person//true;
person.constructor == Person //false
person.constructor == Object //true
아래와 같이 수정하면 된다.
function Person(){
}
Person.prototype = {
constructor:Person,
name:"nick",
age:29,
job:"software engineer",
doSomething:function (){
alert("hello");
}
};
prototype 패턴의 문제점.
function Person(){
}
Person.prototype = {
constructor:Person,
name:"nick",
age:29,
job:"software engineer",
friends: ["a","b"],
doSomething:function(){
alert("hello");
}
};
var person1 = new Person();
var person2 = new Person();
person1.friends.push("c");
person1.friends //a,b,c,
person2.friends //a,b,c,
참조로 존재하는 속성일 경우 하나의 인스턴스에서 수정한 값이 (의도하지 않게) 다른 인스턴스의 참조변수에도 영향을 준다는 점.
이로인해 생성자/prototype 조합 패턴을 가장 많이 사용.
function Person( name, age, job ){
this.name = name;
this.age = age;
this.job = job;
this.friends = ["a", "b", "c"];
}
Person.prototype = {
constructor:Person,
doSomething:function(){
alert("hello");
}
};
var person1 = new Person("nick", 29, "software engineer");
var person2 = new Person("tom", 27, "designer");
person1.friends.push("d");
person1.friends; //a,b,c,d
person2.friends; //a,b,c
person1.friends == person2.friends // false
person1.doSomething == person2.doSomething // true
상속
prototype chaning을 이용한 상속.
function SuperType(){
this.property = true;
}
SuperType.prototype.getSuperValue = function(){
return this.property;
};
function SubType(){
this.subproperty = false;
}
SubType.prototype = new SuperType();
SubType.prototype.getSubValue = function(){
return this.subproperty;
}
var instance = new SubType();
instance.getSuperValue(); // true;


위 코드에서
SubType.prototype.getSuperValue = function(){
return false;
}
var instance2 = new SubType();
instance2.getSuperValue(); // false
하지만 다음과 같이 프로토타입을 오버라이트 해버리면 안된다.
SubType.prototype = {
getSubValue: function(){
return this.subproperty;
},
getSuperValue: function(){
return false;
}
};
이 코드는 기존의 코드라인(SubType.prototype = new SuperType();)을 무력화시키고 null로만들어버린다.
이런 방식의 상속도 참조 형태의 속성을 가지고 있는 객체의 경우에 문제가 생긴다.
생성자 훔치기
function SuperType(){
this.color = ["r","g","b"];
}
function SubType(){
SuperType.call( this );
}
var instance1 = new SubType();
instance1.colors.push("a:);
instance1.colors // "r","g","b","a"
var instance2 = new SubType();
instance2.colors; // "r","g","b"
생성자에 매개변수 전달
function SuperType( name ) {
this.name = name;
}
function SubType(){
SuperType.call( this, "nick" );
this.age = 29;
}
var instance = new SubType();
instance.name //nick
instance.age // 29
생성자 훔치기 방법도 메소드재생성 문제를 지니고 있기때문에 이런 종합적인 문제를 해결하기 위해
조합 상속을 사용한다.
function SuperType( name ){
this.name = name;
this.colors = ["r", "g", "b"];
}
SuperType.prototype.doSomething = function(){
alert("hello");
};
SubType.prototype = new SuperType();
function SubType( name, age ){
SuperType.call( this, name );
this.age = age;
}
SubType.prototype.sayMyName = function(){
alert("my age is: "+this.age);
};
위와 같은 형태의 조합 상속이 보편적으로 가장 많이 사용되는 상속 방식이다.
function object( o ) {
function F(){}
F.prototype = o;
return new F();
}
function inheritPrototype ( subType, superType ){
var prototype = object( superType.prototype );
prototype.constructor = subType;
subType.prototype = prototype;
}
function SuperType( name ){
this.name = name;
this.colors = ["r","g","b"];
}
SuperType.prototype.doSomething = function(){
alert("hello");
}
function SubType( name, age ){
SuperType.call ( this, name );
this.age = age;
}
inheritPrototype( SubType, SuperType );
SubType.prototype.sayAge = function(){
alert(this.age);
};
Yahoo! User Interface(YUI) library 참고 할 것
http://developer.yahoo.com/yui/.




최근 덧글