--- title: 객체로 작업하기 slug: Web/JavaScript/Guide/Working_with_Objects tags: - Beginner - Comparing object - Document - Guide - JavaScript - Object - l10n:priority translation_of: Web/JavaScript/Guide/Working_with_Objects --- {{jsSidebar("JavaScript Guide")}} {{PreviousNext("Web/JavaScript/Guide/Keyed_collections", "Web/JavaScript/Guide/Details_of_the_Object_Model")}} JavaScript는 간단한 객체 기반 패러다임 위에 만들어졌습니다. 객체는 속성의 컬렉션이고, 속성은 이름('키')과 값 사이의 연결 관계입니다. 속성의 값이 함수인 경우에는 메서드라고 부릅니다. 브라우저 안에 미리 정의된 객체 뿐만 아니라 여러분이 직접 객체를 정의할 수도 있습니다. 이번 장에서는 객체, 속성, 함수, 메서드 사용법과 함께 직접 새로운 객체를 생성하는 법을 알아봅니다. ## 객체 개요 JavaScript의 객체는, 다른 프로그래밍 언어에서와 마찬가지로 현실 세계에서 객체(사물)라고 부르는 것과 비교할 수 있습니다. JavaScript 객체의 개념은 현실에서 인식 가능한 사물로 이해가 가능합니다. JavaScript에서 객체는 속성과 타입을 가진 독립적인 개체(entity)입니다. 현실의 컵과 비교해본다면, 컵은 색, 디자인, 무게, 소재 등의 속성을 가진 객체라고 할 수 있습니다. 마찬가지로 JavaScript 객체 역시 특징을 결정짓는 속성을 가질 수 있습니다. ## 객체와 속성 JavaScript 객체는 자신과 연관된 속성들을 가집니다. 객체의 속성은 객체에 붙은 변수라고 설명할 수 있겠습니다. 객체의 속성은 일반적인 JavaScript 변수와 똑같은데, 다만 객체에 붙어있다는 점만 다릅니다. 속성에 접근할 땐 간단한 마침표 표기법을 사용합니다. ```js objectName.propertyName ``` 다른 모든 JavaScript 변수와 마찬가지로, 객체의 이름(아마도 그냥 변수)과 속성의 이름 모두 대소문자를 구별합니다. 객체에 속성을 정의하려면 값을 할당하세요. 예를 들기 위해 `myCar`라는 객체를 생성하고, `make`, `model`, `year`라는 이름의 속성을 추가해보겠습니다. ```js const myCar = new Object(); myCar.make = "Ford"; myCar.model = "Mustang"; myCar.year = 1969; ``` 위의 코드는, 중괄호(`{}`) 안에 쉼표로 구분한 속성 이름과 값의 목록으로 나타내는 [**객체 초기자**](#객체_초기자)로 나타낼 수도 있습니다. ```js const myCar = { make: 'Ford', model: 'Mustang', year: 1969 }; ``` 객체에 할당되지 않은 속성은{{jsxref("undefined")}}입니다. ({{jsxref("null")}}이 아닙니다) ```js myCar.color; // undefined ``` JavaScript의 객체 속성은 대괄호 표기법([속성 접근자](/ko/docs/Web/JavaScript/Reference/Operators/Property_Accessors))을 사용해 접근할 수도 있습니다. 객체를 때때로 '연관 배열'(associative array)이라고 부르기도 하는데, 속성은 자신에 접근할 수 있는 문자열 값과 연관되어 있기 때문입니다. 그러므로 `myCar` 객체의 속성에 아래와 같이 접근할 수도 있을 것입니다. ```js myCar['make'] = 'Ford'; myCar['model'] = 'Mustang'; myCar['year'] = 1969; ``` 객체 속성 이름은 유효한 JavaScript 문자열 혹은 문자열로 변환 가능한 것이면 모두 가능하며, 빈 문자열도 여기 포함됩니다. 그러나 유효한 JavaScript 식별자가 아닌 이름(공백이나 붙임표, 숫자로 시작하는 이름)을 가진 속성은 대괄호 표기법으로만 접근할 수 있습니다. 대괄호 표기법은 속성 이름이 동적으로 정해지는 경우, 즉 런타임 시점까지 알 수 없는 경우 유용합니다. 아래 예제를 살펴보세요. ```js // 네 개의 변수를 쉼표로 구분해서 // 한 번에 생성하고 할당 const myObj = new Object(), str = 'myString', rand = Math.random(), obj = new Object(); myObj.type = '마침표 구문'; myObj['date created'] = '공백을 포함한 문자열'; myObj[str] = '문자열 값'; myObj[rand] = '무작위 수'; myObj[obj] = '객체'; myObj[''] = '빈 문자열까지'; console.log(myObj); ``` 모든 대괄호 표기법 안의 키는 심볼이 아닌 경우 문자열로 변환되는 점을 기억하세요. JavaScript 객체의 속성 이름(키)은 문자열이나 심볼 뿐이기 때문입니다([클래스 필드 제안서](https://github.com/tc39/proposal-class-fields)로 인해 비공개 속성 이름도 추가되겠지만, 비공개 속성 접근에는 `[]` 형식을 사용하지 않을 것입니다). 예를 들어, 위 코드의 `myObj`에 `obj`를 키로 추가하는 부분에서 JavaScript는 {{jsxref("Object.toString", "obj.toString()")}} 메서드를 호출한 결과 문자열을 새로운 키로 사용합니다. 속성 접근은 변수에 저장된 문자열 값으로도 가능합니다. ```js let propertyName = 'make'; myCar[propertyName] = 'Ford'; propertyName = 'model'; myCar[propertyName] = 'Mustang'; ``` 대괄호 표기법은 [`for...in`](/ko/docs/Web/JavaScript/Reference/Statements/for...in)과 함께 객체의 열거 가능한 속성을 순회할 때도 사용할 수 있습니다. 아래 함수는 이 방법의 동작 방식을 보이는 예제로, 객체와 객체 이름을 매개변수로 제공하면 객체의 속성들을 출력합니다. ```js function showProps(obj, objName) { let result = ''; for (let i in obj) { // obj.hasOwnProperty()를 사용해서 객체의 프로토타입 체인에 존재하지 않는 속성을 제외 if (obj.hasOwnProperty(i)) { result += `${objName}.${i} = ${obj[i]}\n`; } } console.log(result); } ``` `showProps(myCar, 'myCar')`를 호출하면 이렇게 출력됩니다. ``` myCar.make = Ford myCar.model = Mustang myCar.year = 1969 ``` ## 객체 속성 나열하기 객체 속성을 나열하거나 순회하는 방법에는 세 가지 내장된 방법이 있습니다. - [for...in](/ko/docs/Web/JavaScript/Reference/Statements/for...in) 반복문. 이 방법은 객체와 객체의 프로토타입 체인에 존재하는 모든 열거 가능한 속성을 순회합니다. 이 방법은 객체와 객체의 프로토타입 체인 상의 열거 가능한 모든 프로퍼티를 순회한다. - {{jsxref("Object.keys", "Object.keys(o)")}}. 이 방법은 `o` 객체 자신만의(프로토타입 체인을 제외한) 열거 가능한 속성 이름("키")을 배열로 반환합니다. - {{jsxref("Object.getOwnPropertyNames", "Object.getOwnPropertyNames(o)")}}. 이 방법은 `o` 객체 자신만의 모든(열거 불가능하더라도) 속성 이름("키")을 배열로 반환합니다. '숨은' 속성(프로토타입 체인 상의 속성 중, 같은 이름의 속성이 체인에서 앞서 존재해서 가려진 속성)을 나열하는 내장 방법은 없습니다. 그러나 밑의 함수를 사용하면 가능합니다. ```js function listAllProperties(o) { let objectToInspect = o; let result = []; while(objectToInspect !== null) { result = result.concat(Object.getOwnPropertyNames(objectToInspect)); objectToInspect = Object.getPrototypeOf(objectToInspect) } return result; } ``` ## 객체 생성하기 JavaScript에는 미리 정의된 객체가 여럿 존재합니다. 여기에 더해 여러분만의 객체도 생성할 수 있습니다. 객체 생성에는 [객체 초기자](/ko/docs/Web/JavaScript/Reference/Operators/Object_initializer)를 사용할 수도 있고, 생성자 함수를 정의한 후에 `new` 연산자와 함께 호출해서 객체 인스턴스를 생성할 수도 있습니다. ### 객체 초기자 사용하기 객체 초기자의 사용은 종종 "리터럴 표기에 의한 객체 생성"이라고 불립니다. "객체 초기자"(Object initializer)라는 단어는 C++에서 사용하는 용어와 같습니다. 객체 초기자를 사용한 객체 생성 구문은 다음과 같습니다. ```js const obj = { property_1: value_1, // 속성의 값은 식별자일 수도 있고 2: value_2, // 숫자일 수도 있고 // ..., 'property n': value_n // 문자열일 수도 있음 }; ``` 위 코드에서 `obj`는 새로운 객체의 이름이고, 콜론 앞에 위치한 속성 이름은 식별자(이름, 숫자, 스트링 리터럴), 각각의 `value_i`는 속성 이름에 할당할 표현식입니다. `obj`와 할당 구문은 선택 사항으로, 이 객체를 다른 곳에서 참조하지 않아도 되면 변수에 할당할 필요도 없습니다. (명령문을 기대하는 곳에 객체 리터럴을 배치하려면 블록 선언문으로 잘못 읽는 경우가 없도록 괄호로 감싸줄 필요가 있습니다) 객체 초기자는 표현식이며 자신이 속한 선언문이 실행될 때마다 새로운 객체를 생성합니다. 같은 초기자가 생성한 객체끼리라도 구별 가능하며 서로 비교했을 때 거짓을 반환합니다. 초기자가 생성하는 객체는 마치 `new Object()` 호출을 한 것과 같이 생성됩니다. 즉 객체 초기자 표현식의 결과 객체들은 `Object`의 인스턴스입니다. 다음 선언문은 `cond`가 참일 때만 객체를 생성해서 변수 `x`에 할당합니다. ```js let x; if (cond) { x = {greeting: '안녕하세요'}; } ``` 다음 예제는 `myHonda`를 세 개의 속성과 함께 생성합니다. `engine` 속성 역시 자신만의 속성을 가진 객체임에 주목하세요. ```js const myHonda = {color: 'red', wheels: 4, engine: {cylinders: 4, size: 2.2}}; ``` 객체 초기자로 배열을 생성할 수도 있습니다. [배열 리터럴](/ko/docs/Web/JavaScript/Guide/Grammar_and_types#배열_리터럴)을 참고하세요. ### 생성자 함수 사용하기 다른 방법으로, 다음의 두 단계를 통해 객체를 생성할 수 있습니다. 1. 생성자 함수를 작성해서 객체 타입을 정의합니다. 객체 타입 이름의 첫 글자는, 그럴만한 이유로, 대문자로 시작하는 관례가 있습니다. 2. `new` 연산자를 사용해 객체 인스턴스를 생성합니다. 객체 타입을 정의하려면 타입 이름, 속성, 메서드를 지정하는 함수를 생성하세요. 예를 들어 차량을 표현하기 위한 객체 타입을 정의한다고 합시다. 그러면 객체 타입의 이름은 `Car`가 될 것이고, 브랜드와 모델, 연식 속성이 필요할 것입니다. ```js function Car(make, model, year) { this.make = make; this.model = model; this.year = year; } ``` 함수에 전달한 값을 객체 속성으로 할당하기 위해 `this`를 사용하는 것에 주목하세요. 이제 `mycar` 객체를 생성할 수 있습니다. ```js var mycar = new Car("Eagle", "Talon TSi", 1993); ``` 이 선언문은 `mycar`를 생성한 후 매개변수로 지정한 값을 속성에 할당합니다. 이후 `mycar.make`는 문자열 "Eagle", `mycar.year`는 정수 1993 등을 가지게 됩니다. `new`를 사용한 호출로 몇 개의 `Car` 객체라도 만들 수 있습니다. ```js const kenscar = new Car("Nissan", "300ZX", 1992); const vpgscar = new Car("Mazda", "Miata", 1990); ``` 객체는 다른 객체도 속성으로 가질 수 있습니다. `Person`이라는 객체를 다음과 같이 정의한다고 하겠습니다. ```js function Person(name, age, sex) { this.name = name; this.age = age; this.sex = sex; } ``` 두 개의 새로운 `Person` 객체도 인스턴스화 했다고 합시다. ```js const rand = new Person('Rand McKinnon', 33, 'M'); const ken = new Person('Ken Jones', 39, 'M'); ``` 이제 `Car`의 정의를, `Person` 객체를 갖는 `owner` 속성을 추가하도록 수정할 수 있습니다. ```js function Car(make, model, year, owner) { this.make = make; this.model = model; this.year = year; this.owner = owner; } ``` 그 후에, 새로운 객체 인스턴스를 생성할 땐 이렇게 할 수 있습니다. ```js const car1 = new Car('Eagle', 'Talon TSi', 1993, rand); const car2 = new Car('Nissan', '300ZX', 1992, ken); ``` 문자열 리터럴이나 정수 값이 아니라 객체 `rand`와 `ken`을 소유자 매개변수로 지정했음을 볼 수 있습니다. 이제 `car2`의 소유자 이름을 알려면 이렇게 속성에 접근합니다. ```js car2.owner.name ``` 이미 정의된 객체에도 속성을 추가할 수 있습니다. 예를 들어, ```js car1.color = 'black'; ``` 위의 코드는 `car1`에 `color` 속성을 추가한 후 값으로 `'black'`을 할당하고 있습니다. 그러나 이 방법은 다른 객체에 영향을 주지 않습니다. 같은 타입의 모든 객체에 값을 추가하려면 `Car` 객체 타입의 정의를 수정해야 합니다. ### `Object.create` 메서드 사용하기 {{jsxref("Object.create()")}} 메서드로 객체를 생성할 수도 있습니다. 이 메서드는 생성자 함수 정의 없이도 생성할 객체의 프로토타입을 지정할 수 있으므로 유용할 수도 있습니다. ```js // 동물 속성과 메서드 캡슐화 const Animal = { type: '무척추동물', // 속성 기본 값 displayType: function() { // 동물 종류를 출력할 메서드 console.log(this.type); } }; // animal1이라는 이름의 동물 타입 객체 생성 const animal1 = Object.create(Animal); animal1.displayType(); // 출력: 무척추동물 // fish라는 이름의 동물 타입 객체 생성 const fish = Object.create(Animal); fish.type = '물고기'; fish.displayType(); // 출력: 물고기 ``` ## 상속 JavaScript의 모든 객체는 적어도 하나의 다른 객체를 상속합니다. 상속 대상 객체를 프로토타입이라고 부르고, 상속한 속성은 생성자의 `prototype` 객체에서 찾을 수 있습니다. [상속과 프로토타입 체인](/ko/docs/Web/JavaScript/Inheritance_and_the_prototype_chain)에서 자세히 알아보세요. ## 객체 속성 인덱싱 객체의 속성에 접근할 땐 속성 이름이나 인덱스로 접근할 수 있습니다. 처음에 속성을 이름으로 정의했으면 그 속성은 항상 이름으로만 참조해야 하고, 처음에 인덱스로 정의했으면 항상 인덱스로만 참조해야 합니다. 이 제한은 (위에서 `Car` 객체 타입으로 했던 것과 같이) 생성자 함수로 객체와 속성을 생성할 때, 그리고 (`myCar.color = 'red'`처럼) 각각의 속성을 명시적으로 정의할 때 모두 해당됩니다. 만약 객체의 속성을 `myCar[5] = '25 mpg'`처럼 인덱스로 정의했으면 이후에 참조할 때도 `myCar[5]`로 해야 합니다. 다만 HTML 요소를 나타내는, `document.forms`와 같은 유사 배열 객체에는 예외로, 문서 상의 순서를 나타내는 인덱스로 접근할 수도 있고 (정의된 경우) 이름으로 접근할 수도 있습니다. 즉 문서의 두 번째 `