Skip to content

Latest commit

 

History

History
875 lines (560 loc) · 29.3 KB

11. Objects.md

File metadata and controls

875 lines (560 loc) · 29.3 KB

11. Objects

자바스크립트의 거의 모든 것은 객체이다. **객체(object)**는 0개 이상의 프로퍼티로 구성되어있으며, **변경 가능(mutable)**한 값이다. **프로퍼티(property)**는 **키(key)**와 **값(value)**으로 구성되어있는데, 특히 값이 함수인 프로퍼티를 **메서드(method)**라고 한다.

객체를 변수에 할당하면 확보한 메모리 공간에는 객체 자체가 아니라 객체가 저장된 메모리 공간의 주소인 참조 값(reference value)이 저장된다.

11.1 객체 리터럴

  • 객체 리터럴0개 이상의 프로퍼티를 ,로 구분하고 {}로 감싼다. 프로퍼티는 key: value 형식으로 이루어져있다.
{
    key: value,
};

마지막 프로퍼티에 붙은 콤마를 trailing comma라고 한다.

  • 프로퍼티를 명시하지 않으면 빈 객체를 만들 수 있다.
{};
  • 객체 이니셜라이저로 생성한 객체는 Object의 인스턴스로, Object 생성자 함수로 만든 것과 같다.
typeof {} === 'object';	// true

객체 리터럴의 평가

  • 리터럴은 값으로 평가되는 표현식이므로 객체 리터럴 역시 값으로 평가된다. 자바스크립트 엔진은 객체 리터럴이 나타나는 문을 실행할 때마다 객체 리터럴을 평가하여 새로운 객체를 생성한다. 따라서 동일한 객체 리터럴이 생성한 두 개의 객체는 동등하지도 일치하지도 않는다.
{ name: 'lana' } == { name: 'lana '};	// false
{ name: 'lana' } === { name: 'lana '};	// false
  • 객체 리터럴의 중괄호는 코드 블록을 의미하지 않으므로 자체 종결성을 가지지 않아 닫는 중괄호 뒤에 ;를 붙인다.
{ name: 'lana' };

11.2 객체 생성하기

자바스크립트에서 객체를 생성하는 방법은 다음과 같다.

  • 객체 이니셜라이저(Object Initializer) 사용하기
  • 생성자 함수(Constructor Function) 사용하기
  • Object.create() 사용하기
  • 클래스(Class) 사용하기(ES6)

객체 이니셜라이저 사용하기

let p = {
    name: 'lana',
    displayName() { console.log(this.name); } // shorthand method definition (ES6)
};

**객체 이니셜라이저(Object Initializer)**는 객체 리터럴을 사용하여 객체를 생성하는 것을 의미한다. [Object Initializer](https://github.com/leegwae/study-javascript/blob/main/Object Initializer.md)를 참고한다.

생성자 사용하기

함수 선언문, 함수 표현식, 클래스로 정의된 함수는 new 연산자와 함께 사용하면 객체의 인스턴스를 생성하는 생성자 함수로서 동작한다. 특히 객체의 타입을 정의하는 함수를 **생성자(constructor)**라고 한다. 생성자 함수는 자바스크립트가 제공하는 표준 내장 객체를 생성하는 빌트인(built-in) 생성자 함수이거나 사용자가 정의한 타입의 객체를 생성하는 사용자 정의(user-defined) 생성자 함수이다.

const obj = new 생성자();

Constuctor Function을 참고한다.

빌트인 생성자 함수

  • 자바스크립트는 빌트인 생성자 함수로 Object, String, Number, Boolean, Function, Array 등을 제공한다.
  • 객체 리터럴로 생성한 객체는 Object 타입의 인스턴스이다.
const album = new Object();

따라서 new Object()를 호출하면 빈 객체({})를 만들 수 있다.

사용자 정의 생성자 함수

function 선언문으로 생성자 함수를 정의할 수 있다.

this는 생성자 함수 내부에서는 생성자 함수가 생성할 인스턴스를 참조하므로 this.프로퍼티로 프로퍼티를 정의한다. 생성자 함수는 함수로서 인자를 받을 수 있는데 이것을 프로퍼티를 초기화하는데 사용할 수 있다.

function Album(title) {
    this.title = title;
    this.printTitle = function () {
        console.log(`title: ${this.title}`);
    };
}

const album = new Album('ultraviolence');
console.log(album);	// Album {title: 'ultraviolence', printTitle: ƒ}
album.printTitle();	// title: ultraviolence

Object.create 메서드 사용하기

Object.create는 피연산자 객체를 프로토타입으로 가진 객체를 생성한다.

let Animal = {
    type: null,
    displayType: function() {
        console.log(this.type);
    },
}

let cat = Object.create(Animal);
cat.type = 'cats';
cat.displayType();

ES6 클래스 사용하기

ES6 클래스는 생성자 함수처럼 프로토타입 기반으로 인스턴스를 생성한다.

class Animal {
    constructor(name) {
        this.name = name;
    }
    
    sayHello() {
        console.log(this.name);
    }
}

클래스를 참고한다.

객체 리터럴과 생성자 함수의 비교

  • 객체 리터럴을 값으로 평가되는 표현식이므로 평가되어 하나의 객체를 생성한다. 따라서 서로 다른 객체가 동일한 프로퍼티 구조를 가지도록 재사용할 수 없다. 다른 변수에 할당하는 것은 동일한 객체에 대한 참조를 늘리는 것뿐이다.
const lux = {
    firstName: 'Luxanna',
    lastName: 'Crownguard',
    getFullName() {
        return `${this.firstName} ${this.lastName}`;
    }
};

console.log(lux.getFullName());	// Luxanna Crownguard

const caitlyn = {
    firstName: 'Caitlyn',
    lastName: 'Kiramman',
    getFullName() {
        return `${this.firstName} ${this.lastName}`;
    }
};

console.log(caitlyn.getFullName());	// Caitlyn Kiramman
  • 생성자 함수는 new 연산자로 동일한 프로퍼티를 가지는 객체를 여러 개 생성할 수 있다.
function Champion(firstName, lastName) {
    this.firstName = firstName;
    this.lastName = lastName;
    this.getFullName = function () {
        return `${this.firstName} ${this.lastName}`;
    };
}

const lux = new Champion('Luxanna', 'Crownguard');
const caitlyn = new Champion('Caitlyn', 'Kiramman');

console.log(lux.getFullName());
console.log(caitlyn.getFullName());

11.3 프로퍼티

**프로퍼티(property)**는 **키(key; 이름)**와 **값(value)**으로 구성된다.

{ name: 'lux'};

이 객체에 있는 프로퍼티의 키는 name이고 값은 'lux'이다.

프로퍼티의 키

  • **프로퍼티의 키(key)**는 문자열이나 symbol 값이다.
const obj = {
	'name': 'lux'
};
  • 프로퍼티의 키로 문자열이나 symbol 값 이외의 값을 사용하면 문자열로 암묵적 타입 변환된다. 특히, 문자열이 식별자 네이밍 규칙을 따른다면 따옴표(''또는 "")를 생략할 수 있다.
let obj = {
    1: 'hello',		// 1은 숫자 타입이지만 문자열 '1'로 타입 변환된다.
    firstName: 'Luxanna',	// firstName은 식별자 네이밍 규칙을 준수하므로 따옴표를 생략할 수 있다.
    'last-name': 'Crownguard', // last-name은 식별자 네이밍 규칙을 준수하지 않으므로 따옴표를 생략할 수 없다.
};
  • 예약어를 프로퍼티의 키로 사용해도 에러가 발생하지 않으나 예상치 못한 에러가 발생할 수 있으니 사용하지 않는다.
const obj = {
    var: 'hello'
};
console.log(obj.var);	// 'hello'

프로퍼티의 값

  • **프로퍼티의 값(value)**은 자바스크립트에서 사용할 수 있는 모든 값이 들어갈 수 있다.
  • 프로퍼티의 값이 함수라면 특별히 **메서드(method)**라고 한다. 메서드를 참고한다.

프로퍼티의 구분

JavaScript의 프로퍼티는 데이터 프로퍼티와 접근자 프로퍼티로 구분할 수 있다.

  • 데이터 프로퍼티(data property): 키와 JavaScript 값으로 구성된 일반적인 프로퍼티
  • 접근자 프로퍼티(accessor property): 키와 접근자 함수(accessor function)로 구성된 프로퍼티.

데이터 프로퍼티 정의하기

**데이터 프로퍼티(data property)**는 키와 JavaScript 값으로 구성된 프로퍼티이다. 데이터 프로퍼티를 정의하는 방법은 다음과 같다.

Object.defineProperty() 사용하기

const champion = {};

Object.defineProperty(champion, 'name', {
    value: 'luxanna',
    writable: true,
    enumerable: true,
    configurable: true
});
console.log(champion.name);	// laxanna

접근자 프로퍼티 정의하기

**접근자 프로퍼티(accessor property)**는 키와 접근자 함수로 구성된 프로퍼티이다. **접근자 함수(accessor function)**란 다른 프로퍼티의 값을 읽거나 저장할 때 호출되는 함수로, 다음과 같이 구분할 수 있다.

  • getter: 값을 읽는 접근자 함수. 데이터 프로퍼티에 값을 읽을 때 호출된다.
  • setter: 값을 저장하는 접근자 함수. 데이터 프로퍼티에 값을 저장할 때 호출된다.

사용자는 접근자 함수를 직접 정의할 수 있다. 접근자 함수를 정의하는 방법은 다음과 같다.

  • 객체 이니셜라이저 사용하기
  • Object.defineProperty() 사용하기

객체 이니셜라이저 사용하기

ES6의 메서드 축약 표현과 형태가 같으며 getter의 경우 앞에 get을 붙이고 setter의 경우 set을 붙인다.

const champion = {
    firstName: 'Luxanna',
    lastName: 'Crownguard',
    
    get fullName() {
        return `${this.firstName} ${this.lastName}`;
    },
    set fullName(name) {
        [this.firstName, this.lastName] = name.split(' ');
    }
};

console.log(champion.fullName);	// Luxanna Crownguard
champion.fullName = 'Caitlyn Kiramman';
console.log(champion.fullName);	// Caitlyn Kiramman

ES6의 계산된 프로퍼티 이름을 사용할 수 있다.

const getter = 'fullName';

const champion = {
    firstName: 'Luxanna',
    lastName: 'Crownguard',
    
    get [getter]() {
        return `${this.firstName} ${this.lastName}`;
    },
};

console.log(champion.fullName);	// Luxanna Crownguard

Object.defineProperty() 사용하기

Object.defineProperty() 혹은 Object.defineProperties()를 사용한다. getter의 경우 디스크립터에 get을, setter의 경우 set을 키로 하고 값에 접근자 함수 getter와 setter를 명시한다.

Object.defineProperty(객체, 프로퍼티이름, {
    get: function() {}
    // set: function() {}
});
const champion = {
    firstName: 'Luxanna',
    lastName: 'Crownguard'
};

Object.defineProperty(champion, 'fullName', {
    get: function () {
        return `${this.firstName} ${this.lastName}`;
    }
});

console.log(champion.fullName);	// Luxanna Crownguard

프로퍼티에 접근하기

프로퍼티에 접근하는 방법은 두 가지이다.

  • 점(.) 표기법(dot notation)
  • 대괄호([]) 표기법(bracket notation)

점(.) 표기법

**점 표기법(dot notation)**은 프로퍼티 접근 연산자 .를 사용하여 프로퍼티에 접근한다. 이때 프로퍼티이름은 유효한 식별자여야한다(식별자 네이밍 컨밴션 참고).

객체이름.프로퍼티이름;

즉, 프로퍼티이름이 유효한 식별자가 아니라면 대괄호 표기법을 사용해야 한다.

let foo = {
    'a': 1,
    b: 2,
    3: 3,
};

foo.a;	// 1
foo.b;	// 2
foo.3;	// SyntaxError 발생: 3은 유효한 식별자가 아니다.

대괄호([]) 표기법

**대괄호 표기법(bracket notation)**은 프로퍼티 접근 연산자 []를 사용하여 프로퍼티에 접근한다. 이때 프로퍼티이름은 문자열이나 symbol만을 사용할 수 있다.

객체이름[프로퍼티이름];
  • 단, 유효한 식별자 이름이 아니라면 따옴표를 생략할 수 있다. 문자열로 암묵적 타입 변환하기 때문이다.
let foo = { 1: 'hello' };
console.log(foo[1]);	// 'hello'
console.log(foo['1']);	// 'hello'
let foo = { name: 'lana' };
console.log(foo['name']);	// 'lana'

존재하지 않는 프로퍼티에 접근하기

  • 객체에 존재하지 않는 프로퍼티에 접근하면 undefined를 반환한다.
let foo = {};
console.log(foo.name);	// undefined

유효한 식별자 이름과 프로퍼티 접근하기

  • 프로퍼티의 이름이 유효한 식별자 이름일 경우, 대괄호 표기법을 사용하면 다음과 같은 일이 발생할 수 있다.
let foo = { name: 'lana' };
console.log(foo[name]);		// ReferenceError: name is not defined

이 경우 name은 유효한 식별자 이름이므로 자바스크립트는 name이라는 식별자의 값을 참조하려하지만, name은 선언한 적이 없으므로 ReferenceError를 발생시킨다.

let name = 'teemo';
let foo = { name: 'lana' };
console.log(foo[name]);		// undefined

이 경우 자바스크립트는 name이라는 식별자의 값을 참조하여 'teemo'를 가져오고, foo['teemo']로 이름이 "teemo"인 프로퍼티에 접근하려한다. 그러나 foo'teemo'라는 이름을 가진 프로퍼티는 정의되지 않았으므로, undefined를 반환한다.

let foo = { name: 'lana' };
console.log(foo['name']);	// 'lana'

따라서 프로퍼티의 이름이 유효한 식별자 이름인 경우, 대괄호 표기법에서는 반드시 foo['name']처럼 따옴표로 감싸 접근하도록 한다.

  • 프로퍼티의 이름이 유효한 식별자 이름일 경우, 점 표기법을 사용하면 비교적 쉽다.
let foo = { name: 'lana' };
console.log(foo.name);		// 'lana'

그러니 상황에 따라 적절하게 표기법을 사용하도록 한다.

프로퍼티 동적으로 생성하기

존재하지 않는 프로퍼티에 값을 할당하면 프로퍼티가 동적으로 생성되고 프로퍼티 값이 할당된다.

let album = {};
console.log(album.title);	// undefined
album.title = 'ultraviolence';
console.log(album.title);	// 'ultraviolnece'

프로토타입 객체에 프로퍼티 정의하기

생성자 함수 객체의 prototype 프로퍼티를 사용하여 프로퍼티를 동적으로 생성할 수 있다.

function Cat(name, age) {
    this.name = name;
    this.age = age;
};

const cat1 = new Cat('나비', 5);
const cat2 = new Cat('유미', 10)

Cat.prototype.color = 'black';
console.log(cat1.color);	// black
console.log(cat2.color);	// black

이 경우 Cat.prototype을 상속하는 모든 객체-곧 프로토타입 체인에서 상위 객체에 Cat.prototype이 있는 객체라면 Cat.prototype.color를 상속한다.

인스턴스 객체에 프로퍼티 정의하기

인스턴스 객체에 프로퍼티를 동적으로 생성할 수 있다.

function Cat(name, age) {
    this.name = name;
    this.age = age;
};

const cat1 = new Cat('나비', 5);
const cat2 = new Cat('유미', 10)

cat1.color = 'black';
console.log(cat1.color);	// black
console.log(cat2.color);	// undefined

Cat.prototype을 상속하는 cat1 객체에 프로퍼티를 동적으로 생성한다. 이 경우 cat1 객체에만 color 프로퍼티가 동적으로 생성되며 Cat.prototype을 상속하는 모든 객체에 color 프로퍼티가 동적으로 생성되지 않는다. 따라서 cat2.colorundefined를 반환한다.

프로퍼티 갱신하기

존재하는 프로퍼티에 값을 할당하면 프로퍼티 값이 갱신된다.

let album = { title: 'born to die' };
console.log(album.title);	// 'born to die'
album.title = 'ultraviolence';
console.log(album.title)	// 'ultraviolence'

프로퍼티 삭제하기

delete 연산자를 사용하여 프로퍼티를 삭제한다. 존재하지 않는 프로퍼티를 삭제해도 에러는 발생하지 않는다.

let myCat = new Obj();
myCat.a = 1;

delete myCat.a;
console.log('a' in myCat);		// false

프로퍼티 순회하기

ES6을 기준으로, 객체의 프로퍼티를 순회하는 방법은 다음과 같다.

  • for...in 루프: 객체와 객체의 프로토타입 체인의 모든 열거 가능한 프로퍼티를 순회한다.
  • Object.keys(객체): 객체의 모든 열거 가능한 프로퍼티를 문자열의 배열로 반환한다.
  • Object.getOwnPropertyNames(객체): 객체의 모든 프로퍼티(열거 가능과 불가능 모두)를 문자열의 배열로 반환한다.
let cat = {
    name: 'umi',
    displayName: function() { console.log(this.name); },
};

for (val in cat) {
    console.log(val);
}
// name
// displayName

프로퍼티 존재 확인하기

프로퍼티 in 객체;

in 연산자를 사용하여 프로퍼티가 객체에 존재하는지 확인한다.

let foo = { a: 1 };
console.log('a' in foo);	// true
console.log('b' in foo);	// false

프로퍼티 정렬하기

  • 정수 프로퍼티는 오름차순으로 정렬된다. 문자열을 정수로 변환하거나, 변환된 정수를 다시 문자열로 바꾸어도 변형이 없으면 정수 프로퍼티이다. +42, 1.2 등은 이 경우에 속하지 않는다.
  • 그 외 프로퍼티는 객체에 추가된 순서로 정렬된다.
let obj = {
    'b': 'b',
    2: '2',
    'a': 'a',
    1: '1',
    'd': 'd',
}

Object.keys(obj);	// ['1', '2', 'b', 'a', 'd']

프로퍼티 어트리뷰트

각 프로퍼티는 여러 가지 상태를 가진다. 예를 들어 프로퍼티는 그 자신의 값을 갱신할 수 있는지를 나타내는 Boolean 값의 상태를 가진다.

ECMAScript 명세는 **프로퍼티 어트리뷰트(Property Attribute)**라는 용어를 사용하여 프로퍼티의 상태를 설명한다. 프로퍼티 어트리뷰트는 내부 슬롯의 일종이다.

프로퍼티 어트리뷰트와 내부 슬롯에 대해서는 내부 슬롯과 내부 메서드를 참고한다.

hidden class

자바스크립트 객체는 프로퍼티 키를 인덱스로 사용하는 해시 테이블과 유사하다. 다른 객체 지향 프로그래밍 언어의 경우 사전에 정의된 클래스를 기반으로 객체를 생성하고 객체가 생성된 이후에는 프로퍼티를 추가하거나 삭제할 수 없다. 이에 반해 자바스크립트 객체는 객체가 생성된 이후 동적으로 프로퍼티를 추가할 수 있다. 이는 성능 면에서 상당히 비효율적이므로 V8 자바스크립트 엔진은 프로퍼티에 접근할 때 동적 탐색(dynamic lookup)이 아니라 히든 클래스(hidden class) 방식을 사용한다.

11.4 메서드

  • 일반적으로 **메서드(method)**는 값이 함수인 프로퍼티이다.
  • 일반적인 메서드의 개념과 달리 ECMAScript에서 메서드는 오직 ES6의 메서드 축약 표현을 사용하여 정의한 함수(객체 리터럴이나 클래스에서 정의)이다. 이 개념의 메서드에 대해서는 12. Functions - 메서드를 참고한다.

여기서는 일반적인 의미의 메서드를 사용한다.

메서드 정의하기

객체 이니셜라이저에서 메서드 정의하기

  • 객체 이니셜라이저에서 프로퍼티에 할당할 값으로서 함수 표현식은 function 키워드를 사용하여 정의할 수 있다.
let circle = {
    radius: 2,
    
    getDiameter: function() {
        return 2 * this.radius;
    }
};
  • 한편 ES6의 메서드 축약 표현(shorthand method definition)을 사용하여 function 키워드를 생략할 수 있다.
let circle = {
    radius: 2,

    getDiameter() {
        return 2 * this.radius;
    }
};

Object Initializer를 참고한다.

생성자에서 메서드 정의하기

  • 생성자에서 프로퍼티에 할당할 값으로서 함수 표현식은 function 키워드를 사용하여 정의할 수 있다.
function Circle(radius) {
    this.radius = radius;
    this.getDiameter = function () {
        return 2 * this.radius;
    };
}

메서드 동적으로 생성하기

  • 프로토타입 객체에 메서드를 동적으로 생성할 수도 있다.
function Circle(radius) {
    this.radius = radius;
}

Circle.prototype.getDiameter = function () {
    return 2 * this.radius;
};
  • 인스턴스 객체에 메서드를 동적으로 생성할 수 있다.
function displayCat() {
    console.log(this.name);
}

function Cat(name) {
    this.name = name;
}

const cat = new Cat('rey');
cat.displayCat = displayCat;
cat.displayCat();	// 'rey'

프로퍼티 동적으로 생성하기를 참고한다.

11.5 객체 비교하기

  • 객체 비교 시 동등 연산자 ==와 일치 연산자 ===는 동일하게 동작한다.
  • 객체는 참조 타입이다. 따라서 두 개의 객체는 동일한 프로퍼티들을 가지더라도 절대로 일치(equl)하지 않는다. 오직 같은 객체 참조끼리 비교할 때에만 true를 반환한다.
var foo = { name: 'a' };
var bar = { name: 'a' };

foo == bar;		// false
foo === bar;	// false
var foo = { name: 'a' };
var bar = bar;

foo == bar;		// true
foo === bar;	// true

11.6 표준 내장 객체

  • **표준 내장 객체(standard built-in objects)**는 ECMAScript에 정의된 객체로, 모든 런타임에서 **전역 객체(global object)**의 프로퍼티로 제공된다. String, Number, Date 등이 속한다.

표준 내장 객체에 대해서는 [Standard Built-in Objects](./Standard Built-in Objects.md)를 참고한다. 전역 객체에 대해서는 11.7 전역 객체를 참고한다.

11.7 전역 객체

  • 런타임에 따라 전역 객체를 가리키는 식별자가 다르다. 브라우저는 window, Node.js는 global이다. ES11의 globalThis는 런타임에 관계없이 전역 객체를 가리킨다.
  • **전역 객체(global object)**는 표준 내장 객체와 호스트 객체, var로 선언한 전역 변수와 암묵적 전역, 전역 함수를 프로퍼티로 가진다.
    • 호스트 객체(host object); ECMAScript에 정의되어있지 않으나 런타임에서 추가적으로 제공하는 객체들이다. 특히 브라우저에서 제공하는 호스트 객체(DOM, Canvas, fetch 등)를 클라이언트 사이드 Web API라고 한다.
  • 전역 객체의 프로퍼티는 var로 선언한 전역 변수를 제외하고 모두 delete를 사용하여 삭제할 수 있다.
  • 전역 객체의 프로퍼티에 접근할 때는 전역 객체를 가리키는 식별자를 생략할 수 있다.
var a = 1;
window.a;	// 1
a;	// 1

암묵적 전역

i = 3;
console.log(window.i);	// 3
console.log(i);	// 3

선언하지 않은 식별자에 값을 할당하는 것은 전역 객체의 프로퍼티를 생성하는 것과 같다. 여기서 window.i전역 변수가 아니라 다만 전역 객체의 프로퍼티이다. 따라서 변수 호이스팅이 발생하지 않으며 delete 연산자를 사용하여 삭제할 수 있다. (var로 선언한 전역 변수는 전역 변수이기 때문에 삭제될 수 없으며 변수 호이스팅도 작동한다.)

암묵적 전역(implicit global)은 이처럼 선언하지 않은 식별자에 값을 할당하여 생성된 전역 객체의 프로퍼티가 전역 변수처럼 동작하는 것을 말한다.

빌트인 전역 프로퍼티

빌트인 전역 프로퍼티는 전역 객체에 기본적으로 내장된 프로퍼티이다. 값 프로퍼티와 함수 프로퍼티로 나눌 수 있다.

값 프로퍼티

  • globalThis: 런타임에 관계없이 전역 객체를 가리킨다.
  • Infinity: Number 타입으로 무한대를 나타낸다. Number.POSITIVE_INFINITY와 같다.
  • NaN: Number 타입으로 숫자가 아님을 나타낸다. Number.NaN과 같다.
  • undefined: Undefined 타입으로 원시값 undefined를 값으로 가진다.

함수 프로퍼티

  • eval: 인수로 자바스크립트 코드를 나타내는 문자열을 전달받아 평가, 실행하여 값을 생성한다. 기존의 스코프를 동적으로 변경한다.
  • isInfinite: 인수의 타입을 Number로 변환하여 유한수인지 확인한다.
  • isNaN: 인수의 타입을 Number로 변환하여 숫자가 아닌지 확인한다.
  • parseFloat: 인수를 부동 소수점 숫자로 해석하여 반환한다.
  • parseInt: 인수를 정수로 해석하여 반환한다.
  • decodeURI/decodeURIComponent: 인코딩된 URI/인코딩된 쿼리스트링을 이스케이프 처리 이전으로 디코딩한다.
  • encodeURI/encodeURIComponent: 완전한 URI/쿼리스트링를 인코딩(아스키 문자로 변환)한다.

객체의 변경 방지하기

JavaScript에서 객체는 변경 가능한 값이다. 객체의 변경이란 다음과 같다.

  1. 프로퍼티 추가
  2. 프로퍼티 삭제
  3. 프로퍼티 쓰기(값 변경하기)
  4. 프로퍼티 어트리뷰트 재정의

JavaScript에서 객체의 변경을 방지하는 메서드는 다음과 같다.

  • Object.preventExtensions
  • Object.seal
  • Object.freeze

또한 이들 모두 객체의 프로토타입을 재할당하는 것을 방지한다.

메서드 프로퍼티 읽기 프로퍼티 쓰기 프로퍼티 어트리뷰트 재정의 프로퍼티 삭제 프로퍼티 추가 프로토타입 재할당
Object.preventExtensions O O O O X X
Object.seal O O X X X X
Object.freeze O X X X X X

객체 확장 금지하기

확장할 수 없는 객체는 프로퍼티를 추가할 수 없다. Object.preventExtensions를 사용하여 객체의 확장을 방지할 수 있다. Object.isExtensible을 사용하여 객체가 확장 가능한지 검사할 수 있다.

const foo = { a: 1 };
console.log(Object.isExtensible(foo));	// true
Object.preventExtensions(foo);
console.log(Object.isExtensible(foo));	// false

객체 봉인하기

봉인된 객체는 확장할 수 없으며 프로퍼티를 삭제하거나 프로퍼티 어트리뷰트를 재정의할 수 없다. 즉, 봉인된 객체는 프로퍼티 읽기와 쓰기만 허용한다. Object.seal을 사용하여 객체를 봉인할 수 있다. Object.isSealed을 사용하여 객체가 봉인되었는지 검사할 수 있다.

const foo = { a: 1 };
console.log(Object.isSealed(foo));	// false
Object.seal(foo);
console.log(Object.isSealed(foo));	// true

객체 동결하기

동결된 객체는 확장할 수 없고, 봉인되었으며 프로퍼티의 값을 변경할 수 없다. 즉, 동결된 객체는 프로퍼티 읽기만 가능하다. Object.freeze를 사용하여 객체를 동결할 수 있다. Object.isFrozen을 사용하여 객체가 동결되었는지 검사할 수 있다.

const foo = { a: 1 };
console.log(Object.isFrozen(foo));	// false
Object.freeze(foo);
console.log(Object.isFrozen(foo));	// true

내부 슬롯과 내부 메서드

내부 슬롯과 내부 메서드는 ECMAScript 명세에서 객체를 설명할 때 사용하는 알고리즘과 내부 상태이다. 내부 슬롯과 내부 메서드에 대해서는 Internal Slot and Internal Method를 참고한다.

프로퍼티 어트리뷰트

프로퍼티 어트리뷰트(Property Attribute)는 객체 프로퍼티의 상태를 나타내는 내부 슬롯이다. Property Attributes를 참고한다.

참고

  • 모던 자바스크립트 Deep Dive 10장 객체 리터럴
  • 모던 자바스크립트 Deep Dive 11장 원시 값과 객체의 비교
  • 모던 자바스크립트 Deep Dive 16장 프로퍼티 어트리뷰트
  • 모던 자바스크립트 Deep Dive 21장 빌트인 객체
  • MDN - Working with objects
  • MDN - Object initializer