javascript oop javascript

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/.


1 2 3 4 5 6 7 8 9 10 다음