오늘 한 일
- 자바스크립트 완벽가이드 ~164p
프로퍼티 검색과 설정
- 프로퍼티 값에 접근할 때
let author = book.author;
let title = book["main title"];
- 프로퍼티 생성 또는 설정 시
book.edition = 7;
book["main title"] = "ECMA Script";
- 대괄호 연산자 사용 시 그 안의 표현식은 반드시 문자열 혹은 문자열이나 심벌로 변환될 수 있는 값으로 평가되어야 한다.
연관 배열인 객체
object["property"]
- 이렇게 문자열을 인덱스로 사용하는 배열을
연관 배열(associative array)
라고 한다.- 또는 해시(hash), 맵(map), 딕셔너리(dictionary)라고 부르기도 한다.
- 연관 배열은 다음과 같은 상황에서 유용하게 사용할 수 있다.
💌 예시
- 예로 자신이 소유한 주식(stock) 이름과 보유량(share)을 프로그램에 입력한다.
- 이 정보를 portfolio라는 객체에 담는다.
- 객체의 프로퍼티 하나는 주식 하나에 대응한다.
주식을 추가하는 함수
function addstock(portfolio, stockname, shares) {
portfolio[stockname] = shares;
}
- 사용자는 런타임에 “주식 이름”을 입력한다.
- 프로퍼티 이름을 미리 알 수 없기 때문에 . 연산자를 사용하여 프로퍼티에 접근할 수 없다.
- 하지만 대괄호 연산자는 동적이고 런타임에 바꿀 수 있는 문자열을 사용하므로 사용할 수 있다.
function computeValue(portfolio) {
let total = 0.0;
for(let stock in portfolio) {
let share = portfolio[stock];
let price = getQuote(stock);
total += shares * price;
}
return total;
}
✅ ES6 문법 이후에는 일반 객체를 쓰기 보다 Map 클래스를 사용하는 것이 좋다.
상속
객체 o의 x프로퍼티를 가져온다고 할 때, o에 x라는 프로퍼티가 없다면 o의 프로토타입 객체에서 x프로퍼티를 가져온다. 그것도 없다면 프로토타입의 프로토타입에서 검색하고 프로토타입이 null인 객체에 도달할 때까지 검색
을 계속한다.
객체 o의 x프로퍼티에 값을 할당한다고 할 때, o에 x프로퍼티가 이미 있다면 할당은 기존 프로퍼티 값을 바꾼다. 상속된 프로퍼티 x가 있다면, 새로 생성된 자체 프로퍼티 x에 가려진다.
프로퍼티 할당은 프로토타입 체인을 검색해 할당이 허용되는지 확인
한다.
o가 읽기 전용인 x 프로퍼티를 할당해도 할당되지 않는다.
// javascript에서 읽기 전용 설정
let o = {x : 1};
Object.defineProperty(o, "x", {
writable : false
});
console.log(o.x); // => 1
o.x = 2;
console.log(o.x); // => 1
할당이 허용되어도 원래 객체에 프로퍼티를 생성하거나 설정할 뿐 프로토타입 체인에 존재하는 객체는 수정되지 않는다.
프로퍼티 할당은 실패 혹은 원래 객체에 생성이나 설정이 가능하지만 한 가지 예외가 있다.
o가 x 프로퍼티를 상속하고 그 프로퍼티가 세터 메서드
가 있는 접근자 프로퍼티라면 o에 x 프로퍼티를 새로 만드는 대신 세터 메서드를 호출한다.
→ 하지만 세터 메서드는 객체 o를 호출하기 때문에 세터 메서드가 프로퍼티를 변경하더라도 o에 변화만 있을 뿐 프로토타입 체인은 변하지 않는다.
프로퍼티 접근 에러
⭕ 에러 아님
- 존재하지 않는 프로퍼티를 검색하는 것은 에러가 아니다.
- 접근 표현식은 undefined로 표현된다.
❌ 에러
- 존재하지 않는 객체의 프로퍼티를 검색하는 것은 에러
- 프로퍼티 접근 표현식은 점 연산자의 왼쪽이 null 혹은 undefined일 경우 실패
- ❗ 조건부 프로퍼티 접근 연산자 ?. 를 사용한다.
- 스트릭트 모드에서는 프로퍼티를 설정하려다 실패하면 TypeError가 일어난다.
- 객체 o에 자체 프로퍼티가 있고 p가 읽기 전용일 때 실패
- 객체 o에 상속된 프로퍼티 p가 있고 읽기 전용일 때 : 상속된 읽기 전용 프로퍼티를 같은 이름의 자체 프로퍼티로 가릴 수 없다.
- 객체 o에 자체 프로퍼티 p가 없으며 세터 메서드로 프로퍼티 p를 상속하지 않고, o의 확장 가능(extensible) 속성이 false일 때 : p는 o에 존재하지 않고 호출할 세터 메서드도 없으므로 p를 o에 추가해야 하지만 확장 불가이므로 실패
프로퍼티 삭제
delete 연산자
delete 연산자를 사용하여 객체에서 프로퍼티를 삭제할 수 있다. 피연산자는 프로퍼티 접근 표현식이여야 한다.
delete book.author; // book의 author 프로퍼티가 사라졌습니다.
delete book["main title"]; // main title도요.
delete 연산자는 자체 프로퍼티만 삭제할 뿐 상속된 프로퍼티는 삭제하지 않는다.
- 반드시 해당 프로퍼티를 정의한 프로토타입 객체에서 삭제해야 한다.
delete 표현식은 삭제 성공했을 때 또는 존재하지 않는 프로퍼티 삭제를 시도하는 등 효과가 없었을 때, 프로퍼티 접근 표현식이 아닌 표현식을 사용했을 때도 true로 평가
변경가능 속성이 false인 프로퍼티는 제거하지 않는다.
- 스트릭트 모드에서 삭제하려 하면 Type Error 발생, 일반 모드는 false 반환
프로퍼티 테스트
주어진 이름을 가진 프로퍼티가 존재하는지 확인해야 할 때
- in 연산자
- hasOwnProperty()
- propertyIsEnumerable()
- 프로퍼티 검색
in 연산자
- 자체 프로퍼티, 상속된 프로퍼티 테스트
let o = { x : 1 };
"x" in o // => ture
"y" in o // => false
hasOwnProperty()
- 자체 프로퍼티가 있는지 테스트
o.hasOwnProperty("x") => true
o.hasOwnProperty("toString") => false : 자체 프로퍼티가 아님
propertyIsEnumerable()
- hasOwnProperty()를 더 제한한 버전
- 지정된 프로퍼티가 자체 프로퍼티이며 열거 가능 속성이 true일 때만 true를 반환
o.propertyIsEnumerable("x") // => true
o.propertyIsEnumerable("toString") // => false: 자체 프로퍼티 아님
o.propertyIsEnumerable("toString") // => false: 열거 불가
프로퍼티 검색
o.x !== undefined // => true