221208 TIL

오늘 한 일

  • 자바스크립트 완벽가이드 ~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 반환

프로퍼티 테스트

주어진 이름을 가진 프로퍼티가 존재하는지 확인해야 할 때

  1. in 연산자
  2. hasOwnProperty()
  3. propertyIsEnumerable()
  4. 프로퍼티 검색

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