객체
객체
순서가 없는 이름있는 값의 집합이며, 식별자에 허용되지 않는 문자가 들어간 속성이름을 정의 할때는 반드시 문자열 표기 사용
객체 리터럴(Object Literal)
객체는 여러 값을 담을 수 있는 주머니와 같은 자료구조
객체 안에는 {이름 : 값}, {key : value} 로 저장되는데, 이를 객체의 속성 이라고 합니다.
const person = {
name : '홍길동', // 속성 이름 - 'name' , 속성 값 - '홍길동'
age : 19, // 속성이름 - 'age' , 속성값 - 19
'languages': ['korean', 'english'] // 속성 이름 - 'languages', 속성 값 - 배열
};
// 이름과 값이 같을 때
const name = '홍길동'
const person= {
name, // `name: name`과 같은 동작을 합니다.
age: 19,
'languages': ['korean', 'english']
}
// 대괄호를 사용해서 다른 변수에 저장된 문자열을 속성의 이름을 쓰는 법
const name = 'prop';
const obj = {
[name]:1
};
obj.prop; // 1
속성 접근자(property accessor)점 표기법, 대괄호 표기법
속성 접근자(점 표기법, 대괄호 표기법)를 이용해 이미 생성된 객체의 속성을 지정해줄 수 있습니다.
const person = {}; // 빈 객체
// 점 표기법 (Dot notation)
person.name = '홍길동';
person.age = 19;
person.languages = ['korean', 'english'];
// 대괄호 표기법 (Bracket notation)
person['한국 나이'] = 20;
동적 바인딩
속성 접근자, delete 연산자, in 연산자 등을 이용해서 객체에 대한정보를 읽고 쓸 수 있습니다.
const person = {
name: '홍길동',
age: 19,
languages: ['korean', 'english']
};
// 속성 읽기
person.name; // '홍길동'
person.age; // 19
person.languages[0] // 'korean'
// 속성 쓰기
person.name = '철수';
person.age =20;
// 새 속성 추가하기
person.address = '서울특별시 강남구';
// 속성 삭제하기
delete person.address;
// 속성이 객체에 존재하는지 확인하기
'name' in person; // true
'phoneNumber' in person; // false
메소드(Method)
객체의 속성값으로 함수를 지정할 수도 있으며, 어떤 객체의 속성으로 접근해서 사용하는 함수를 메소드(method)라고 부릅니다.
메소드를 사용하면 데이터와 관련된 동작을 객체라는 하난의 단위로 묶어서 다룰 수 있어 함수 대신 메소드를 사용
const person = {
greet: funcition() {
return 'hello';
}
};
person.greet(); // 'hello';
const person = {
greet() {
return 'hello';
}
};
person.greet(); // 'hello';
this
this 키워드를 사용하면, 메소드 호출 시에 메소드를 갖고 있는 객체에 접근할 수 있습니다.
this는 같은 함수임에도 불구하고 어떤 객체의 메소드로 사용되느냐에 따라 메소드 내부의 this가 가리키는 객체가 달라질 수 있습니다.
const person = {
name: '홍길동',
age: 19,
introduce() {
// `this`를 사용해서 객체의 속성에 접근합니다.
return `안녕하세요, 제 이름은 ${this.name}입니다. 제 나이는 ${this.age}살 입니다.`
},
getOlder() {
// `this`를 사용해서 객체의 속성을 갱신합니다.
this.age++;
}
};
person.introduce(); // '안녕하세요, 제 이름은 홍길동입니다. 제 나이는 19살 입니다.'
person.getOlder(); // undefined
person.introduce(); // '안녕하세요, 제 이름은 홍길동입니다. 제 나이는 20살 입니다.'
// function을 통해 정의된 함수 내부의 this키워드가 실제로 무엇을 가리킬 것인가는,
// 메소드가 어떻게 정의되는가에 의해 결정이 되는것이 아니라 어떻게 사용되는가에 의해 결정이 됩니다.
function introduce() {
return `안녕하세요, 제 이름은 ${this.name}입니다.`;
}
const person1 = {
name: '홍길동',
introduce
};
const person2 = {
name: '철수'
introduce
};
person1.introduce(); // 안녕하세요, 제 이름은 홍길동입니다.
person2.introduce(); // 안녕하세요, 제 이름은 철수입니다.
프로토타입(Prototype)
객체 간에 공유되어야 하는 속성과 메소드를 프로토타입(prototype)이라는 기능을 이용해서 효율적으로 저장 할 수 있으며 재사용 가능
어떤 객체의 속성을 변경하거나 속성을 삭제하는 작업은 그 객체의 프로토타입에 아무런 영향을 미치지 않음.
프로토타입 상속(prototype inheritance)
프로토타입 기능을 이용해 한 객제에서 다른 객체의 기능을 가져와 사용하는 것
Object.create 함수
const person = {
introduce: function() {
return `안녕하세요, 제 이름은 ${this.name}입니다.`;
}
};
const person1 = Object.create(person); // 새 객체를 생성하고 프로토타입을 지정합니다.
person1.name= '홍길동';
const person2= Object.create(person);
person2.name= '철수';
person1.introduce(); // 안녕하세요, 제 이름은 홍길동입니다.
person2.introduce(); // 안녕하세요, 제 이름은 철수입니다.
person1.introduce === person2.introduce; // true
프로토타입 읽고 쓰기
어떤 객체의 프로토타입을 읽어오기 위해 사용
이미 생성된 객체의 프로토타입을 변경 할 수 있으나, 객체가 생성된 이후에 변경하는 작업은 느리므로 Object.setPrototypeOf 피하기
const parent = {
familyName: '홍'
};
const child = Object.create(parent);
Object.getPrototypeOf(child) === parent; // true
const newParent = {
familyName: '김'
};
Object.setPrototypeOf(child, newParent);
getPrototypeOf(child) === parent; // false
// 객체 리터럴을 통해 생성된 객체의 프로토타입에는 자동으로 Object.prototype이 지정
const obj = {};
Object.getPrototypeOf(obj) === Object.prototype; // true
프로토타입 체인(Prototype Chain)
객체의 속성에 접근하면 프로토타입 객체의 속성까지 확인하고 해당 이름을 갖는 속성이 있다면 그 속성이 값을 반환, 없다면 undefined을 반환
const parent = {
a: 1
};
const child = {
b: 2
};
Object.setPrototypeOf(child, parent);
console.log(child); // { 'b': 2 }
// 출력결과
console.log(child.a); // 1
속성 가리기(Property Shadowing)
프로토타입 체인의 상위에 있는 속성이 하위 속성에 의해 가려지는 현상을 속성 가리기(Property Shadowing)라고 합니다.
// parent에 같은 이름의 속성이 있음에도 불구하고,
// child.prop에 접근하면 프로토타입 체인에서 가장 먼저 만나는 값이 불러와짐
const parent= {
prop: 1
};
const child = {
prop: 2
};
Object.setprototypeOf(child, parent); // `child`의 프로토타입을 `parent`로 재설정합니다.
child.prop; // 2
생성자(Constructor)
Object는 함수이며 객체를 만들 때 new 키워드와 함께 사용하는 함수를 가지고 생성자(constructor)라고 부릅니다.
const obj = new Object();
typeof Object; // 'function'
생성자 정의하기
생성자 이름은 대문자로 시작함
// 생성자 정의
// function구문을 통해 person이라는 생성자를 정의하고,
// 생성자 안에는 this 키워드를 사용해서 새로 만들어질 객체의 속성을 지정
function person(name) {
this.name = name;
}
// 생성자를 통한 객체 생성
// new 키워드를 사용해서 객체를 생성하는 순간에 생성자 안에 있는 코드가 실행되어 객체의 속성이 지정
const person1 = new person('홍길동');
인스턴스(Instance)
생성자를 통해 생성된 객체를 그 생성자의 인스턴스(instance) 라고 함
instanceof 연산자 사용하면 알 수 있음
person1 instanceof person; // true (person1이 person의 인서턴스)
생성자와 프로토타입
생성자를 통해 만들어낸 객체의 프로토타입에는 생성자의 prototype 속성에 저장되어 있는 객체가 자동으로 지정
Object.getprototypeOf(person1) === person.prototype; // ture
// function구문을 통해 함수를 정의할때 함수의 prototype 속성에 객체가 자동으로 생성되어 저장
function person() {
}
typeof person.prototype; // 'object'
constructor
생성자의 prototype 속성에 자동 생성되는 객체에는 constructor라는 속성 생김.
이 속성에는 생성자 자신이 저장
function person() {
...
}
person.prototype.constructor === person; // true
정적 메소드(Static Method)
생성자의 속성에 직접 지정된 메소드
특정 인스턴스에 대한 작업이 아니라, 해당 생성자와 관련된 일반적인 작업을 정의하고 싶을 때 사용됨
// 생성자의 속성에 함수를 직접 할당
person.compareAge = function(person1, person2) {
if(person1.age < person2.age) {
return '첫번째 사람이 나이가 더 많습니다.'
} else if (person1.age === person2.age) {
return '두 사람의 나이가 같습니다.';
} else {
return '두번째 사람이 나이가 더 많습니다.'
}
}