ECMAScript명세의 JavaScript언어 내장객체인 Native object 중 JavaScript언어에서 가장 많이 접할 수 있는 Object(객체)에 대해서 알아보려 한다.
객체: 키와 값으로 구성된 프로퍼티(property)들의 집합, JavaScript를 이루고 있는 거의 모든 것(원시타입 제외) 이 객체(Object)이다. ex) 함수, 배열, 정규표현식 등
JavaScript의 객체는 객체지향의 상속을 구현하기 위해 "프로토타입(prototype)" 이라고 불리는 객체의 프로퍼티와 메소드를 상속 받을 수 있다.
* 프로토 타입에 대해서는 추후에 기록할 예정이다.
객체에 대한 기록 순서는 다음과 같다.
1. 객체 타입
2. 객체 생성방법
3. 객체 속성 접근방법
1. 객체 타입
객체(Object) 타입을 설명하기 전에 JavaScript에서의 자료형에 대해서 먼저 알아보자.
원시 타입: 문자열, 숫자, Boolean, null, undefined
객체 타입(참조 타입): 객체, 배열, 함수 등
원시 타입과 객체 타입에 가장 큰 차이점은 Immutability(변경 불가성)에 포함 여부이다.
원시타입
원시타입은 값이 복사되어 전달된다. 이를 Pass-by-value(값에 의한 전달)이라고 하는데, 이들의 값은 정적이기 때문에 런타임(변수 할당시점)에 메모리 스택 영역에 고정된 메모리 영역을 점유하고 저장된다.
위에 코드를 보게 되면 이렇게 진행이 된다.
1. 변수 x 의 원시타입 숫자 데이터를 할당
2. x의 변수 값을 y 변수에 복사
3. 변수 x의 값을 변경
4. y의 값은 변경되지 않은 채 숫자 100이 출력
좀 전에도 설명 하였듯이, 원시 타입 데이터는 변수에 할당 될 때 메모리 상에 고정된 크기로 저장되고, 원시 데이터 값을 보관하기 문에, 해당 데이터의 값이 직접 복사된다.
즉, 원시타입은 값이 정해지면 변경할 수 없다. 객체의 값을 복사 하더라도 원본 데이터 값이 변하지 않으므로 불변적(Immutable)이라 할 수 있다.
객체타입(참조타입)
이에 반해 객체 타입(참조 타입)은 객체의 모든 연산이 실제 값이 아닌 참조값으로 처리된다. 이를 pass-by-reference 라고 하는데, 원시 타입은 값이 정해지면 변경할 수 없지만(Immutable), 참조 타입은 변경이 가능하다.(mutable)
객체 타입(참조 타입)은 값이 동적으로 변화할 수 있으므로, 어느 정도의 메모리 공간을 확보해야 하는지 예측할 수 없다.
그렇기 때문에 런타임(변수 할당 시점)에 메모리 공간을 확보하고 스택 영역이 아닌 힙 영역에 저장된다.
위에 코드는 다음과 같이 진행된다.
1. 변수 x 의 객체타입(참조타입) 객체 데이터를 할당
2. x의 변수 값을 y 변수에 복사
3. 객체 프로퍼티 값을 변경
4. 객체는 객체타입(참조타입)이기 때문에, y는 x와 동일한 객체를 가리키므로, 숫자 99가 출력
다시 그림을 이용하여 살펴보자.
1. 변수 x는 객체 리터럴 방식으로 객체를 생성하였는데, 변수 x는 객체 자체를 저장하고 있는 것이 아니라 생성된 객체의 참조값을 저장하고 있다.
2. 변수 y에 변수 x의 값을 할당할 때, 변수 x의 값은 생성된 객체를 가리키는 참조값이므로, 변수 y에도 같은 참조값이 저장된다. 이때 변수 x와 y는 동일한 객체를 참조하고 있다.
3. 동일한 객체를 참조하고 있는 값을 변경하게 되면 변수 x와 y는 동일한 객체를 참조하고 있기 때문에, 두 변수 모두 변경된 객체의 프로퍼티 값을 참조하게 된다.
즉, 객체타입(참조타입)은 값이 동적으로 변화할 수 있다. 객체의 값을 복사 하게되면 동일한 객체를 참조하고 있으므로 원본 데이터 값은 변한다. 그러므로 불변적(Immutable)이라 할 수 없다.
2. 객체 생성 방법
객체를 생성하는 방법은 총 3가지로 나뉘어 진다.
- 객체 리터럴
- Object 생성자 함수
- 생성자 함수
객체 리터럴
중괄호({})를 사용하여 객체를 생성하는데, 가장 일반적인 객체 생성 방식을 객체 리터럴(object literal)이라고 부른다.
중괄호({}) 내에 아무것도 기술하지 않으면 빈객체가 생성되는데 텅 빈 객체기 때문에 필요한 상황에 알맞게 사용하기가 힘들다.
다음 코드는 person 변수에 이름과 나이, 성별, 취미, 그리고 몇가지 메소드들을 통해 기능들을 객체 리터럴 방식으로 객체를 구성해보겠다.
* 객체 메소드 안에 선언되어 있는 this 키워드는 this 기록 페이지에서 알아볼 예정이다. 여기서는 object(객체)만 다룬다.
person 객체는 문자열, 숫자들이 배열로 구성되어 있고, 두개의 함수를 가지고 있다.
name, age, gender, interests 들은 데이터의 아이템들인데, 이것을 객체의 속성(Property)라고 부른다.
속성(Property): 프로퍼티는 키와 값으로 구성된다. 키는 프로퍼티를 식별하기 위한 식별자이고, 값은 키에 대한 값이다. 프로퍼티 키에는 빈 문자열을 포함하는 모든 문자열 또는 symbol 값이 들어 갈수 있고, 암묵적으로 타입이 변환되어 문자열이 된다. 만약 프로퍼티 키를 중복선언하면 나중에 선언한 프로퍼티가 먼저 선언한 프로퍼티를 덮어쓴다. 프로퍼티 값에는 모든 값이 들어갈 수 있다. 객체는 프로퍼티를 열거할 때 배열과 달리 순서를 보장하지 않는다.
또한 끝에 greet(), intro() 두개의 아이템은 함수인데, 이 함수를 통해 작성된 데이터 아이템들을 가지고 기능들을 만들 수 있습니다. 객체 안에 포함되어 있는 함수들은 메소드라고 부른다.
메소드: 객체에 제한되어 있는 함수를 의미한다.
Object 생성자 함수
객체 리터럴 방식과 다르게 Object 생성자 함수를 통해 객체를 생성할 때는 두가지 키워드를 알아야 한다.
1. new 연산자
2. 생성자 함수
new 연산자: 클래스 타입의 인스턴스(객체)를 생성해주는 역할을 담당한다 new 연산자를 통해 메모리(Heap 영역)에 데이터를 저장할 공간을 할당받고 그 공간의 참조값(reference value /해시코드)을 객체에게 반환하여 주고 이어서 생성자를 호출하게 된다.
생성자 함수: new 키워드와 함께 객체를 생성하고 초기화하는 함수를 의미, 생성자 함수의 이름은 파스칼 케이스를 사용하는 것이 일반적이다.
* 파스칼 케이스: 첫 단어를 대문자로 시작하는 표기법 ex) PascalCase
생성자 함수를 통해 생성된 객체를 인스턴스(Instance)라고 하는데, 아래 코드를 통해 더 자세히 알아보자.
Object 생성자 함수를 호출하여 객체를 생성할 때 보통 빈 객체를 생성한 이후 프로퍼티 또는 메소드를 추가하여 객체를 완성한다.
객체 리터럴 방식과 Object 생성자 함수 방식을 굳이 비교하자면, 객체 리터럴 방식이 훨씬 쉽고 간편하다.
사실 객체 리터럴 방식으로 생성된 객체는 Object 생성자 함수로 객체를 생성하는 것을 단순화시킨 축약표현이다.
생성자 함수
만약 동일한 프로퍼티를 갖는 객체의 값만 다를 경우, 앞서 살펴 보았던 객체 리터럴 방식과 Object 생성자 함수 방식으로 객체를 생성하는 것은 굉장히 비효율적인 방법이다. 왜냐하면 매번 같은 프로퍼티를 기술해야 하기 때문이다.
위에 예시를 보면, 코드가 길어지고, 중복되는 코드들이 발생하는 것을 볼 수 있다.
이때 사용하는 것이 생성자 함수 방식이다.
생성자 함수 방식의 특징은 다음과 같다.
1. 생성자 함수 이름은 일반적으로 대문자로 시작한다.
2. this는 생성자 함수가 생성할 인스턴스를 가리킨다.
3. this에 바인딩되어 있는 객체의 프로퍼티와 메소드는 외부에서 참조가 가능하다.
4. 생성자 함수 내에서 선언된 일반 변수는 외부에서 참조가 불가능하다.
* 객체 메소드 안에 선언되어 있는 this 키워드는 this 기록 페이지에서 알아볼 예정이다. 여기서는 object(객체)만 다룬다.
3. 객체 속성 접근 방법
객체를 접근하는 방식은 객체 리터럴 방식으로 설명하려고 한다.
현재 생성되어 있는 객체에 2가지 방법을 사용하여 접근할 수 있다.
- 점 표기법
- 괄호 표기법
점표기법
위에 코드는 점 표기법을 이용해 객체의 속성(property)와 메소드에 접근하였다. 객체내에 캡슐화되어있는 것에 접근하려면 객체의 변수를 먼저 입력하고, 점을찍고, 접근하고자 하는 항목을 적으면 된다.
객체의 이름은 네임스페이스처럼 동작하기때문에, 프로퍼티나, 배열의 일부, 그리고 메소드를 호출할 수 있다.
그럼 만약 이렇게 작성되어 있는 객체는 어떻게 접근하면 될까?
객체 안에 여러 객체 멤버들의 데이터들을 선언할 수도 있는데, 이를 하위 네임스페이스라고 한다.
객체 안에 객체가 있고 그 객체 안에 객체의 속성이 존재하니, 다음과 같은 코드로 속성에 접근할 수 있다.
좀 전과는 다르게 끝에 다른 점을 하나 더 찍어주면 된다.
괄호표기법
또 다른 방법으로는 괄호표기법을 사용할 수 있는 객체의 접근할 수 있는 방법은 다음과 같다.
괄호표기법에 접근할 수 있는 방법은 배열 속에 있는 항목에 접근하는 방법과 유사한데, 실제로도 이는 동일한 접근 방법이다.
인덱스 숫자를 이용하여 접근하는 배열과는 달리 괄호표기법은 각 멤버의 값들과 연결된 이름을 이용하여 접근한다.
지금까지는 객체 멤버를 단순히 가져와 콘솔 창에 찍어보는 예제들만 살펴보았다.
지금부터는 이미 선언된 객체멤버에 값을 설정(갱신)하는 방법을 살펴보도록 하자.
person 객체의 초기값에 데이터들을 선언한 위에서 보았던 코드와는 달리, person 객체의 초기값을 빈 값으로 선언하고, 객체의 멤버들을(속성, 메소드) 점표기법을 통하여 설정(갱신)하였다.
console.log() 함수를 이용하여 객체의 속성과 메소드의 값을 출력해보니, 위에 코드와 같은 결과를 볼 수 있다.
대괄호 표기법도 점 표기법과 마찬가지로 객체 멤버의 값을 설정(갱신)할 수 있다. (여기서는 점 표기법만을 사용하겠다.)
초기값으로 객체 속성의 값을 선언하고, 이후 점표기법을 사용해 객체 속성에 접근하여 값을 변경(갱신)하는 것 또한 가능하다.
다음 기록은 Array(배열)이다.
< 참고자료 >
[도서] You don't know JS - 카일심슨 지음-
https://developer.mozilla.org/ko/docs/Learn/JavaScript/Objects/Basics
<ES5 series> chapter 5, Object(객체) end
'Language & Framework & Library > JavaScript' 카테고리의 다른 글
ES5 .Intro(2) - 데이터 타입 (0) | 2019.12.10 |
---|---|
ES5 .Object(2) - Array(배열) (2) | 2019.11.26 |
ES5 .Object(0) - Intro (0) | 2019.11.22 |
ES5 .Intro(4) - URI vs URL (0) | 2019.11.22 |
ES5 .Intro(3) - Browser 동작 원리 (0) | 2019.11.22 |