객체는 { } 중괄호를 사용해 정의한다. 객체는 속성의 집합으로 이뤄지고, 속성은 이름과 값으로 이뤄진다. 객체 정의 시 속성이름:값
형태로 속성을 정의할 수 있다.
예를 들어 회원제 사이트에서 회원정보를 어떻게 저장할까? 회원으로 가입하면 이름, 아이디, 비밀번호, 생년월일 등 여러 정보가 하나의 회원정보에 저장될 것이다. 그리고 회원정보를 확인할 때 이 정보를 한번에 가져와야 한다. 이 경우 '회원'이라는 변수에 여러 정보를 저정하는 것이 편하므로 변수 '회원'을 객체 형태로 만든다.
객체에서 값을 담고 있는 정보를 속성이라고 한다. 객체의 속성값을 가져올 때는 객체 이름 뒤에 마침표(.)를 찍고 그 뒤에 속성 이름을 적는다.
navigator.vendor // "Google Inc." 브라우저 제조업체 정보
navigator.onLine // true or false 인터넷 연결 여부
메소드는 객체가 어떻게 동작할지를 선언해 놓은 함수이다. 즉, 객체 안에서 정의된 함수이다. 객체의 메소드를 사용할 때는 마침표(.)를 사용해 객체 이름 다음에 메소드를 지정하면 된다. 메소드를 실행할 인수가 필요하면 괄호 안에 인수를 지정하고, 필요 없다면 빈 괄호를 함께 입력한다.
❗️ window 객체는 모든 객체를 품고 있는 차상위 객체이기 때문에 window 객체의 함수를 실행할 때에는 window와 마침표를 빼고 함수 이름만 사용해서 실행해도 된다.
window.alert("안녕하세요.")
alert("안녕하세요") // 위와 동일
Navigator
객체, 브라우저에서 방문한 기록을 남기는 History
객체, 화면 크기 정보가 들어 있는 Screen
객체 등이 있다.var book = {
title : "마음의 소리",
author : "조석",
info : function(){
alert(this.title + "책의 작가는 " + this.author + "입니다.");
}; //info 함수 (메소드)
};
book.title // 마음의 소리
book.info()
상속 (inheritance)
상속이란 새로운 클래스에서 기존 클래스의 모든 속성과 메소드를 사용할 수 있는 것을 의미합니다. 상속을 통해 새로운 프로그램의 요구에 맞게 기존 클래스를 수정하여 재사용할 수 있습니다. 또한, 클래스 간의 종속 관계를 형성함으로써 객체의 관계를 조직화할 수 있는 장점이 있습니다. 따라서 이러한 상속은 추상화, 캡슐화와 더불어 객체 지향 프로그래밍을 구성하는 중요한 특징 중 하나가 됩니다.
하지만 C#, C++과 같은 클래스 기반(class-based)의 객체 지향 언어와는 달리 자바스크립트는 프로토타입 기반(prototype-based)의 객체 지향 언어입니다. 프로토타입 기반이기 때문에 상속의 개념이 클래스 기반의 객체 지향 언어와는 약간 다릅니다.
자바스크립트의 모든 객체는 '프로토타입'이라는 객체를 가지고 있습니다. 모든 객체는 그들의 프로토타입으로부터 속성과 메소드를 상속받는다. 이처럼 자바스크립트의 모든 객체는 최소한 하나 이상의 다른 객체로부터 상속을 받으며, 이때 상속되는 정보를 제공하는 객체를 프로토타입, 프로토타입을 이용해 만들어낸 객체를 인스턴스(개별 객체)라고 한다.
프로토타입 객체도 또 다시 상위 프로토타입 객체로부터 메소드와 속성을 상속 받을 수도 있고 그 상위 프로토타입 객체도 마찬가지이다. 이를 프로토타입 체인(prototype chain)이라 부르며 다른 객체에 정의된 메소드와 속성을 한 객체에서 사용할 수 있도록 하는 근간이 된다.
// 1
function Person(name,first,second){
this.name = name;
this.first = first;
this.second = second;
}
//2
Person.protytpe.sum = function(){}
var kim = new Person('kim',10,20);
1) 위 코드에서 Person 이라는 새로운 객체가 생성된다. 이때, Person 이라는 객체만 생성되는것이 아니라 Person's prototype 객체도 같이 생성된다. 두 객체의 관계는 다음과 같다.
Person 객체
의 prototype 속성은 Person's prototype 객체를 가리키고,Person's prototype 객체
는 constructor 라는 속성을 생성해 Person 객체를 가리킨다.
2) kim 이라는 새로운 객체를 생성하고 Person's prototype 객체에 sum( )이라는 함수를 추가해준 것이다. 새로운 객체를 생성할때 객체의 프로퍼티와 함께 __proto__
프로퍼티가 같이 생성된다. __proto__
는 kim 이라는 객체를 생성한 Person 객체의 prototype 객체를 가리킨다. (Person's prototype)
우리는 Person.prototype을 통해서 Person's prototype 객체에 접근할 수 있고 kim 객체의 __proto__
를 통해서도 Person's prototype 객체에 접근 할 수 있다.
❗프로토타입 체인에서 한 객체의 속성과 메소드들은 다른 객체로 복사되는 것이 아니다. Java Script에서는 객체 인스턴스와 프로토타입 간에 체인이 구성되며, 이 프로토타입 체인을 타고 올라가며 속성과 메소드를 탐색한다.
객체를 사용하는 것만으로 객체 지향이 가능한데 왜 프로토타입이 필요한 것일까?
/* 1) 두 객체의 메소드가 따로 정의되어 메모리 낭비 */
function Person(name,company){
this.name = name;
this.company = company;
this.getName = function(){
return this.name;
};
this.setName = function(name){
this.name = name;
};
}
const Na = new Person("나혜수", "cnu");
const kim = new Person("김혜수", "cnu");
console.log(Na); // Person {name: '나혜수', company: 'cnu', getName: ƒ, setName: ƒ}
console.log(kim); // Person {name: '김혜수', company: 'cnu', getName: ƒ, setName: ƒ}
/* 2) Person's prototype 객체에 메소드 추가 */
function Person(name,company){
this.name = name;
this.company = company;
Person.prototype.getName = function(){
return this.name;
};
Person.prototype.setName = function(name){
this.name = name;
};
}
const Na = new Person("나혜수", "cnu");
const kim = new Person("김혜수", "cnu");
console.log(Na); // Person {name: '나혜수', company: 'cnu'}
console.log(kim); // Person {name: '김혜수', company: 'cnu'}
console.log(Na._proto_); // {getName:f, setName:f, constructor:f}
console.log(Person.__proto__); // {}
console.log(Person.prototype); // {getName:f, setName:f, constructor:f}
자바스크립트에서 객체를 생성하는 가장 쉬운 방법은 리터럴 표기를 이용하는 방법입니다. 각각의 프로퍼티는 이름과 값을 콜론(:)으로 연결하고, 쉼표(,)를 사용해 다른 프로퍼티와 구분합니다.
/* 개별적으로 객체 선언 */
var kitty = {
name: "나비",
family: "코리안 숏 헤어",
age: 1,
weight: 0.1
};
리터럴 표기를 사용하면 객체를 쉽게 만들 수 있지만, 정해진 값을 가진 객체를 한 번만 만든다. 만약 이 방법으로 도서 관리 프로그램을 작성하면 매번 똑같은 속성과 함수를 입력하고 값을 다르게 넣어 새로운 객체를 만들어야 한다. 이때 항상 필요한 속성과 함수를 미리 틀처럼 만들고, 필요 시 그 틀을 복제한 인스턴스를 만들어 값을 담는 것이 편하다. 이럴 대 사용하는 것이 생성자 함수이다.
프로토타입을 생성하는 가장 기본적인 방법은 객체 생성자 함수를 작성하는 것이다. 생성자 함수 (생성자)란 객체를 만들어 내는 함수를 말한다. 생성자 함수를 작성하고 new
예약어를 사용해 객체를 생성하면, 같은 프로토타입을 가지는 객체들을 생성할 수 있다.
생성자 함수
함수 이름의 첫 글자는 대문자로 시작
반드시new
연산자를 붙여 실행
생성자 함수 작동 과정
1. 빈 객체를 만들어this
에 할당
2.this
에 새로운 프로퍼티를 추가해this
를 수정
3.this
를 반환
생성된 객체 반환
반환문이 없는 경우, this에 바인딩된 새로 생성한 객체가 반환된다. 반환문이 this가 아닌 다른 객체를 명시적으로 반환하는 경우, this가 아닌 해당 객체가 반환된다. 이때 this를 반환하지 않은 함수는 생성자 함수로서의 역할을 수행하지 못한다. 따라서 생성자 함수는 반환문을 명시적으로 사용하지 않는다.
function User(name) {
// this = {}; (빈 객체가 암시적으로 만들어짐)
// 새로운 프로퍼티를 this에 추가함
this.name = name;
this.isAdmin = false;
// return this; (this가 암시적으로 반환됨)
let user = new User("메이"); //user 객체 생성
console.log(user.name); // 메이
console.log(user.isAdmin); // false
}
new User("메이")
이외에도 new User("루이")
, new User("바니")
등을 이용하면 객체 리터럴 문법으로 일일이 객체를 만드는 방법보다 훨씬 간단하게 객체를 만들 수 있다. 생성자의 의의는 재사용할 수 있는 객체 생성 코드를 구현하는 것이다.
Class는 객체를 생성하기 위한 템플릿으로 자바스크립트 ES6부터 class를 지원한다.
Class body는 중괄호 { } 로 묶여 있는 안쪽 부분으로 이곳에 메소드와 constructor를 정의한다. 참고로 Class body는 strict mode에서 실행된다. 즉, 여기에 적힌 코드는 성능 향상을 위해 더 엄격한 문법이 적용된다.
constructor
는 인스턴스를 생성하고 클래스 필드를 초기화하기 위한 특수한 메소드이다. constructor
는 클래스 안에 한 개만 존재할 수 있고 2개 이상 있을 경우 Syntax Error가 발생한다.
class Person {
height = 180; // 인스턴스 변수
constructor(name, age) {
// this는 클래스가 생성할 인스턴스를 가리킨다.
this.name = name;
this.age = age;
}
}
let person1 = new Person('john', 23);
console.log(person1.name); // john
console.log(person1.age); // 23
console.log(person1.height); // 180
class Calculator {
add(x, y) {
return x + y;
}
subtract(x, y) {
return x - y;
}
}
let calc = new Calculator();
calc.add(1,10); // 11