[JavaScript] 객체
객체
객체는 관련된 데이터와 함수(일반적으로 여러 데이터와 함수로 이루어짐, 객체 안에 있을 떄는 보통 프로퍼티와 메소드라고 부름)의 집합이다.
객체는 중괄호를 이용해 만들 수 있다. 중괄호 안에는 ‘키(key): 값(value)’쌍으로 구성된 프로퍼티를 여러 개 넣을 수 있는데, 키(key)에는 문자형, 값(value)에는 모든 자료형이 허용된다.
빈 객체 만들기
let user = new Object(); // '객체 생성자' 문법
let user = {}; // '객체 리터럴' 문법
Object 생성자로 생성하는 방식
let user = new Object(); // 비어있는 객체 생성
user.name = "John"
user.age = 30
user.gender = "male"
리터럴로 생성하는 방식
아래와 같이 인라인으로 코드를 작성하고 동시에 객체 생성이 가능하다.
리터럴로 생성하면 코드를 간결하게 작성할 수 있어, 직관적이며 가독성이 높아진다.
let user = {
name: "John",
age: 30
gender: "male",
}
프로퍼티를 추가, 삭제할 수 있다.
점 표기법(dot nation)을 이용하여 프로퍼티 값을 읽을 수 있다.
alert( user.name ); // John
alert( user.age ); //30
프로퍼티 값엔 모든 자료형이 올 수 있다.
user.isAdmin = true; // 불린형 프로퍼티
delete 연산자를 사용하면 프로퍼티 삭제가 가능하다.
delete user.age;
계산된 프로퍼티
객체 리터럴 안의 프로퍼티 키가 대괄호로 둘러싸여 있는 경우 이를 계산된 프로퍼티라고 한다.
let fruit = prompt("어떤 과일을 구매하시겠습니까?", "apple");
let bag = {
[fruit]: 5, //변수 fruit에서 프로퍼티 이름을 동적으로 받아온다.
};
alert( bag.apple ); //fruit에 "apple"이 할당되었다면, 5가 출력된다.
위 예시에서 [fruit]는 프로퍼티 이름을 변수 fruit에서 가져오겠다는 것을 의미한다.
대괄호 안에는 복잡한 표현식이 올 수도 있다.
let fruit = 'apple';
let bag = {
[fruit + 'Computers']: 5 //bag.appleComputers = 5
};
대괄호 표기법은 프로퍼티 이름과 값의 제약을 없애주기 때문에 점 표기법보다 훨씬 강력하다.
단축 프로퍼티
function makeUser(name, age){
return{
name: name,
age: age,
};
}
let user = makeUser("John", 30);
alert(user.name); // John
위 예시의 프로퍼티들은 이름과 값이 변수의 이름과 동일하다.
이렇게 변수를 사용해 프로퍼티를 만들때 프로퍼티 값 단축 구문을 사용하면 코드를 짧게 줄일 수 있다.
name: name 대신 name만 적어도 프로퍼티를 설정할 수 있다.
function makeUser(name, age){
return{
name,
age,
};
}
한 객체에서 일반 프로퍼티와 단출 프로퍼티를 함께 사용하는 것도 가능하다.
‘in’연산자로 프로퍼티 존재 여부 확인하기
자바스크립트 객체는 존재하지 않는 프로퍼티에 접근하려 해도 에러가 발생하지 않고 undefined를 반환한다.
undefined와 비교하여 프로퍼티 존재 여부를 쉽게 확인할 수 있다.
undefined와 비교하는 것 이외에도 연산자 in을 사용하면 프로퍼티 존재 여부를 확인할 수 있다.
"key" in object
let user = { name: "John", age: 30};
alert( "age" in user ); // true
alert( "blabla" in user ); //false
‘for…in’ 반복문
for…in 반복문을 사용하면 객체의 모든 키를 순회할 수 있다.
for(key in object){
// 각 프로퍼티 키(key)를 이용하여 본문(body)을 실행한다.
}
let user = {
name: "John",
age: 30,
isAdmin: true
};
for(let key in user){
// 키
alert( key ); // name, age, isAdmin
// 키에 해당하는 값
alert( user[key] ); // John, 30, true
}
객체 정렬 방식
정수 프로퍼티는 자동으로 정렬되고, 그외의 프로퍼티는 객체에 추가한 순서 그대로 정렬된다.
키가 정수가 아닌 경우엔 작성된 순서대로 프로퍼티가 나열된다.
정수로 취급되지 않도록 숫자 앞에 “+”를 붙이는 속임수를 써서 작성된 순서대로 나열되도록 할 수 있다.
참조에 의한 객체 복사
객체는 ‘참조에 의해(by reference)’저장되고 복사된다.
변수에 객체가 그대로 저장되는 것이 아니라, 객체가 저장되어있는 ‘메모리 주소’인 객체에 대한 ‘참조 값’이 저장된다.
let user = {name : "John"};
let admin = user; // 참조값을 복사함
변수는 두 개이지만 각 변수엔 동일 객체에 대한 참조값이 저장된다.
따라서 객체에 접근하거나 객체를 조작할 땐 여러 변수를 사용할 수 있다.
let user = { name: 'John' };
let admin = user;
admin.name = 'Pete'; // 'admin' 참조 값에 의해 변경됨
alert(user.name); // 'Pete'가 출력됨. 'user' 참조 값을 이용해 변경사항을 확인함
객체 복사
let user = {
name: "John",
age: 30
};
let clone = Object.assign({}, user);
clone 변수에 user 객체의 복제본이 저장된다. clone과 user는 서로 다른 객체이며, user객체를 수정해도 clone객체는 변경되지 않는다. //얕은 복사(Shallow Copy)
메서드와 this
자바스크립트의 객체는 프로퍼티 키와 값으로 구성되어지는데, 이때 값에는 자바스크립트에서 평가 되어지는 모든 값을 담을 수 있다.
프로퍼티의 값이 함수일때, 이 프로퍼티를 메서드(method)라고 한다.
메서드는 상태 데이터를 참조하고, 조작 할 수 있는 동작의 역할을 가진다.
let user = {
name: "John",
age: 30
};
user.sayHi = function() {
alert("안녕하세요!");
};
user.sayHi(); // 안녕하세요!
위 예시 코드를 보면 객체 프로퍼티 user.sayHi에 함수가 할당되어 있다. 객체에 할당된 함수를 호출하면 user가 인사를 해준다. 메서드는 이미 정의된 함수를 이용해서 만들 수도 있다.
let user = {
// ...
};
// 함수 선언
function sayHi() {
alert("안녕하세요!");
};
// 선언된 함수를 메서드로 등록
user.sayHi = sayHi;
user.sayHi(); // 안녕하세요!
메서드 단축 구문
user = {
sayHi() { // "sayHi: function()"과 동일합니다.
alert("Hello");
}
};
위처럼 function을 생략해도 메서드를 정의할 수 있다.
다만, 일반적인 방법과 단축 구문을 사용한 방법이 완전히 동일하지는 않다.
객체 상속과 관련된 미묘한 차이가 존재한다.
this
메서드 내부에서 this 키워드를 사용하면 객체에 접근할 수 있다.
이때 ‘점 앞’의 this는 객체를 나타낸다. 정확히는 메서드를 호출할 때 사용된 객체를 나타낸다.
let user = {
name: "John",
age: 30,
sayHi() {
// 'this'는 '현재 객체'를 나타냅니다.
alert(this.name);
}
};
user.sayHi(); // John
동일한 함수라도 다른 객체에서 호출했다면 this가 참조하는 값은 달라진다.
화살표 함수는 자신만의 this를 가지지 않는다. 화살표 함수 안에서 this를 사용하면, 외부에서 this 값을 가져온다.
new 연산자와 생성자 함수
‘new’연산자와 생성자 함수를 사용하면 유사한 객체 여러 개를 쉽게 만들 수 있다.
new 연산자
‘new’ 연산자는 생성자 함수를 호출하여 새로운 객체를 생성하는 역할을 한다.
new 연산자로 객체를 생성할 때 다음과 같은 단계가 발생합니다.
- 빈 객체가 생성된다.
- 생성자 함수가 호출된다. 이때 ‘this’는 새로 생성된 빈 객체를 가리킨다.
- 생성자 함수 내에서 속성과 메서드를 이용하여 객체를 초기화한다.
- 생성자 함수에서 명시적으로 다른 객체를 반환하지 않으면, this로 참조된 객체가 반환된다.
생성자 함수
생성자 함수는 객체를 만들기 위한 함수다. 일반적으로 생성자 함수의 이름은 대문자로 시작하며, 객체를 초기화하기 위한 파라미터를 받을 수 있다.
생성자 함수는 new 연산자를 사용하여 호출됩니다. 생성자 함수 내에서 this를 사용하여 객체의 속성을 초기화하고, 이렇게 생성된 객체는 해당 생성자 함수의 인스턴스다.
function User(name) {
this.name = name;
this.isAdmin = false;
}
let user = new User("보라");
alert(user.name); // 보라
alert(user.isAdmin); // false
위 코드에서 user은 User 생성자 함수의 인스턴스이며, ‘name’과 ‘isAdmin’속성을 가지고 있다.
new User(“보라”) 이외에도 new User(“호진”), new User(“지민”) 등을 이용하면 사용자 객체를 손쉽게 만들 수 있다.
생성자의 의의는 재사용할 수 있는 객체 생성 코드를 구현하는 것이다.
옵셔널 체이닝 ‘?.’
?.은 ?. ‘앞’의 평가 대상이 undefined나 null이면 평가를 멈추고 undefined를 반환한다.
let user = null;
alert( user?.address ); // undefined
alert( user?.address.street ); // undefined
?.는 존재하지 않아도 괜찮은 대상에만 사용해야 한다.
사용자 주소를 다루는 위 예시에서 논리상 user는 반드시 있어야 하는데 address는 필수값이 아니다. 그러니 user.address?.street를 사용하는 것이 바람직하다.
?.앞의 변수는 꼭 선언되어 있어야 한다.
변수 user가 선언되어있지 않으면 user?.anything 평가시 에러가 발생한다.
옵셔널 체이닝은 선언이 완료된 변수를 대상으로만 동작한다.
단락 평가
?.는 왼쪽 평가대상에 값이 없으면 즉시 평가를 멈춘다. 이런 평가 방법을 단락 평가(short-circuit)라고 한다.
그렇기 때문에 함수 호출을 비롯한 ?. 오른쪽에 있는 부가 동작은 ?.의 평가가 멈췄을 때 더는 일어나지 않는다.
let user = null;
let x = 0;
user?.sayHi(x++); // 아무 일도 일어나지 않는다.
alert(x); // 0, x는 증가하지 않는다.
?.()와 ?.[]
?.은 연산자가 아니다. 함수나 대괄호와 함께 동작하는 특별한 문법 구조체다.
존재 여부가 확실치 않은 함수를 호출할 때 ?.()를 사용하는 방법
let user1 = {
admin() {
alert("관리자 계정입니다.");
}
}
let user2 = {};
user1.admin?.(); // 관리자 계정
user2.admin?.();
두 상황 모두에서 user객체는 존재하기 때문에 admin 프로퍼티는 .만 사용해 접근한다.
그리고 난 후 ?.()를 사용해 admin의 존재 여부를 확인 할 수 있다.
.대신 대괄호 []를 사용해 객체 프로퍼티에 접군하는 경우엔 ?.[]를 사용할 수 있다.
let user1 = {
firstName: "Violet"
};
let user2 = null; // user2는 권한이 없는 사용자라고 가정
let key = "firstName";
alert( user1?.[key] ); // Violet
alert( user2?.[key] ); // undefined
alert( user1?.[key]?.something?.not?.existing); // undefined
delete와 조합해 사용 할 수도 있다.
delete user?.name; // user가 존재하면 user.name을 삭제
?.은 ‘읽기’나 ‘삭제하기’에는 사용할 수 있지만 ‘쓰기’에는 사용할 수 없다.
// user가 존재할 경우 user.name에 값을 쓰려는 의도로 아래와 같이 코드를 작성
user?.name = "Violet"; // SyntaxError: Invalid left-hand side in assignment
// 에러가 발생하는 이유는 undefined = "Violet"이 되기 때문
참고문서
https://ko.javascript.info/object-basics