1. 자바스크립트의 기본 타입
자바스크립트에서 기본 타입은 숫자, 문자열, 불린값을 비롯해 null과 undefined라는 타입이 있다. 이들 타입의 특징은 그 자체가 하나의 값을 나타낸다는 것이다. 기본 타입의 변수들을 생성하고, 해당 변수의 타입을 typeof 연산자(피연산자의 타입을 리턴)를 이용해서 알 수 있다. 자바스크립트는 느슨한 타입 체크 언어이다. 자바스크립트는 변수를 선언할 때 타입을 미리 정하지 않고, var라는 키워드로만 변수를 선언한다. 변수에 어떤 형태의 데이터를 저장하느냐에 따라 해당 변수의 타입 이 결정된다.
1) 숫자(Number)
C나 Java의 경우, 정수와 실수를 구분하여 int, long, float, double 등과 같은 다양한 숫자 타입이 존재한다. 하지만 자바스크립트는 독특하게 하나의 숫자 타입만 존재한다. var 키워드로 선언된 자바스크립트 변수에는 정수나 실수 구분없이 그 값을 바로 저장하므로 typeof 연산자의 결과값이 number타입이다. 자바스크립트의 숫자 타입은 정수만을 위한 타입이 없고 모든 수를 실수를 처리한다.
console.log(1 === 1.0); // true
var result = 4 / 2;
console.log(result); // 2
result = 3 /2;
console.log(result); // 1.5
2) 문자열(String)
문자열(String) 타입은 텍스트 데이터를 나타내는데 사용한다. 문자열은 작은 따옴표(‘’) 또는 큰 따옴표(“”) 안에 텍스트를 넣어 생성한다. 가장 일반적인 표기법은 작은 따옴표를 사용하는 것이다. 자바스크립트의 문자열은 원시 타입이며 변경 불가능(immutable)하다. 이것은 한 번 문자열이 생성되면, 그 문자열을 변경할 수 없다는 것을 의미한다.
//str 문자열 생성
var str = 'test';
console.log(str[0], str[1], str[2], str[3]); // t e s t
// 문자열의 첫글자를 대문자로 변경?
str[0] = 'T';
console.log(str); // test
위와 같이 문자열은 배열처럼 인덱스를 통해 접근할 수 있다. 이와 같은 특성을 갖는 데이터를 유사 배열이라 한다. str[0] = 'T'처럼 이미 생성된 문자열의 일부 문자를 변경해도 반영되지 않는다(이때 에러가 발생하지 않는다). 한번 생성된 문자열은 read only로서 변경할 수 없다. 이것을 변경 불가능(immutable)이라 한다. 그러나 새로운 문자열을 재할당하는 것은 물론 가능하다. 이는 기존 문자열을 변경하는 것이 아니라 새로운 문자열을 새롭게 할당하는 것이기 때문이다.
3) 불리언(boolean)
불리언(boolean) 타입의 값은 논리적 참, 거짓을 나타내는 true와 false 뿐이다. 불리언 타입의 값은 참과 거짓으로 구분되는 조건에 의해 프로그램의 흐름을 제어하는 조건문에서 자주 사용한다.
비어있는 문자열과 null, undefined, 숫자 0은 false로 간주된다.
4) undefined
undefined 타입의 값은 undefined가 유일하다. 선언 이후 값을 할당하지 않은 변수는 undefined 값을 가진다. 즉, 선언은 되었지만 값을 할당하지 않은 변수에 접근하거나 존재하지 않는 객체 프로퍼티에 접근할 경우 undefined가 반환된다. 이는 변수 선언에 의해 확보된 메모리 공간을 처음 할당이 이루어질 때까지 빈 상태(대부분 비어있지 않고 쓰레기 값(Garbage value)이 들어 있다)로 내버려두지 않고 자바스크립트 엔진이 undefined로 초기화하기 때문이다.
var foo;
console.log(foo); // undefined
그렇다면 변수의 값이 없다는 것을 명시하고 싶은 경우 위와 같은 코드를 구성하면 될까? 아니다. 그런 경우는 undefined를 할당하는 것이 아니라 null을 할당해야 한다.
5) null
null은 의도적으로 변수에 값이 없다는 것을 명시할 때 사용한다. 이는 변수가 기억하는 메모리 어드레스의 참조 정보를 제거하는 것을 의미하며 자바스크립트 엔진은 누구도 참조하지 않는 메모리 영역에 대해 가비지 콜렉션을 수행할 것이다.
var foo = 'Lee';
foo = null; // 참조 정보가 제거됨
typeof 연산자로 null 값을 연산해 보면 null이 아닌 object가 나온다. 이는 자바스크립트의 설계상의 오류이다. 따라서 null 타입을 확인할 때 typeof 연산자를 사용하면 안되고 일치 연산자(===)를 사용하여야 한다.
var foo = null;
console.log(typeof foo === null); // false
console.log(foo === null); // true
2. 객체 타입(Object type)
객체는 데이터와 그 데이터에 관련한 동작(절차, 방법, 기능)을 모두 포함할 수 있는 개념적 존재이다. 자바스크립트의 객체는 키(key)과 값(value)으로 구성된 프로퍼티(Property)들의 집합이다. 자바스크립트는 객체(object) 기반의 스크립트 언어로서 자바스크립트를 이루고 있는 거의 “모든 것”이 객체이다. 원시 타입(Primitives)을 제외한 나머지 값들(배열, 함수, 정규표현식 등)은 모두 객체이다.
자바스크립트에서 기본 타입은 하나의 값만을 가지는 데 비해, 참조 타입인 객체는 여러 개의 프로퍼티들을 포함할 수 있으며, 이러한 객체의 프로퍼티는 기본 타입의 값을 포함하거나, 다른 객체를 참조할 수 있다. 이러한 프로퍼티의 성질에 따라 객체의 프로퍼티는 함수로 포함될 수 있으며, 자바스크립트에서는 메서드라고 부른다.
1) 객체 생성 방법
① 객체 리터럴
가장 일반적인 자바스크립트의 객체 생성 방식이다. 클래스 기반 객체 지향 언어와 비교할 때 매우 간편하게 객체를 생성할 수 있다. 중괄호{}를 사용하여 객체를 생성하는데 {} 내에 1개 이상의 프로퍼티를 기술하면 해당 프로퍼티가 추가된 객체를 생성할 수 있다. {} 내에 아무것도 기술하지 않으면 빈 객체가 생성된다.
var emptyObject = {};
console.log(typeof emptyObject); // object
var person = {
name: 'Lee',
gender: 'male',
sayHello: function () {
console.log('Hi! My name is ' + this.name);
}
};
console.log(typeof person); // object
console.log(person); // {name: "Lee", gender: "male", sayHello: ƒ}
person.sayHello(); // Hi! My name is Lee
② Object 생성자 함수
new 연산자와 Object 생성자 함수를 호출하여 빈 객체를 생성할 수 있다. 빈 객체 생성 이후 프로퍼티 또는 메소드를 추가하여 객체를 완성하는 방법이다. 생성자(constructor) 함수란 new 키워드와 함께 객체를 생성하고 초기화하는 함수를 말한다. 생성자 함수를 통해 생성된 객체를 인스턴스(instance)라 한다. 사실 객체 리터럴 방식으로 생성된 객체는 결국 빌트인(Built-in) 함수인 Object 생성자 함수로 객체를 생성하는 것을 단순화시킨 축약 표현(short-hand)이다.
// 빈 객체의 생성
var person = new Object();
// 프로퍼티 추가
person.name = 'Lee';
person.gender = 'male';
person.sayHello = function () {
console.log('Hi! My name is ' + this.name);
};
console.log(typeof person); // object
console.log(person); // {name: "Lee", gender: "male", sayHello: ƒ}
person.sayHello(); // Hi! My name is Lee
③ 생성자 함수
객체 리터럴 방식과 Object 생성자 함수 방식으로 객체를 생성하는 것은 프로퍼티 값만 다른 여러 개의 객체를 생성할 때 불편하다. 동일한 프로퍼티를 갖는 객체임에도 불구하고 매번 같은 프로퍼티를 기술해야 한다.
var person1 = {
name: 'Lee',
gender: 'male',
sayHello: function () {
console.log('Hi! My name is ' + this.name);
}
};
var person2 = {
name: 'Kim',
gender: 'female',
sayHello: function () {
console.log('Hi! My name is ' + this.name);
}
};
하지만 생성자 함수를 사용하면 마치 객체를 생성하기 위한 템플릿(클래스)처럼 사용하여 프로퍼티가 동일한 객체 여러 개를 간편하게 생성할 수 있다.
// 생성자 함수
function Person(name, gender) {
this.name = name;
this.gender = gender;
this.sayHello = function(){
console.log('Hi! My name is ' + this.name);
};
}
// 인스턴스의 생성
var person1 = new Person('Lee', 'male');
var person2 = new Person('Kim', 'female');
console.log('person1: ', typeof person1);
console.log('person2: ', typeof person2);
console.log('person1: ', person1);
console.log('person2: ', person2);
person1.sayHello();
person2.sayHello();
2) 객체 프로퍼티 접근
객체는 새로운 값을 가진 프로퍼티를 생성하고, 생성된 프로퍼티에 접근해서 해당 값을 읽거나 또는 원하 는 값으로 프로퍼티의 값을 갱신할 수 있다.
① 프로퍼티 값 읽기
객체의 프로퍼티 값에 접근하는 방법은 마침표(.) 표기법과 대괄호([]) 표기법이 있다.
// 객체 리터럴 방식을 통한 foo 객체 생성
var foo = {
name : 'hong',
major : 'computer science'
};
// 객체 프로퍼티 읽기
console.log(foo.name); // hong
console.log(foo['name']); // hong
console.log(foo.nickname); // 객체에 없는 프로퍼티에 접근하는 경우는 undefined
프로퍼티 키가 유효한 자바스크립트 이름이고 예약어가 아닌 경우 프로퍼티 값은 마침표 표기법, 대괄호 표기법 모두 사용할 수 있다. 프로퍼티 이름이 유효한 자바스크립트 이름이 아니거나 예약어인 경우 프로퍼티 값은 대괄호 표기법으로 읽어야 한다. 대괄호([]) 표기법을 사용하는 경우, 대괄호 내에 들어가는 프로퍼티 이름은 반드시 문자열이어야 한다.
② 프로퍼티 값 갱신
객체가 소유하고 있는 프로퍼티에 새로운 값을 할당하면 프로퍼티 값은 갱신된다.
// 객체 리터럴 방식을 통한 foo 객체 생성
var foo = {
name : 'hong',
major : 'computer science'
};
// 객체 프로퍼티 갱신
foo.major = 'electronics engineering';
console.log(foo.major); //electronics engineering
console.log(foo['major']); //electronics engineering
③ 프로퍼티 동적 생성
객체가 소유하고 있지 않은 프로퍼티 키에 값을 할당하면 하면 주어진 키와 값으로 프로퍼티를 생성하여 객체에 추가한다.
// 객체 리터럴 방식을 통한 foo 객체 생성
var foo = {
name : 'hong',
major : 'computer science'
};
// 객체 프로퍼티 동적 생성
foo.age = 30;
console.log(foo.age); // 30
④ 프로퍼티 삭제
delete 연산자를 사용하면 객체의 프로퍼티를 삭제할 수 있다. 이때 피연산자는 프로퍼티 키이어야 한다. 여기서 주의할 점은 delete 연산자는 객체의 프로퍼티만 삭제할 뿐, 객체 자체를 삭제하진 못한다.
// 객체 리터럴 방식을 통한 foo 객체 생성
var foo = {
name : 'hong',
nickname : 'javascript'
};
console.log(foo.nickname); // javascript
delete foo.nickname; // nickname 프로퍼티 삭제
console.log(foo.nickname); // undefined
delete foo; // foo 객체는 삭제되지 않는다.
console.log(foo.name); // hong
⑤ for-in 문과 객체 프로퍼티 출력
for-in 문을 사용하면 객체(배열 포함)에 포함된 모든 프로퍼티에 대해 루프를 수행할 수 있다.
// 객체 리터럴을 통한 foo 객체 생성
var foo = {
name: 'foo',
age: 30,
major: 'computer science'
};
// for in문을 이용한 객체 프로퍼티 출력
for (var prop in foo) {
console.log(prop, foo[prop]);
}
3. 참조 타입(Reference type)
1) 참조 타입의 특성
object type을 객체 타입 또는 참조 타입이라 한다. 참조 타입이란 객체의 모든 연산이 실제값이 아닌 참조값으로 처리됨을 의미한다. 원시 타입은 값이 한번 정해지면 변경할 수 없지만(immutable), 객체는 프로퍼티를 변경, 추가, 삭제가 가능하므로 변경 가능(mutable)한 값이라 할 수 있다. 따라서 객체 타입은 동적으로 변화할 수 있으므로 어느 정도의 메모리 공간을 확보해야 하는지 예측할 수 없기 때문에 런타임에 메모리 공간을 확보하고 메모리의 힙 영역(Heap Segment)에 저장된다. 이에 반해 원시 타입은 값(value)으로 전달된다. 즉, 복사되어 전달된다. 이를 pass-by-value라 한다.
// Pass-by-reference
var foo = {
val: 10
}
var bar = foo;
console.log(foo.val, bar.val); // 10 10
console.log(foo === bar); // true
bar.val = 20;
console.log(foo.val, bar.val); // 20 20
console.log(foo === bar); // true
변수 foo는 객체 자체를 저장하고 있는 것이 아니라 생성된 객체의 참조값(address)를 저장하고 있다. 변수 bar에 변수 foo의 값을 할당하였다. 변수 foo의 값은 생성된 객체를 가리키는 참조값이므로 변수 bar에도 같은 참조값이 저장된다. 즉, 변수 foo, bar 모두 동일한 객체를 참조하고 있다. 따라서 참조하고 있는 객체의 val 값이 변경되면 변수 foo, bar 모두 동일한 객체를 참조하고 있으므로 두 변수 모두 변경된 객체의 프로퍼티 값을 참조하게 된다. 객체는 참조(Reference) 방식으로 전달된다. 결코 복사되지 않는다.
2) 객체 비교
동등 연산자(==)를 이용하여 두 객체를 비교할 때도 객체의 프로퍼티 값이 아닌 참조값을 비교한다.
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
참조 타입(객체)를 동등 연산자(==)로 비교하면 프로퍼티값이 같더라도 다른 참조타입(객체)로 여겨 false가 된다.
- 참고 문헌
'언어 > JavaScript' 카테고리의 다른 글
[JavaScript] 브라우저 이벤트 종류 및 사용 (0) | 2023.12.26 |
---|---|
[JavaScript] 자바스크립트(JavaScript)의 객체지향 (0) | 2023.12.25 |