원시 타입(숫자, 문자열, boolean, null, undifined, symbol)이 아닌 모든 데이터
를 의미한다.프로퍼티
-(key와 value의 조합)으로 저장하는 자료형이다.const person1 = {
// 프로퍼티 key: value
name: 'Tom',
age: 25,
married: false
};
// 이름은 Tom, 나이는 25, 미혼인 정보를 담고 있는 객체
// 프로퍼티의 value부분에는 문자열, 숫자, boolean 등 다양한 자료형을 담을 수 있다.
// 기본적으로는 key를 따옴표("")로 감싸야 하지만 자바스크립트 코드에서는 생략이 가능하다.
console.log(typeof porson1); // Object
console.log(porson1); // {name: 'Tom', age: 25, married: false}
객체를 생성해보고 해당 객체의 프로퍼티에 접근해보자.
객체의 프로퍼티에 접근하는 방법은 두 가지가 있다.
object.key
object['key']
const food = {
name: '치킨',
price: '20000',
};
console.log(food); // {name: '치킨', price: '20000'}
console.log(food.name) // 치킨
console.log(food['price']) // 20000
// 객체의 프로퍼티를 수정 할 수도 있다.
food.name = '햄버거';
food.price = '5000';
[]
안에 표현식을 작성하여 설정 할 수 있다.let idx = 0;
const obj = {
['key-' + ++idx]: `value-${idx}`,
['key-' + ++idx]: `value-${idx}`,
['key-' + ++idx]: `value-${idx}`
}
console.log(obj); // {key-1: 'value-1', key-2: 'value-2', key-3: 'value-3'}
// 반복문으로 객체 만들기
const obj2 = {};
for (let index = 1; index < 4; index++) {
obj2['key-' + index] = `value-${index}`;
}
console.log(obj); // {key-1: 'value-1', key-2: 'value-2', key-3: 'value-3'}
⚠️ 객체의 key값으로 배열이나 다른 객체를 사용시
객체에 담긴 데이터가 key값이 되지 않는다.
예를 들어 아래 코드를 보자const objKey = { x: 1, y: 2 };
const arrKey = [1, 2, 3];
const obj = {
[objKey]: '객체를 키값으로',
[arrKey]: '배열을 키값으로'
}
console.log(
obj[{ a: 1, b: 2, c: 3 }],
obj['1,2,3']
);
// 출력결과
// 객체를 키값으로 배열을 키값으로
{ x: 1, y: 2 }
와 배열 [1,2,3]
과 다른 내용의 객체{ a: 1, b: 2, c: 3 }
, 문자열 '1,2,3
으로 접근해도 객체의 저장된 데이터가 정상적으로 출력된다. 왜 그럴까? 객체
obj
를 출력해보자
console.log(obj);
/* 출력 결과
{ 1,2,3: "배열을 키값으로", [object Object]: "객체를 키값으로" }
*/
{ x: 1, y: 2 }
, [1,2,3]
과 완전히 달라진 것을 확인 할 수 있다. 그 이유는 무엇일까?💡 객체 key값으로 배열을 넣을 경우 배열에 담긴 데이터로 만든 문자열을 key값으로 사용한다.
1,2,3
으로 변환되었기 때문에 obj['1,2,3']
으로도 접근이 가능했던 것이다.💡 객체 key값으로 객체를 넣을 경우 [object Object]
라는 문자열을 key값으로 사용한다. 어떤 객체를 넣어도 마찬가지로 동일한 [object Object]
문자열을 뱉는다.
위 예제에서는 key 객체와 접근 객체가 [object Object]
문자열로 변환되어서 객체에 저장된 데이터가 다름에도 접근이 가능했던 것이다.
즉, 실제로 해당 객체나 배열의 데이터의 값이 키 값이 되는 것이 아니다.
비슷한 데이터 구조를 갖는 Map
과 다른점이라고 할 수 있다.
객체를 사용할 때 객체나 배열을 key로는 쓰지 말자
delete
delete
연산자를 붙여주면 프로퍼티가 삭제된다.const person1 ={
name: 'Tom'
age: 25
}
delete person1.age;
// 만약 정의되지 않은 프로퍼티를 삭제하려고 하면 오류가 발생하지는 않지만 아무일도 일어나지 않는다.
const obj1 = {
key1: 'value1',
key2: 'value2',
key3: 'value3'
}
function addProperty(obj, key, value){
obj.key = value;
}
function addProperty(obj, key, value){
delete obj.key;
}
obj.key
라는 코드는 obj['key']
와 같은 의미이다. 즉, obj내에 존재하는 key
라는 키에 접근을 시도하는 것이지 매개변수로 전달된 key를 추가하는 것이 아니게된다.obj[key] = value;
가 되겠다.const x = 1, y = 2; // 객체에 대입할 상수
const obj1 = {
x: x,
y: y
}
console.log(obj1); // { x: 1, y: 2 }
const x = 1, y = 2;
const obj = { x, y };
console.log(obj); // { x: 1, y: 2 }
function createObj(key1, key2, key3){
// 매개변수의 이름이 key
// 매개변수에 담긴 데이터가 value
return { key1, key2, key3 }
}
createObj(1, 2, 3)
// {key1: 1, key2: 2, key3: 3}
// 이전 문법
const obj1 = {
func: function(){
console.log('Hello world');
}
}
obj1.func(); // Hello world
// 메서드 정의
const obj2 = {
func(){
console.log('Hello world');
}
}
obj2.func(); // Hello world
const person1 = {
name: 'Tom',
age:25
}
const person2 = {
name: 'Mike',
age:22
}
// ........
// 생성자 함수, 대문자로 시작해야한다.
function Person(name, age) {
this.name = name;
this.age = age;
this.hello = function () {
return `hello my name is ${this.name}, ${this.age} years old`
}
// return this
}
// 인스턴스 생성
const person1 = new Person('Tom', 24);
const person2 = new Person('Bruno', 17);
const person3 = new Person('Jym', 26);
console.log(person1);
console.log(person2);
console.log(person3);
this
는 생성자 함수로 만들어질 인스턴스를 가리킨다.this
, 즉 현재 생성한 인스턴스를 반환한다.new
를 붙이지 않으면 undefined
가 된다.fucntion
으로 선언된 함수는 기본적으로 생성자 함수의 기능을 갖는다는 말이다.new
를 붙이는가 여부에 따라 호출 원리가 다르다.function hello(){
console.log('Hello world');
}
const f = new hello();
// Hello world
// f에는 hello {} 객체가 할당된다. 함수가 생성자 함수로 호출 된 것!!
hello();
// Hello world
const f2 = hello(); // 반환값이 없기 때문에 f2는 undifined
메서드
를 정의 할 수 없다.❓그런데 의문점이 든다.
객체를 생성하는 것이라면 꼭 생성자 함수를 만들어야 할까?
객체를 반환하는 함수를 사용하면 안될까?
두 방식의 차이가 뭘까?
프로토타입
- class가 나오기 이전 자바스크립트의 객체지향 프로그래밍 중 자바스크립트 객체지향의 중심
다음 코드를 보자
function Person(name, age) {
this.name = name;
this.age = age;
this.hello = function () {
return `hello my name is ${this.name}, ${this.age} years old`
}
}
const person1 = new Person('Tom', 25); // 생성
Person
에 기능을 추가해보자. (사람은 인사만 할 수 있는게 아니니까)Person.prototype.walk = function() {
return `walking ${this.name}`
}
생성자함수.prototype.property =
의 형태로 함수나 값을 추가 할 수 있는데, 이런 방식으로 추가한 프로퍼티는 이미 만들어진 인스턴스, 그리고 앞으로 만들어질 인스턴스들도 모두 포함하게 된다.Person
의 프로토타입 프로퍼티는 같은 생성자로 만들어진 인스턴스들이 모두 갖게 된다.age: 24
hello: ƒ ()
name: "Tom"
[[Prototype]]: Object // 크롬 콘솔에 출력하면 Object라는 이름으로 나오지만 Person이라고 생각하면 된다.
walk: ƒ () //추가된 프로토타입
constructor: ƒ Person(name, age) // 프로토타입에 생성자 명시
[[Prototype]]: Object
⚠️ hello
와 walk
는 종류가 다르다.
function Person(name, age){
return { name, age,
hello() { `hello my name is ${this.name}, ${this.age} years old`}
}
}
const person1 = Person('Jym', 17);
// new Person();으로 진행해도 인스턴스로 생성되지 않는다.
console.log(person1);
/*
age: 17
hello: ƒ hello()
name: "Jym"
[[Prototype]]: Object
*/
해당 코드에서 만들어진 객체는 생성자 함수로 만든 객체와 가지고 있는 데이터는 같지만, 반환값으로 만들어진 객체는 오리지날 순수 그냥 객체
이다.
어딘가에서 태어난 것이아니라 태초부터 존재한 유일무이한 존재
따라서 프로토타입이 최상위 객체인 Object
인 것을 확인 할 수 있다.
앞서 생성자로 만들어진 것들은 어떤 하나의 객체(Person)에서 파생되어 생성된 인스턴스라는 점에서 차이가 있다.
만들어지는 인스턴스가 아니라 생성자 함수 그 자체에 어떤 기능을 추가하고 싶을 때에는 어떻게 해야할까?
자바스크립트에서는 함수도 객체라고 했다. 그렇다면 프로퍼티 접근자로 기능을 추가할 수 있지 않을까?
function Person(name, age) {
this.name = name;
this.age = age;
this.hello = function () {
return `hello my name is ${this.name}, ${this.age} years old`
}
}
Person.heart = '두근두근';
const person1 = new ('Tom', 25);
console.log(person1.heart) // 에러 발생, heart 프로퍼티 없음
static
이라는 키워드를 떠올렸을 것이다.