본문 바로가기
Javascript

자바스크립트(javascript) 객체

by 램쥐뱅 2016. 8. 30.

1. 클래스 기반의 객체지향


보통 객체지향이라고 하면 클래스 기반의 객체지향을 주로 의미한다.

객체지향의 특성을 잠시 정리해본다.


1) 객체, 메서드, 속성

2) 클래스

3) 캡슐화

4) 집합

5) 상속성

6) 다형성


위와 같은 객체지향적인 특징을 자바스크립트로는 어떻게 구현할까?



캡슐화


캡슐화와 함께 나오는 개념으로 정보은닉(information hiding) 이 있다.

내부의 구현이 어떻게 되어있는지 어떻게동작을 하는지는 사용자에게 숨겨져 있다.

자바스크립트에서는 모든 메서드, 속은은 공개(public)로 정의된다. 그러나 비공개(private)특징을 구현하는 방법이 있다.




집합


몇 개의 객체를 합쳐서 하나의 객체로 만드는 것을 집합이라고 한다.

이러한 집합 개념은 문제를 좀 더 작고 관리 수 있는 부분으로 나눠서 분리할수 있는 방법이다.

예를들어 컴퓨터라는 객체를 설계한다면 동시에 컴퓨터 전체를 설계하기보다는 모니터 객체, 마우스 객체, 키보드 객체 등의 각 부분으로 나눠서 나중에 합치는 것이 더 효율적일 것이다.

자바스크립트도 이런 집합 특징은 기본적으로 지원 한다.




상속


객체지향 프로그래밍에서 상속이랑 이미 존재하는 코드를 재사용하거나 기존 코드를 확장 하는 좋은 방법이다.

일반 객체지향언어에서는 클래스 차원에서 상속을 지원하지만 자바스크립트에서는 클래스 상속은 없다.

대신 프로토타입을 이용한 객체 차원의 상속을 지원한다.




다형성


프로그램 언어의 각 요소들(상수, 변수, 식, 오브젝트, 함수, 메소드 등)이 다양한 자료형(type)에 속하는 것이 허가되는 성질이라고 표현할수 있는데 자바스크립트도 마찬가지로 지원한다.





2. 객체 생성



객체 생성자.


객체지향언어는 객체를 생성할 수 있는 방법이 있어야 한다.

자바스크립트에는 C#, 자바 같은 일반 객체지향 언어와는 다르게 클래스가 존재하지 않는다.


자바스크립트에서는 함수가 다른 언어에서의 클래스를 대신해서 객체를 정의하고 생성하는 데 사용된다.


객체를 생성하는데 사용되는 함수, 함수 역할 3을 하는데 사용되는 함수를 특별히 생성자(constructor)라고 한다.




객체의 정의 및 생성


동일한 멤버를 가진 객체를 만들어 내기 위해 일반 객체지향 언어와 자바스크립트는 상당히 다른 구문을 사용한다.

자바스크립트에서는 개체를 만들어 내는 방법이 3가지가 있다.


1) new 와 Object 생성자 이용 ex) new Object()

2) 객체 리터럴 이용. ex) {}

3) new와 사용자 정의 생성자 이용 ex) new Person()


방법 1, 2 는 자바스크립트에 내장되어 있는 Object 객체의 구조를 정의하고 생성하는 방법이다.

방법 3은 사용자가 객체를 생성하는 함수를 직접 정의해서 객체를 생성하는 방법이다.




자바스크립트 내장(built-in) 생성자


앞에서 언급된 Object라는 함수 처럼 자바스크립트에서 기본적으로 제공해주는 생성자는 많다.


String, Number, Boolean, Array, Datem Function, Object, RegExp, Math 등


위와 같은 함수를 생성자라고 부를는대신 "내장 타입" 또는 "내장 객체", "내장 함수" 라고 해도 될 것 이다.


중요한 것은 표현의 문제가 아니라 모두 생성자의 역할을 해서 객체의 초기 구조를 정의하고 있고 객체를 생성하는데 사용할 수 있다는 것이다.


내장 되어 있는 함수라고 해서 특별한 것은 없다.

프로그램이 시작되면 자바스크립트 엔진은 다음과 유사하게 정의된 함수를 기본적으로 메모리에 정의한다고 이해하면 된다.


function Object(){

 //...

}


function String(){

 //...

}


function Number(){

 //...

}


function Function(){

 //...

}

....


이러한 내장함수는 개발자의 편의와 특별한 목적을 위해 자바스크립트에서 특별히 부여한 기능을 지는 멤버가 사전에 정의되어 더해져 있을뿐, 일반 함수가 지는 모든 특성을 그대로 가진다.


내장 생성자도 함수 모델을 그대로 따른다.


내장 타입 가운에 Math라는 것은 사실 함수가 아니다. 루트 객체에 Math라는 속성으로 노출시켜 놓은 것이다. 

따라서 객체를 생성할 필요없이 Math.pow(), Math.random(), Math.PI 처럼 Math의 멤버만 잘 사용하면 된다.


자바스크립트에서는 미리 정의해 놓은 객체와 동일한 이름의 객체를 정의하는 것을 막고 있지 않다.

따라서 개발자는 주의해서 함수의 이름을 정의해야 한다.




함수와 클래스의 차이점


함수가 객체를 생성하는 역할을 하지만 클래스와 동일한 개념은 아니다.


클래스를 사용하는 언어는 강력한 타입의 언어이다.

강력한 타입의 언어는 객체의 타입만 보고도 그 객체가 어떤구조로 되어 있느지 알수 있고, 또한 변수 에는 선언된 타입의 값만을 할당할 수 있다.


자바스크립트 언어에서는 함수에 전달되는 객체가 어떤 타입인지는 중요하지도 않고 타입 체크도 하지 않는다.


자바스크립트의 타입 시스템에서는 객체에 속성과 메서드가 존재하는지 여부는 해당 객체의 타입을 통해서가 아니라 실제 런타임에 호출해봐야 알 수 있다.


다음으로 클래스로 생성된 객체의 구조는 고정적이지만, 자바스크립트 객체의 구조는 런타임에 언제든지 변경될 수 있다.


객체를 생성한 후에 객체의 멤버를 추가, 제거, 대체하면서 구조를 런타임에 변경해서 최종적으로 원하는 객체의 구조를 만들어 낼 수 있다. 따라서 함수, 즉 생성자는 객체의 구조 결정 이라기보다는 객체의 초기 구조 결적 이라고 해야한다.

런타임에 멤버들을 동적으로 추가/제거 할 수 있다는 것은 자바스크립트의 기본적인 특징 이다.


자바스크립트에서는 객체의 구조를 런타임에 언제든지 변경할 수 있다.



자바스크립트언어의 타입 체계의 특징은 다음과 같다.


 특징 

 설명

 타입 체크를 수행하지 않음

 컴파일 시에 타입체크를 하지 않는다. 런타임에 원하는 멤버만 있으면 된다. 

 객체 초기 구조 결정

 생성자는 생성되는 객체의 최초 구조를 결정한다. 

 객체 구조 변경

 생성된 인스턴스의 속성, 메소드를 런타임에 언제든지 추가, 제거, 대체 할수 있다. 





3. Object객체 정의 1 - new Object


자바스크립트에서는 객체를 생성하기 위해 함수를 호출할 때 new를 사용한다.

new와 함께 사용되어 새로운 객체를 생성하는 함수를 앞에서 말했듯이 생성자(constructor)라고 한다.


흔히 내장(built-in) 객체 또는 전역 객체(global object) 또는 타입이라고 하는 Object, Array도 사실 그 실체는 함수이다.

이것들을 어떻게 부르든 object와 Array의 본질은 함수다.


Object, Array등 내장 객체의 본질은 함수다.


Object처럼 미리 제공되는 생성자의 경우 멤버는 이미 정의되어 있기 때문에 저으이 단계는 건너띄고 객체를 생성하는 단계만 수행하면 된다.


var mySon = new Object();


위 코드를 통해 사용자 정의 멤버가 없는 기본적인 Object 객체가 mySon이라는 이름으로 생성된다.


mySon.Name = "jusungPark";

mySon.Age = 27;

mySon.IncreaseAge = function(i){ this.Age = this.Age + i; };


객체 생성 후 위와같이 사용자 정의 멤버를 추가할수 있다.





4. Object객체 정의 2 - 객체 리터럴


Object 객체의 구조를 정의하고 생성하는 구문을 하나로 합칠 수 있어서 new 와 Object 생성자를 이용해 객체를 생성하고 필요한 구조를 만들어가는 과정을 좀 더 간소화 할 수 있다.

그래서, 코드가 간결해지고 가독성(readabilty)이 높아진다. 때문에 객체 생성 구문으로 많이 사용된다.


var mySon = {

Name : "jusungPark",

Age : 27,

IncreaseAge : function(i){ this.Age = this.Age + i; };

};


전체 객체의 멤버가 {} 내부에 콤마(,)로 구분되어 있다. 그리고 다시 각 멤버는 콜론(:)으로 이름과 초기값이 구분되어 있다.


객체 리터럴을 이용해 객체를 생성하는 방법과 Object 생성자를 이용해 객체를 생성하는 방법의 내부적인 절차는 동일하다.


객체 리터럴을 사용해 객체를 생성하는 방법은 내부적으로 new Object를 수행한 후 멤버를 구성하는 방법과 동일한 절차를 따른다.


이렇게 정의된 멤버는 모두 외부에서 접근할 수 있는 공개 멤버이다.

비공개 멤버를 구현 방법은 자바스크립트 객체멤버에서 정리한다.


리터럴 표현에서 this는 {}로 생성되는 객체를 가리킨다.
따라서 this.Age 는 mySon.Age와 동일한 표현이다.


아무도 멤버도 없는 Object 객체를 생성하고 싶다면 다음과 같이 하면된다.


var obj = {};


이는 다음 코드와 동일하다.


var obj = new Object();


앞의 mySon과 동일한 구조의 객체는 객체 리터럴 표현을 이용해 다음과 같은 방법으로도 만들 수 있다.


var mySon = {};

mySon.Name = "jusungPark";

mySon.Age = 27;

mySon.IncreaseAge = function(i){ this.Age = this.Age + i; };


객체리터럴을 사용해 속성에 다른 객체를 할당하는 중첩된 표현도 가능하다.


var teacherName = "Prof. Park";

var mySon = {

Name : "jusungPark",

Age : 27,

Parent : {

Name : "Park",

Job : "Freelancer"

},

Etc : this.Name + ", Prof. name : "+teacherName;

};


Parent 의 Job 속성에 대해서는 아래와 같이 접근할수 있다.


mySon.Parent.Job


실제 jQuery 같은 라이브러리를 보면 new Object 보다 Object 리터럴 표현을 자주 사용하고 있음을 알수 있다.


jQuery.fn = {

constructor : jQuery,

init : fucntion() {...},

selector : "",

length : 0,

size : function() {...}

...

}


함수를 호출할 때 전달할 인자값도 객체 리터럴 표현을 이용해 구성하는 코드를 자주 볼수 있다.


function OpenWindow(options){

var url = options.path || 'blank';

var name = option.windowName || 'defaultName';

var option = options.windowOptions || 'width=100,height=100';

window.open(url, name, option);

}


var options = { path : 'http://jusungpark.tistory.com', windowName : 'jusungPark Blog'}

OpenWindow(options);





5. Object객체 정의 3 - 사용자 정의 객체 정의


일반 객체지향 언어에서 클래스를 사용해 객체를 생성하는 방법과 가장 유사한 방법이다.




객체 정의


사용자 정의의 객체를 정의하기 위해 자바스크립트에서는 class라는 키워드 대신 function을 사용한다.


fucntion Person(name) {

this.name = name;

}


객체를 정의할 때 function 키워드를 사용한다면 그냥 함수를 정의할 때 사용하는 function과는 어떤 차이가 있을까 ?


단도직입적으로 말하면 함수의 function과 객체를 생성할 때의 function은 동일 하다.


앞서 "자바스크립트 함수의 역할" 글에서 정리한 내용처럼, 동일한 함수가 호출 가능한 요소로도 사용될 수 있고(역할 1) 다른 객체를 생성하는 요소로도 사용될수 있다. (역할 3)

역할1과 역할3 가운데 어떤 역할로 사용될지는 주변 실행 환경, 즉 연산자에 따라 달라진다.

new 와 함께 사용되면 메모리에 인스턴스를 생성하는 역할로 사용된다.

단순히 ()연산자를 사용해 Person("jusungPark") 과 같이 호출하면 일반 함수처럼 사용된다.


지금부터는 일반 함수와 생성자를 구분하고자 일반 함수는 소문자로, 생성자는 대문자로 시작하는 이름 작명 규칙을 사용할 것이다.




멤버 정의


자바스크립트에서는 멤버를 추가할 때 this를 사용한다.


this.name = name;


위와 같은 코드는 Person 객체에 name이라는 공개 속성(public property)을 정의한다.


메서드를 정의하고자 한다면 익명 함수를 이용할 수 있다.


this.setnewName = function(newName) { this.name = newName; };


멤버를 정의한 Person 생성자는 다음과 같다.


function Person(name) {

this.name = name;

this.setnewName = function(newName) { this.name = newName; };

}




객체 생성


이제 Person 생성자를 new 키와드와 함께 호출하면 객체를 생성할 수 있다.


var mySon = new Person(name);


생성자는 최초 생성되는 객체의 멤버 구조를 정의하고 그 값을 초기화 하는 역할을 한다.


자바스크립트 생성자 = 객체 초기 구조 정의 & 객체 초기화.


자바스크립트에서는 new를 이용해 Person 생성자를 호출하는 구문이 다양하다.


var mySon = new Person("jusungPark");

var mySon = new Person();    // 생성자 매개변수 name 의 undefined로 설정됨.

var mySon = new Person;     // 생성자 매개변수 name 의 undefined로 설정됨.


생성자를 new와 함께 사용할 때는 세번째 구문처럼 () 연산자를 생략해도 된다.


생성자를 호출할떄 new Person(), new Person처럼 인자없이 인스턴스를 생성하면 name 은 undefined로 설정된다.

"함수 인자" 절에서 함수를 호출할 때 인자를 정의된 대로 전달하지 않아도 된다고 했다. (외부로부터 값을 전달받지 못한 함수의 매개변수는 undefined로 초기화 된다.)

이런 일반 함수의 특징은 그대로 생성자에 적용되는 것이다.


this로 정의된 멤버는 new로 생성되는 인스턴스별로 별도로 존재한다.


앞으로 this를 통해 정의된 멤버를 인스턴스 멤버라고 설명할 것이다.


인스턴스 멤버는 뒤에 설명될 프로토타입 멤버(prototype member)와 대비되는 개념이다.

프로토타입 멤버는 동일한 생성자로 생성되는 모든 객체(인스턴스)가 공유할수 있는 멤버로서, 그 값이 변경되면 해당 생성자로 생성된 모든 객체에 영향을 준다. (Java 의 클래스 멤버인 static 변수)

그에 반해 인스턴스 멤버의 변경을 해당 객체에만 영향을 준다.


자바스크립트는 프로토타입 멤버 중심이다.

객체를 설계하거나 상속을 설계할 때 모두 프로토타입객체를 기준으로 한다.

따라서 자바스크립트는 프로토타입 기반의 객체지향 언어라고 한다.


자바스크립트는 프로토타입 기반의 객체지향을 지원한다.














참고.


자바스크립트 객체지향 프로그래밍.

댓글