자바스크립트는 객체 기반의 프로그래밍 언어이며, 자바스크립트를 구성하는 거의 "모든 것"이 객체이다. 원시 값을 제외한 나머지 값(함수, 배열, 정규 표현식 등)은 모두 객체이다.
원시 타입은 단 하나의 값만 나타내지만 객체 타입은 다양한 타입의 값을 하나의 단위로 구성한 복합적인 자료구조다.
원시 타입의 값, 즉 원시 값은 변경 불가능한 값이지만 객체 타입의 값, 즉 객체는 변경 가능한 값이다.
객체는 0개 이상의 프로퍼티로 구성된 집합이며, 프로퍼티는 키와 값으로 구성된다.
프로퍼티란?
객체의 상태를 나타내는 값(data)
메서드란?
프로퍼티를 참조하고 조작할 수 있는 동작(behavior)
객체 리터럴이란?
리터럴이란 사람이 이해할 수 있는 문자 또는 약속된 기호를 사용하여 값을 생성하는 표기법. 객체 리터럴은 객체를 생성하기 위한 표기법이다.
var person = {
name : 'Lee',
sayHello: function() {
console.log(`Hello! My name is ${this.name}.`);
}
};
console.log(typeof person); // objcet
console.log(person); // {name: "Lee", sayHelloL f}
프로퍼티 = 프로퍼티 키 + 프로퍼티 값
프로퍼티 키는 포르퍼티 값에 접근할 수 있는 이름으로 식별자 역할을 한다.
식별자 네이밍 규칙을 따라야하는 것은 아니지만 식별자 네이밍 규칙을 따르지 않은 이름에는 반드시 따옴표를 사용해야한다.
var person = {
firstName: 'Sangmin', // 식별자 네이밍 규칙 준수
'last-name': 'Lee', // 식별자 네이밍 규칙 미준수
last-name: 'Lee' // SyntaxError: Unexpected token -
};
var obj = {};
var key = 'hello';
obj[key] = 'world';
console.log(obj); // {hello: "world"}
문자열 또는 문자열로 평가 할 수 있는 표현식을 사용하여 프로퍼티 키를 동적으로 생성할 수 있는데 이럴 때는 프로퍼티 키로 사용할 표현식을 대괄호로 묶어야한다.
프로퍼티 값이 함수일 경우 일반 함수와 구분하기 위해서 메서드라고 부른다.
var circle = {
radius: 5, // 프로퍼티
// 원의 지름
getDiameter: function() { // 메서드
return 2 * this.radius; // this는 객체 자신(circle)을 가리키는 참조변수
}
};
console.log(circle.getDiameter()); // 10
var person = {
name: 'Lee'
};
// 마침표 표기법
console.log(person.name); // Lee
// 대괄호 표기법
console.log(person['name']); // Lee
var person = {
'last-name': 'Lee',
1: 10
};
person.'last-name'; // SyntaxError : Unexpected string
person.last-name; // 브라우저 환경 : NaN
// Node.js 환경 : ReferenceError: name is not defined
person[last-name]; // ReferenceError: last is not defined
person['last=name']; // Lee
person.1; // SyntaxError: Unexpected number
person.'1'; // Syntaxerror: Unexpected string
person[1]; // 10 : person[1] -> person['1']
person['1']; // 10
위 예제에서 person.last-name의 경우 브라우저환경과 Node.js환경에 따라 결과값이 다르다는 것을 알 수 있다.
person.last-name을 실행할 때 자바스크립트 엔진은 person.last부터 먼저 평가한다. person 객체를 보면 키가 last인 프로퍼티가 없기 때문에 undefined로 평가된다. 따라서 person.last-name은 person.undefined-name과 같다.
그 다음 name이라는 식별자를 찾는다(이 때 name은 프로퍼티 키가 아니라 식별자로 해석).
Node.js 환경에서는 name이라는 식별자 선언이 없기 때문에 ReferenceError: name is not defined 에러가 발생한다.
브라우저 환경에서는 name이라는 전역변수(전역객체 window의 프로퍼티)가 암묵적으로 존재한다. name은 창(window)의 이름을 가리키고, 기본값은 빈문자열이다.
즉 브라우저 환경에서는 person.undefined-''가 되므로 NaN이 된다.
이미 존재하는 프로퍼티에 값을 할당하면 프로퍼티 값이 갱신된다.
var person = {
name: 'Lee'
};
person.name = 'Kim';
console.log(person); // {name: "Kim"}
존재하지 않는 프로퍼티에 값을 할당하면 프로퍼티가 동적으로 생성되어 추가되고 프로퍼티 값이 할당된다.
var person = {
name: 'Lee'
};
person.age = 31;
console.log(person); // {name: "Lee", age: 31}
delete 연산자는 프로퍼티를 삭제한다. 만약 존재하지 않는 프로퍼티를 삭제하면 아무런 에러 없이 무시된다.
var person = {
name: 'Lee'
};
person.age = 31;
delete person.age;
delete person.address;
console.log(person); // {name: "Lee"}
객체 리터럴의 프로퍼티는 프로퍼티 키 + 프로퍼티 값으로 구성된다.
프로퍼티 값은 변수에 할당된 값(식별자 표현식)일 수도 있다.
// ES5
var x = 1, y = 2;
var obj = {
x: x, // 프로퍼티 값에 x라는 식별자를 할당
y: y // 프로퍼티 값에 y라는 식별자를 할당
}
console.log(obj); // {x:1, y:2}
// ES6
var x = 1, y = 2;
var obj = {x,y}; // 프로퍼티 키 생략가능
console.log(obj); // {x:1, y:2}
ES6에서는 프로퍼티 값으로 변수를 사용하는 경우, 프로퍼티 키와 값이 같을 때 프로퍼티 키를 생략할 수 있다.
문자열 또는 문자열로 타입 변환할 수 있는 값으로 평가되는 표현식을 사용해 프로퍼티 키를 동적으로 생성 할 수도 있다. 대신 프로퍼티 키로 사용할 표현식을 대괄호로 묶어야한다.
// ES5
var prefix = 'prop';
var i = 0;
var obj = {};
// 계산된 프로퍼티 이름으로 프로퍼티 키 동적 생성
obj[prefix + '-' + ++i] = i;
obj[prefix + '-' + ++i] = i;
obj[prefix + '-' + ++i] = i;
console.log(obj);
// {props-1: 1, props-2: 2, props-3: 3}
// ES6
const prefix = 'prop';
let i = 0;
const obj = {
// 객체 리터럴 내부에서 계산된 프로퍼티 이름으로 프로퍼티 키 동적 생성
[`${prefix}-${++i}`]: i,
[`${prefix}-${++i}`]: i,
[`${prefix}-${++i}`]: i
};
console.log(obj);
// {props-1: 1, props-2: 2, props-3: 3}
ES5에서 메서드를 정의하려면 프로퍼티 값으로 함수를 할당한다.
// ES5
var obj = {
name: 'Lee',
sayHi: function() { // 프로퍼티 값에 함수를 할당
console.log('Hi! ' + this.name);
}
};
obj.sayHi(); // Hi! Lee
ES6에서는 메서드를 정의할 때 function 키워드를 생략한 축약 표현을 할 수 있다.
// ES6
var obj = {
name: 'Lee',
sayHi() { // 메서드 축약
console.log('Hi! ' + this.name);
}
};
obj.sayHi(); // Hi! Lee