hoon's bLog

Javascript 객체 Object 상속, 프로토타입 prototype, 순회 본문

IT/Javascript

Javascript 객체 Object 상속, 프로토타입 prototype, 순회

개발한기발자 2023. 4. 29. 12:34
반응형


객체의 전반적인 기본 개념을 보시려면 "객체(1)" ← ← 포스팅을 참고해 주세요!!

상속(inheritance)

  • 새로운 클래스에서 기존 클래스의 모든 프로퍼티와 메서드를 사용할 수 있는 것
  • 상속을 통해 새로운 프로그램의 요구에 맞게 기존 클래스를 수정하여 재사용 가능
  • 클래스 간의 종속 관계를 형성함으로써 객체의 관계를 조직화 가능

자바스크립트는 프로토타입 기반(prototype-based)의 객체 지향 언어

자바스크립트에서는 현재 존재하고 있는 객체를 프로토타입으로 사용하여, 해당 객체를 복제하여 재사용하는 것을 상속이라고 함.

프로토타입(prototype)

  • 자바스크립트의 모든 객체는 프로토타입(prototype)이라는 객체를 가지고 있음
  • 모든 객체는 그들의 프로토타입으로부터 프로퍼티와 메서드를 상속
  • 이처럼 자바스크립트의 모든 객체는 최소한 하나 이상의 다른 객체로부터 상속을 받으며, 이때 상속되는 정보를 제공하는 객체를 프로토타입(prototype)
  • 자바스크립트에서는 객체 이니셜라이저를 사용해 생성된 같은 타입의 객체들은 모두 같은 프로토타입
  • 또한, new 연산자를 사용해 생성한 객체는 생성자의 프로토타입을 자신의 프로토타입으로 상속
let obj = new Object(); // 이 객체의 프로토타입은 Object.prototype
let arr = new Array();  // 이 객체의 프로토타입은 Array.prototype
let date = new Date();  // 이 객체의 프로토타입은 Date.prototype
  • 하지만 Object.prototype 객체는 어떠한 프로토타입도 가지지 않으며, 아무런 프로퍼티도 상속받지 않음
  • 또한, 자바스크립트에 내장된 모든 생성자나 사용자 정의 생성자는 바로 이 객체를 프로토타입으로 가짐

프로토타입 체인(prototype chain)

  • 프로토타입이 상속되는 가상의 연결 고리
  • Object.prototype 객체는 이러한 프로토타입 체인에서도 가장 상위에 존재하는 프로토타입
  • 자바스크립트의 모든 객체는 Object.prototype 객체를 프로토타입으로 상속
let date = new Date(); // 이 객체는 Date.prototype 뿐만 아니라 Object.prototype도 프로토타입으로 가짐.

프로토타입의 생성

  • 객체 생성자 함수(object constructor function)를 작성
  • 생성자 함수를 작성하고 new 연산자를 사용해 객체를 생성하면, 같은 프로토타입을 가지는 객체들을 생성 가능
function Dog(color, name, age) { // 개에 관한 생성자 함수를 작성함.
    this.color = color;          // 색에 관한 프로퍼티
    this.name = name;            // 이름에 관한 프로퍼티
    this.age = age;              // 나이에 관한 프로퍼티
}

let myDog = new Dog("누런색", "누렁이", 1); // 이 객체는 Dog라는 프로토타입을 가짐.

document.write("우리 집 강아지는 " + myDog.name + "라는 이름의 " + myDog.color + "을 가진 강아지");
  • 객체 생성자 함수를 작성할 때에는 관례상 이름의 첫 문자만을 대문자로 작성
  • 객체에 프로퍼티 및 메서드 추가
function Dog(color, name, age) {
    this.color = color;
    this.name = name;
    this.age = age;
}

let myDog = new Dog("누런색", "누렁이", 12);

myDog.family = "시고르자브종"; // 품종에 관한 프로퍼티를 추가함.

myDog.breed = function() {        // 털색을 포함한 품종을 반환해 주는 메서드를 추가함.
    return this.color + " " + this.family;
}

document.write("우리 집 강아지는 " + myDog.breed() + "");
  • 위의 에서 새롭게 추가된 weight 프로퍼티와 breed() 메서드는 오직 myDog 인스턴스에만 추가
  • 이미 생성된 다른 Dog 객체나 차후에 생성되는 어떠한 다른 Dog 객체에도 추가되지 않음

프로토타입에 프로퍼티 및 메서드 추가

프로토타입의 경우에는 생성자 함수에 직접 추가해야만 이후에 생성되는 모든 다른 객체에도 적용 가능

function Dog(color, name, age) {
    this.color = color;
    this.name = name;
    this.age = age;
    this.family = "시고르자브종"; // 프로토타입에 프로퍼티를 추가할 때에는 기본값을 가지게 할 수 있음.

    this.breed = function() {
        return this.color + " " + this.family;
    };
}

let myDog = new Dog("흰색", "흰둥이", 1);
let hisDog = new Dog("갈색", "갈뱅이", 3);
document.write("우리 집 강아지는 " + myDog.family + "이고, 친구네 집 강아지도 " + hisDog.family + "");

Prototype 프로퍼티

Prototype 프로퍼티를 이용하면 현재 존재하고 있는 프로토타입에 새로운 프로퍼티나 메서드를 손쉽게 추가 가능

function Dog(color, name, age) {
    this.color = color;
    this.name = name;
    this.age = age;
}
// 현재 존재하고 있는 Dog 프로토타입에 family 프로퍼티를 추가함.
Dog.prototype.family = "시고르자브종";

// 현재 존재하고 있는 Dog 프로토타입에 breed 메서드를 추가함.
Dog.prototype.breed = function() {
    return this.color + " " + this.family;
};

let myDog = new Dog("흰색", "흰둥이", 1);
let hisDog = new Dog("갈색", "갈뱅이", 3);

document.write("우리 집 강아지는 " + myDog.family + "이고, 친구네 집 강아지도 " + hisDog.family + "");
document.write("우리 집 강아지의 품종은 " + myDog.breed() + "<br>");
document.write("친구네 집 강아지의 품종은 " + hisDog.breed() + "");
  • 직접 생성한 프로토타입은 위와 같이 새로운 프로퍼티나 메서드를 마음껏 추가하거나 삭제 가능
  • 물론 자바스크립트 표준 객체의 프로토타입도 임의로 수정할 수 있으나, 심각한 오류가 발생할 가능성이 있음
  • 따라서 자바스크립트 표준 객체의 프로토타입은 수정 X

객체 다루기

this 키워드

  • 해당 키워드가 사용된 자바스크립트 코드 영역을 포함하고 있는 객체
  • 메서드 내부에서 사용된 this 키워드는 해당 메서드를 포함하고 있는 객체!
  • 또한, 객체 내부에서 사용된 this 키워드는 객체 그 자신!
  • 이러한 this는 변수가 아닌 키워드이므로, 사용자가 임의로 가리키는 값 변경 불가!!
  • 객체 생성자 함수 내부에서 사용된 this 키워드는 어떠한 값도 가지지 않으며, 단순히 새로운 객체로 대체

delete 키워드

  • 객체의 프로퍼티를 삭제 가능
  • delete 키워드를 사용하여 프로퍼티를 삭제하면, 프로퍼티의 값뿐만 아니라 프로퍼티 그 자체도 삭제
  • 본래 객체의 프로퍼티만을 삭제하기 위해 만들어졌기 때문에 함수나 변수에 적용 불가
delete 객체이름.프로퍼티이름;
function Dog(color, name, age) {
    this.color = color;
    this.name = name;
    this.age = age;
}

let myDog = new Dog("흰색", "마루", 1);

delete myDog.age; // age 프로퍼티를 삭제함.

// age 프로퍼티가 삭제되었기 때문에 undefined를 출력함.

document.write("우리집 강아지의 나이는 " + myDog.age + "입니다.");
  • 직접 생성한 프로토타입은 위와 같이 새로운 프로퍼티나 메서드를 마음껏 추가하거나 삭제 가능
  • 자바스크립트 표준 객체의 프로토타입도 임의로 수정할 수 있으나, 심각한 오류가 발생을 일으킴.

객체 프로퍼티의 순회

  • 자바스크립트에서는 for / in 문을 사용하여 객체의 모든 프로퍼티를 반복 가능
  • for / in 문은 객체의 모든 열거할 수 있는 프로퍼티(enumerable properties)를 손쉽게 순회
  • 객체의 프로퍼티를 순회하는 방법으로는 for / in 문 이외에도 다음과 같은 메서드를 사용 가능

Object.keys()

메서드는 해당 객체가 가진 고유 프로퍼티 중에서 열거할 수 있는 프로퍼티의 이름을 배열에 담아 반환


Object.getOwnPropertyNames()

메서드는 해당 객체가 가진 모든 고유 프로퍼티의 이름을 배열에 담아 반환

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

let myDog = new Dog("흰색", "마루", 1);
// color 프로퍼티의 enumerable 속성을 false로 설정함.

Object.defineProperty(myDog, 'color', {enumerable : false} );
// 객체가 가진 고유 프로퍼티 중에서 열거할 수 있는 프로퍼티 이름을 배열에 담아 반환

document.write(Object.keys(myDog) + "<br>");       // name, age
// 객체가 가진 모든 고유 프로퍼티의 이름을 배열에 담아 반환

document.write(Object.getOwnPropertyNames(myDog)); // color, name, age

Object.defineProperty() //메서드는 ECMAScript 5부터 추가된 객체에 프로퍼티를 추가해 주는 메서드
// 이때 추가하는 프로퍼티의 속성까지도 설정 할 수 있다.

객체 간의 비교 : 자바스크립트에서 별개의 두 객체는 프로퍼티의 값이 모두 같아도, 절대로 같다고 말할 수 없습니다.

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

let myDog = new Dog("흰색", "마루", 1);
let hisDog = new Dog("흰색", "마루", 1);      // 모든 프로퍼티의 값이 모두 같은 객체를 생성함.

document.write((myDog == hisDog) + "<br>");   // false
document.write((myDog === hisDog) + "<br>");  // false

let herDog = hisDog;                          // hisDog 객체를 변수 herDog에 대입함.

document.write((hisDog == herDog) + "<br>");  // true
document.write((hisDog === herDog) + "<br>"); // true
  • 위의 코드에서 myDog과 hisDog 객체는 가지고 있는 프로퍼티의 값이 모두 동일
  • 하지만 이 두 객체는 별개의 객체이므로, 동등(==) 연산자와 일치(===) 연산자로 비교해도 모두 false를 반환
  • 위의 에서는 변수 herDog에 hisDog 객체를 대입
  • 이렇게 객체를 대입한 변수를 객체 레퍼런스(object reference)라고 하며, 이제부터 변수 herDog은 hisDog 객체를 가리킴
  • 객체 레퍼런스는 객체 자체를 저장하는 것이 아니라, 객체가 위치한 주소를 저장하기 때문에, 변수 herDog과 hisDog을 동등 연산자와 일치 연산자로 비교하면, 모두 true를 반환

객체 프로퍼티(property)

  • 모든 자바스크립트 객체는 Object 객체와 Object.prototype 객체의 모든 프로퍼티를 상속
  • prototype 프로퍼티를 이용하면 현재 존재하는 프로토타입에 새로운 프로퍼티나 메서드를 손쉽게 추가

객체 메서드(method)

모든 자바스크립트 객체는 Object 객체와 Object.prototype 객체의 모든 프로퍼티와 메서드를 상속

hasOwnProperty()

  • 특정 프로퍼티가 해당 객체에 존재하는지를 검사
  • 해당 객체에서 직접 선언된 프로퍼티만을 검사하며, 같은 이름의 프로퍼티라도 상속받은 프로퍼티는 false 값을 반환
function Dog(color, name, age, family) {
    this.color = color;
    this.name = name;
    this.age = age;
    this.family = family;

    this.breed = function() {
        return this.color + " " + this.family;
    }
}

let myDog = new Dog("검정색", "곰", 3, "불독");

myDog.hasOwnProperty("color"); // true
myDog.hasOwnProperty("breed"); // true
myDog.hasOwnProperty("class"); // 상속받은 프로퍼티이므로, false를 반환

propertyIsEnumerable()

  • 특정 프로퍼티가 해당 객체에 존재하고, 열거할 수 있는 프로퍼티인지를 검사
  • hasOwnProperty() 메서드의 결과가 true이면서, 동시에 열거할 수 있는 프로퍼티인지를 검사
function Dog(color, name, age) {
    this.color = color;
    this.name = name;
    this.age = age;
}

let myDog = new Dog("흰색", "마루", 1);


// color 프로퍼티의 enumerable 속성을 false로 설정함.
Object.defineProperty(myDog, 'color', { enumerable : false} );


document.write(myDog.propertyIsEnumerable("color") + "<br>"); // false
document.write(myDog.propertyIsEnumerable("name") + "<br>");  // true
document.write(myDog.propertyIsEnumerable("age"));            // true

열거할 수 있는 프로퍼티

  • 내부적으로 enumerable 플래그가 true로 설정된 프로퍼티
  • 이러한 프로퍼티들은 for / in 문으로 접근 가능
  • 이때 추가하는 프로퍼티의 속성까지도 설정 할 수 있음.

isPrototypeOf()

특정 객체의 프로토타입 체인에 현재 객체가 존재하는지를 검사

let day = new Date(); // Date 객체를 생성함.

// 객체 day의 프로토타입이 Date.prototype인지를 검사함.
document.write(Date.prototype.isPrototypeOf(day));          // true

document.write(Date.prototype.isPrototypeOf(new String())); // false

isExtensible()

  • 객체에 새로운 프로퍼티를 추가할 수 있는지 여부를 반환
  • 자바스크립트에서 모든 객체는 기본적으로 새로운 프로퍼티를 추가 가능
  • 하지만 preventExtensions() 메서드를 사용하여 해당 객체에 새로운 프로퍼티를 추가할 수 없도록 설정 할 수 있음.
let day = new Date(); // Date 객체를 생성함.
// 객체 day에 새로운 프로퍼티를 추가할 수 있는지 검사함.

document.write(Object.isExtensible(day) + "<br>"); // true
// 해당 객체에 새로운 프로퍼티를 추가할 수 없도록 설정함.

let myDay = Object.preventExtensions(day);
document.write(Object.isExtensible(day));          // false

toString()

이 메서드를 호출한 객체의 값을 문자열로 반환

let arr = [10, "문자열", true]; // 배열
let bool = false;               // 불리언
function func() { return 0; }   // 함수

arr.toString();  // 10, 문자열, true
bool.toString(); // false
func.toString(); // 함수의 소스 코드가 전부 문자열로 반환됨.

valueOf()

  • 특정 객체의 원시 타입(primitive type)의 값을 반환
  • 자바스크립트에서는 원시 타입의 값이 기대되는 곳에 객체가 사용되면, 내부적으로 이 메서드를 호출하여 처리
  • 만약 어떤 객체가 원시 타입의 값을 가지고 있지 않다면, 객체 자신을 반환
function func(n) {
    this.number = n;
}

myFunc = new func(4);
document.write(myFunc + 5); // ① : [object Object]5

func.prototype.valueOf = function() { // valueOf() 메서드를 정의함.
    return this.number;
}

document.write(myFunc + 5); // ② : 9
  • 위의  ① 부분에서는 산술 연산을 위해 number 타입의 값을 기대하는 곳에 myFunc 객체가 사용
  • 자바스크립트는 내부적으로 해당 객체의 valueOf() 메서드를 호출
  • 하지만 이 객체의 valueOf() 메서드는 아직 정의되지 않았으므로, 해당 객체 자신을 반환
  • 산술 연산이 아닌 문자열 결합 연산이 수행
  • 그 후에 prototype 프로퍼티를 이용하여 valueOf() 메서드를 정의
  • 따라서 ② 부분에서는 내부적으로 호출된 valueOf() 메서드가 해당 객체의 number 프로퍼티 값을 반환하고, 정상적으로 산술 연산 수행

getter와 setter

접근자 프로퍼티라고 부릅니다.
getter : 특정 프로퍼티의 값을 받아오기 위한 메서드
setter : 특정 프로퍼티의 값을 설정하기 위한 메서드

let gildong = { age: 18 };
document.write(gildong.age + "<br>"); // 18

Object.defineProperty(gildong, "americanAge", { get: function() { return this.age - 1; } });
document.write(gildong.americanAge); // 17
  • 위의 에서는 gildong 객체에 americanAge라는 프로퍼티를 추가할 때 get 키워드를 사용하여 getter 메서드를 정의
  • 따라서 해당 프로퍼티를 참조하려고 할 때는 내부적으로 미리 정의한 getter 메서드가 자동으로 호출될 것
let gildong = { age: 18 };
gildong.age = 20;

document.write(gildong.age + "<br>"); // 20

Object.defineProperty(gildong, "changeAge", { set: function(n) { this.age = this.age - n; } });
gildong.changeAge = 5;

document.write(gildong.age); // 15
  • 위의 에서는 gildong 객체에 changeAge라는 프로퍼티를 추가할 때 set 키워드를 사용하여 setter 메서드를 정의
  • 따라서 해당 프로퍼티의 값을 변경하려고 할 때는 내부적으로 미리 정의한 setter 메서드가 자동으로 호출

정리하다 보니 객체가 생각보다 양이 많다.. ㄷㄷㄷ

다음시간엔 객체(3)으로 전역객체 / 래퍼객체 / 표준 객체에 대해 정리해 보겠다!

객체의 전반적인 기본 개념을 보시려면 "객체(1)" ← ← 포스팅을 참고해 주세요!!

 

끝!

Reference

https://www.tcpschool.com/javascript/js_object_prototype

 

728x90
반응형