3.2 자바스크립트 참조 타입(객체 타입)
자바스크립트에서 숫자, 문자열, 불린값, null, undefined 같은 기본 타입을 제외한 모든 값은 객체
배열, 함수, 정규표현식 등도 모두 결국 자바스크립트 객체로 표현됨
자바스크립트에서의 객체 : 단순히 ‘이름(key):값(value)’ 형태의 프로퍼티들을 저장하는 컨테이너. 자료구조 해시(Hash)와 유사.
자바스크립트에서의 기본 타입 : 하나의 값만 가짐
참조 타입인 객체 : 여러 개의 프로퍼티들을 포함할 수 있으며, 이러한 객체의 프로퍼티는 기본 타입의 값을 포함하거나, 다른 객체를 가리킬 수도 있음
객체의 프로퍼티는 함수로 포함할 수 있으며, 자바스크립트에서는 이러한 프로퍼티를 메서드라고 부름.property란?
MDN에서 정의하고 있는 Property : 해당 object의 특징. property는 보통 데이터 구조와 연관된 속성을 나타낸다. property에는 두 가지 종류가 있다.
- 인스턴스 property들은 특정 object 인스턴스의 특정한 데이터를 가진다.
- static property들은 모든 object 인스턴스들에게 공유된 데이터를 가진다.
property는 이름(a string)과 값(primitive, method 또는 object reference).
보통 “프로퍼티가 object를 가지고 있다”라고 말하는 것은 “property가 object reference”를 가지고 있다는 것을 줄여서 말함.
property의 값이 변한 후에도 object는 그대로 남아 있기 때문에 이걸 구분하는 것은 중요하다.
3.2.1 객체 생성
자바 : 클래스를 정의하고, 클래스의 인스턴스를 생성하는 과정에서 객체가 만들어진다.
but 자바스크립트 : 클래스라는 개념이 없고, 객체 리터럴이나 생성자 함수 등 별도의 생성 방식이 존재.
자바스크립트에서 객체를 생성하는 세 가지 방법
- 기본 제공
Object()
객체 생성자 함수 이용 이번 장 - 객체 리터럴 이용 이번 장
- 생성자 함수 이용 다음 장
3.2.1.1 Object() 생성자 함수 이용
예제 3-5 Object() 생성자 함수를 통한 객체 생성
// Object()를 이용해서 foo 빈 객체 생성
var foo = new Object();
// foo 객체 프로퍼티 생성
foo.name = 'foo';
foo.age = 30;
foo.gender = 'male';
console.log(typeof foo); // (출력값) object
console.log(foo); // (출력값) { name: 'foo', age:30, gender:'male' }
3.2.1.2 객체 리터럴 방식 이용
리터럴 : 표기법
객체 리터럴 : 객체를 생성하는 표기법
객체 리터럴 방식 : 간단한 표기법만으로도 객체를 생성할 수 있는 자바스크립트의 강력한 문법
객체 리터럴 : 중괄호({}
)를 이용하여 객체 생성
1) {}
안에 아무것도 적지 않은 경우 : 빈 객체 생성
2) 중괄호 안에 “프로퍼티 이름”:”프로퍼티값” 형태로 표기하면 해당 프로퍼티가 추가된 객체 생성.
프로퍼티 이름 : 문자열이나 숫자
프로퍼티값 : 자바스크립트의 값을 나타내는 모든 표현식. 이 값이 함수일 경우 이러한 프로퍼티를 메서드라고 부른다.
예제 3-6 객체 리터럴 방식으로 객체 생성
// 객체 리터럴 방식으로 foo 객체 생성
var foo = {
name : 'foo',
age : 30,
gender: 'male'
};
console.log(typeof foo); // (출력값) object
console.log(foo); // (출력값) { name: 'foo', age:30, gender:'male' }
3.2.1.3 생성자 함수 이용
함수를 통해서도 객체를 생성할 수 있다.
이렇게 객체를 생성하는 함수를 생성자 함수라고 부름.
4장에서 살펴봄.
3.2.2 객체 프로퍼티 읽기/쓰기/갱신
객체가 할 수 있는 일
- 새로운 값을 가진 프로퍼티 생성
- 생성된 프로퍼티에 접근해서 해당 값을 읽기
- 원하는 값으로 프로퍼티의 값을 갱신
객체의 프로퍼티에 접근하는 두 가지 방법
- 대괄호(
[]
) 표기법 - 마침표(
.
) 표기법
예제 3-7 객체의 프로퍼티 접근하기
// 객체 리터럴 방식을 통한 foo 객체 생성
var foo = {
name : 'foo',
major : 'computer science'
};
// 객체 프로퍼티 읽기
console.log(foo.name); // (출력값) foo
console.log(foo['name']); // (출력값) foo
console.log(foo.nickname); // (출력값) undefined
// 객체 프로퍼티 갱신
foo.major = 'electronics engineering';
console.log(foo.major); // (출력값) electronics engineering
console.log(foo['major']); // (출력값) electronics engineering
// 객체 프로퍼티 동적 생성
foo.age = 30;
console.log(foo.age); // (출력값) 30
// 대괄호 표기법만을 사용해야 할 경우
foo['full-name'] = 'foo bar';
console.log(foo['full-name']); // (출력값) foo bar
console.log(foo.full-name); // (출력값) NaN
console.log(foo.full); // (출력값) undefined
console.log(name); // (출력값) undefined
1) 프로퍼티 읽기
주의할 점 : 대괄호 표기법에서는 접근하려는 프로퍼티 이름을 문자열 형태로 만들어야 한다. 만약 앞 예제에서 foo[‘name’]
대신에 foo[name]
이라고 접근하면 'foo'
가 아닌 undefined
값이 출력된다.
이유 자바스크립트에서는 대괄호 표기법에서 접근하려는 프로퍼티 이름을 문자열 형태로 만들지 않으면 모든 자바스크립트 객체에서 호출 가능한 toString()
이라는 메서드를 자동으로 호출해서 이를 문자열로 바꾸려는 시도를 한다.
만약 객체에 없는 프로퍼티에 접근하는 경우는 undefined
값이 출력된다.
2) 프로퍼티 갱신
프로퍼티에 접근하여 객체의 기존 프로퍼티값 갱신
3) 프로퍼티 동적 생성
자바스크립트에서는 객체가 생성된 후에도 동적으로 프로퍼티를 생성해서, 해당 객체에 추가할 수 있다. 예제에서는 foo
객체에 age
라는 프로퍼티가 동적으로 생성된 다음, 30이라는 값이 할당된다.
4) 대괄호 표기법만을 사용해야 하는 경우
일반적으로 자바스크립트 또한 마침표 표기법을 이용해서 객체의 프로퍼티에 접근하는 방법 주로 사용. but 접근하려는 프로퍼티가 표현식이거나 예약어일 경우에는 대괄호 표기법만을 이용하여 접근.
full-name : -
연산자가 있는 표현식
foo.full-name
: NaN
출력
NaN (Not a Number) 값
: 수치 연산을 해서 정상적인 값을 얻지 못할 때 출력됨.
가령, 1-‘hello’
라는 연산의 결과는 NaN. 1이라는 숫자와 문자열 ‘hello’를 빼는 연산 수행했기 때문.
위의 foo.full-name
을 자바스크립트에서는 foo.full
과 foo.name
변수의 값을 -
연산자로 계산하는 표현식으로 취급했기 때문에 NaN 출력.
즉 undefined - undefined
의 연산 결과가 NaN
으로 정의되므로 결국 foo.full-name
의 결과로 NaN
출력된 것.
3.2.3 for in 문과 객체 프로퍼티 출력
for in
문을 사용하면, 객체에 포함된 모든 프로퍼티에 대해 루프를 수행할 수 있다.
예제 3-8 for in 문을 통한 객체 프로퍼티 출력
// 객체 리터럴을 통한 foo 객체 생성
var foo = {
name: 'foo',
age: 30,
major: 'computer science'
};
// for in 문을 이용한 객체 프로퍼티 출력
var prop;
for (prop in foo) {
console.log(prop, foo[prop]);
}
3.2.4 객체 프로퍼티 삭제
delete
연산자를 이용해 즉시 삭제할 수 있다.
delete
// 객체 리터럴을 통한 foo 객체 생성
var foo = {
name: 'foo',
nickname: 'babo'
};
console.log(foo.nickname); // (출력값) babo
delete foo.nickname; // (출력값) nickname 프로퍼티 삭제
console.log(foo.nickname); // (출력값) undefined
delete foo; // (출력값) foo 객체 삭제 시도
console.log(foo.name); // (출력값) foo
3.3 참조 타입의 특성
자바스크립트에서는 기본 타입인 숫자, 문자열, 불린값, null, undefined 5가지를 제외한 모든 값은 객체. 배열이나 함수 또한 객체로 취급된다.
이러한 객체는 자바스크립트에서 참조 타입이라고 부른다.
왜? 객체의 모든 연산이 실제 값이 아닌 참조값으로 처리되기 때문.
예제 3-9 동일한 객체를 참조하는 두 변수 objA와 objB
var objA = {
val : 40
};
var objB = objA;
console.log(objA.val);
console.log(objB.val);
objB.val = 50;
console.log(objA.val);
console.log(objB.val);
objA 객체를 객체 리터럴 방식으로 생성.
여기서 objA 변수는 객체 자체를 저장하고 있는 것 (x)
생성된 객체를 가리키는 참조값을 저장하고 있음 (o)
objB에 objA 값을 할당 objB에도 같은 객체의 참조값이 저장
즉, objA와 objB 변수가 동일한 객체를 가리키는 참조값을 가지게 됨.
3.3.1 객체 비교
동등 연산자(==
)를 사용하여 두 객체를 비교할 때도 객체의 프로퍼티값이 아닌 참조값을 비교
예제 3-10 기본 타입과 참조 타입의 비교 연산
var a = 100;
var b = 100;
var objA = { value: 100 };
var objB = { value: 100 };
var objC = objB;
console.log(a == b); // (출력값) true
console.log(objA == objB); // (출력값) false
console.log(objB == objC); // (출력값) true
a와 b는 기본 타입의 변수 기본 타입의 경우 동등 연산자(==
)를 이용해서 비교할 때 값을 비교
3.3.2 참조에 의한 함수 호출 방식
기본 타입과 참조 타입의 경우는 함수 호출 방식도 다르다.
기본 타입 : 값에 의한 호출(call by value) 함수를 호출할 때 인자로 기본 타입의 값을 넘길 경우, 호출된 함수의 매개변수로 복사된 값 전달. 함수 내부에서 매개변수를 이용해 값을 변경해도 실제로 호출된 변수의 값이 변경되지는 않음.
객체와 같은 참조 타입 : 참조에 의한 호출(call by reference) 함수를 호출할 때 인자로 참조 타입인 객체를 전달할 경우, 객체의 프로퍼티값이 함수의 매개변수로 복사되지 않고, 인자로 넘긴 객체의 참조값이 그대로 함수 내부로 전달됨. 함수 내부에서 참조값을 이용하여 인자로 넘긴 실제 객체의 값을 변경 가능.
예제 3-11 Call by Value와 Call by Reference 차이
var a = 100;
var objA = { value: 100};
function changeArg(num, obj) {
num = 200;
obj.value = 200;
console.log(num);
console.log(obj);
}
changeArg(a, objA);
console.log(a);
console.log(objA);
3.4 프로토타입
자바스크립트의 모든 객체는 자신의 부모 역할을 하는 객체와 연결되어 있다.
객체지향의 상속 개념과 같이 부모 객체의 프로퍼티를 마치 자신의 것처럼 쓸 수 있는 것 같은 특징이 있음.
이 부모 객체 프로토타입 객체 (프로토타입)
예제 3-12 객체 생성 및 출력
var foo = {
name: 'foo',
age: 30
};
console.log(foo.toString());
console.dir(foo);
foo
객체의 프로토타입에 toString()
메서드가 이미 정의되어 있고, foo
객체가 상속처럼 toString()
메서드를 호출 에러X
name, age 이외에도 foo
객체에 __proto__
프로퍼티 존재
프로토타입 객체를 가리킴
ECMAScript 명세서에는 자바스크립트의 모든 객체는 자신의 프로토타입을 가리키는 [[Prototype]]
라는 숨겨진 프로퍼티를 가진다고 설명. (크롬 브라우저에서는 __proto__
)
모든 객체의 프로토타입은 자바스크립트의 룰에 따라 객체를 생성할 때 결정됨. (4.5. 프로토타입 체이닝에서 자세히 살펴봄) 예제 3-12와 같이 객체 리터럴 방식으로 생성된 객체의 경우 Object.prototype
객체가 프로토타입 객체가 된다.
#책/인사이드자바스크립트