[JS] 객체 지향

day024·2024년 11월 13일

HTML&CSS&JS

목록 보기
10/15

생활코딩 - 자바스크립트(JavaScript) 기본

생활코딩-자바스크립트-객체지향
위 강의를 듣고 정리한 글입니다.


17.객체지향 프로그래밍 소개

17.1 객체지향 프로그래밍 소개

객체지향 프로그래밍(Object-Oriented Programming)은 좀 더 나은 프로그램을 만들기 위한 프로그래밍 패러다임으로 로직을 상태(state)와 행위(behave)로 이루어진 객체로 만드는 것이다.

객체는 변수와 메소드를 그룹핑한 것이다.

17.2 추상화

추상화 : 특정 기능을 하는 그룹의 공통된 기능(프로퍼티와 메서드)을 정의하는 작업을 말한다.

JS 추상화, 캡슐화

17.3 부품화

메소드는 부품화의 예라고 할 수 있다. 연관되어 있는 로직들을 결합해서 메소드라는 완제품을 만드는 것이다.
그리고 이 메소드들을 부품으로 해서 하나의 완제품인 독립된 프로그램을 만드는 것이다. 메소드를 사용하면 코드의 양을 극적으로 줄일 수 있고, 메소드 별로 기능이 분류되어 있기 때문에 필요한 코드를 찾기도 쉽고 문제의 진단도 빨라진다.

객체 지향 프로그래밍이다 핵심은 연관된 메소드와 그 메소드가 사용하는 변수들을 분류하고 그룹핑하는 것이다.
바로 그렇게 그룹핑 한 대상이 객체(Object)다.
비유하자면 파일과 디렉토리가 있을 때 메소드나 변수가 파일이라면 이 파일을 그룹핑하는 디렉토리가 객체라고 할 수 있다. 이를 통해서 더 큰 단위의 부품을 만들 수 있게 되었다.

은닉화, 캡슐화 인터페이스

은닉화, 캡슐화
즉 내부의 동작 방법을 단단한 케이스 안으로 숨기고 사용자에게는 그 부품의 사용방법만을 노출하고 있는 것이다.
이러한 컨셉을 정보의 은닉화(Information Hiding), 또는 캡슐화(Encapsulation)라고 부른다.

인터페이스
잘 만들어진 부품이라면 부품과 부품을 서로 교환 할 수 있어야 한다.

각각의 부품은 미리 정해진 약속에 따라서 신호를 입, 출력하고, 연결점의 모양을 표준에 맞게 만들면 된다. 이러한 연결점을 인터페이스(interface)라고 한다.
인터페이스란 이질적인 것들이 결합하는 것을 막아주는 역할도 하는 것이다. 즉 인터페이스는 부품들 간의 약속이다.


18. 생성자와 new

18.1 소개& 객체 생성

객체는 서로 연관된 변수와 함수를 그룹핑한 그릇, 객체 내의 변수를 프로퍼티(property) 함수를 메소드(method)라고 한다.

var person = {}
person.name = 'egoing';
person.introduce = function(){
    return 'My name is '+this.name;
}
document.write(person.introduce());

객체를 만드는 과정에 분산되어 있다. 객체를 정의 할 때 값을 셋팅하도록 코드를 바꿔보자.

var person = {
    'name' : 'egoing',
    'introduce' : function(){
        return 'My name is '+this.name;
    }
}
document.write(person.introduce());

만약 다른 사람의 이름을 담을 객체가 필요하다면 객체의 정의를 반복해야 할 것이다. 객체의 구조를 재활용할 수 있는 방법이 필요하다. 이 때 사용하는 것이 생성자다.

18.2 생성자

생성자(constructor)는 객체를 만드는 역할을 하는 함수다.
자바스크립트에서 함수는 재사용 가능한 로직의 묶음이 아니라 객체를 만드는 창조자이다.

function Person(){} 
var p = new Person();
p.name = 'egoing';
p.introduce = function(){
    return 'My name is '+this.name; 
}
document.write(p.introduce());

함수를 호출할 때 new을 붙이면 새로운 객체를 만든 후에 이를 리턴한다.

function Person(){}
var p1 = new Person();
p1.name = 'egoing';
p1.introduce = function(){
    return 'My name is '+this.name; 
}
document.write(p1.introduce()+"<br />");
 
var p2 = new Person();
p2.name = 'leezche';
p2.introduce = function(){
    return 'My name is '+this.name; 
}
document.write(p2.introduce());
function Person(name){
    this.name = name;
    this.introduce = function(){
        return 'My name is '+this.name; 
    }   
}
var p1 = new Person('egoing');
document.write(p1.introduce()+"<br />");
 
var p2 = new Person('leezche');
document.write(p2.introduce());

초기화 : 생성자 내에서 이 객체의 프로퍼티를 정의,
이를 통해서 코드의 재사용성이 높아진다.

생성자 함수는 일반함수와 구분하기 위해서 첫글자를 대문자로 표시한다.

자바스크립트 생성자의 특징
일반적인 객체지향 언어에서 생성자는 클래스의 소속이다. 하지만 자바스크립트에서 객체를 만드는 주체는 함수다.
함수에 new를 붙이는 것을 통해서 객체를 만들 수 있다는 점은 자바스크립트에서 함수의 위상을 암시하는 단서이면서 또 자바스크립트가 추구하는 자유로움을 보여주는 사례라고 할 수 있다.


19.전역객체

전역객체(Global object)는 특수한 객체다.
모든 객체는 이 전역객체의 속성(프로퍼티)이다.

function func(){
    alert('Hello?');    
}
func();
window.func();

func();와 window.func();는 모두 실행이 된다.
모든 전역변수와 함수는 사실 window 객체의 프로퍼티다.
객체를 명시하지 않으면 암시적으로 window의 프로퍼티로 간주된다.

var o = {'func':function(){
    alert('Hello?');
}}
o.func();
window.o.func();

전역객체 API
ECMAScript에서는 전역객체의 API를 정의해두었다.
그 외의 API는 호스트 환경에서 필요에 따라서 추가로 정의하고 있다.
이를테면 웹브라우저 자바스크립트에서는 alert()이라는 전역객체의 메소드가 존재하지만 node.js에는 존재하지 않는다.
또한 전역객체의 이름도 호스트환경에 따라서 다른데, 웹브라우저에서 전역객체는 window이지만 node.js에서는 global이다.

20. this

20.1 함수와 this

this는 함수 내에서 함수 호출 맥락(context)를 의미한다. 즉 함수를 어떻게 호출하느냐에 따라서 this가 가리키는 대상이 달라진다.
함수와 객체의 관계가 느슨한 자바스크립트에서 this는 이 둘을 연결시켜주는 실질적인 연결점의 역할을 한다.

함수호출
this는 전역객체인 window와 같다.

function func(){
    if(window === this){
        document.write("window === this");
    }
}
func();
window === this

20.2 메소드와 this

매소드의 호출 : 객체의 소속인 메소드의 this는 그 객체를 가르킨다.

var o = {
    func : function(){
        if(o === this){
            document.write("o === this");
        }
    }
}
o.func();   
o === this

o.func()
(window).func() 이 메소드 안에서 this는 window를 의미함

20.3 생성자와 this

생성자의 호출

var funcThis = null; 
 
function Func(){
    funcThis = this; // 생성된 객체를 가르킴 
}
var o1 = Func();
if(funcThis === window){ // 함수를 통하면 window를 가르킴
    document.write('window <br />');
}
 
var o2 = new Func();
if(funcThis === o2){
    document.write('o2 <br />');
}
window 
o2

생성자는 빈 객체를 만든다. 그리고 이 객체내에서 this는 만들어진 객체를 가르킨다.
생성자가 실행되기 전까지는 객체는 변수에도 할당될 수 없기 때문에 this가 아니면 객체에 대한 어떠한 작업을 할 수 없다.

function Func(){
    document.write(o);
}
var o = new Func();
undefined

20.4 객체로서의 함수 & apply 와 this

리터럴은 데이터(값) 그 자체를 뜻한다. 즉, 변수에 넣는 변하지 않는 데이터를 의미하는 것.
코드 상에서데이터를 표현하는 방식 을 리터럴이라 하고, 객체 지향언어에서는 객체의 리터럴 표기법을 지원한다.
리터럴(Literal)이란?

함수 리터럴 (literal)

function sum(x,y){return x+y} 

객체 리터럴

var o = {} // new object 

배열 리터럴

var a = [1,2,3] // new Array[1,2,3] 

함수의 메소드인 apply, call을 이용하면 this의 값을 제어할 수 있다.

var o = {}
var p = {}
function func(){
    switch(this){
        case o:
            document.write('o<br />');
            break;
        case p:
            document.write('p<br />');
            break;
        case window:
            document.write('window<br />');
            break;          
    }
}
func();
func.apply(o);
func.apply(p);

결과

window
o
p


21. 상속

21.1 상속(inheritance)이란?

상속은 객체의 로직을 그대로 물려 받는 또 다른 객체를 만들 수 있는 기능을 의미한다.
기존의 로직을 수정하고 변경해서 파생된 새로운 객체를 만들 수 있게 해준다.

function Person(name){
    this.name = name;
    this.introduce = function(){
        return 'My name is '+this.name; 
    }   
}
var p1 = new Person('egoing');
document.write(p1.introduce()+"<br />");

결과

My name is egoing
function Person(name){
    this.name = name;
}
Person.prototype.name=null;
Person.prototype.introduce = function(){
    return 'My name is '+this.name; 
}
var p1 = new Person('egoing');
document.write(p1.introduce()+"<br />");

하지만 상속을 위한 기본적인 준비가 되었다.

21.2 상속의 사용법

function Person(name){
    this.name = name;
}
Person.prototype.name=null;
Person.prototype.introduce = function(){
    return 'My name is '+this.name; 
}
 
function Programmer(name){
    this.name = name;
}
Programmer.prototype = new Person();
 
var p1 = new Programmer('egoing');
document.write(p1.introduce()+"<br />");

Programmer이라는 생성자를 만들었다.
그리고 이 생성자의 prototype과 Person의 객체를 연결했더니 Programmer 객체도 메소드 introduce를 사용할 수 있게 되었다.

Programmer가 Person의 기능을 상속하고 있는 것이다.
부모의 기능을 계승 발전할 수 있는 것이 상속의 가치다.

21.3 기능의 추가

function Person(name){
    this.name = name;
}
Person.prototype.name=null;
Person.prototype.introduce = function(){
    return 'My name is '+this.name; 
}
 
function Programmer(name){
    this.name = name;
}
Programmer.prototype = new Person();
Programmer.prototype.coding = function(){
    return "hello world";
}
 
var p1 = new Programmer('egoing');
document.write(p1.introduce()+"<br />");
document.write(p1.coding()+"<br />");
My name is egoing
hello world

Programmer는 Person의 기능을 가지고 있으면서 Person이 가지고 있지 않은 기능인 메소드 coding을 가지고 있다.

21.4 prototype

클래스 기반 언어에서는 클래스 내부에 모든 속성과 메소드가 정의되어있다.
해당 클래스를 기반으로한 객체가 인스턴스로 생성되면 이 객체는 클래스 내부에 정의되어있는 속성과 메소드에 접근하여 사용할 수 있는 형태이다.
[Javascript] Prototype 기본 이해하기

prototype은 말 그대로 객체의 원형이라고 할 수 있다. 함수는 객체다. 그러므로 생성자로 사용될 함수도 객체다
객체는 프로퍼티를 가질 수 있는데 prototype이라는 프로퍼티는 그 용도가 약속되어 있는 특수한 프로퍼티다.
prototype에 저장된 속성들은 생성자를 통해서 객체가 만들어질 때 그 객체에 연결된다.

function Ultra(){}
Ultra.prototype.ultraProp = true;
 
function Super(){}
Super.prototype = new Ultra();
 
function Sub(){}
Sub.prototype = new Super();
 
var o = new Sub();
console.log(o.ultraProp);

결과는 true다.
위 예시 코드는 프로토타입 체인

프로토타입 체인: 프로토타입 객체도 또 다시 상위 프로토타입 객체로부터 상속받을 수 있고 그 상위도 마찬가지인데 이를 프로토타입 체인 이라고 한다.
[Javascript] Prototype 기본 이해하기

생성자 Sub를 통해서 만들어진 객체 o가 Ultra의 프로퍼티 ultraProp에 접근 가능한 것은 prototype 체인으로 Sub와 Ultra가 연결되어 있기 때문이다. 내부적으로는 아래와 같은 일이 일어난다.

function Ultra(){}
Ultra.prototype.ultraProp = true;
 
function Super(){}
var t = new Ultra(); 
sub.prototype = t;
 
function Sub(){}
Sub.prototype = new Super();
var s = new Super();
sub.prototype = s;

var o = new Sub();

console.log(o.ultraProp);

객체 o에서 ultraProp를 찾는다.
없다면 Sub.prototype.ultraProp를 찾는다.
없다면 Super.prototype.ultraProp를 찾는다.
없다면 Ultra.prototype.ultraProp를 찾는다.
prototype는 객체와 객체를 연결하는 체인의 역할을 하는 것이다. 이러한 관계를 prototype chain이라고 한다.

Super.prototype = Ultra.prototype 으로하면 안된다. 이렇게하면 Super.prototype의 값을 변경하면 그것이 Ultra.prototype도 변경하기 때문이다. Super.prototype = new Ultra();는 Ultra.prototype의 원형으로 하는 객체가 생성되기 때문에 new Ultra()를 통해서 만들어진 객체에 변화가 생겨도 Ultra.prototype의 객체에는 영향을 주지 않는다.


22.표준 내장객체의 확장

22.1 표준 내장 객체란?

표준 내장 객체(Standard Built-in Object)는 자바스크립트가 기본적으로 가지고 있는 객체들을 의미한다.

자바스크립트는 아래와 같은 내장 객체를 가지고 있다.

Object
Function
Array
String
Boolean
Number
Math
Date
RegExp

22.2 배열의 확장

배열을 확장해보자.
아래 코드는 배열에서 특정한 값을 랜덤하게 추출하는 코드다.

var arr = new Array('seoul','new york','ladarkh','pusan', 'Tsukuba');
function getRandomValueFromArray(haystack){
    var index = Math.floor(haystack.length*Math.random());
    return haystack[index]; 
}
console.log(getRandomValueFromArray(arr));

조금 더 세련된 방법은 이 함수를 배열 객체에 포함시키는 것이다. 배열에 내장된 메소드인 것처럼 위의 기능을 사용할 수 있다.

Array.prototype.rand = function(){
    var index = Math.floor(this.length*Math.random());
    return this[index];
}
var arr = new Array('seoul','new york','ladarkh','pusan', 'Tsukuba');
console.log(arr.rand());

23. Object

23.1 Object란

Object 객체는 객체의 가장 기본적인 형태를 가지고 있는 객체이다. 아무것도 상속받지 않는 순수한 객체다.

자바스크립트에서는 값을 저장하는 기본적인 단위로 Object를 사용한다.

object가 갖고있는 프로포티는 모든 객체가 상속받는다.

var grades = {'egoing': 10, 'k8805': 6, 'sorialgi': 80};

동시에 자바스크립트의 모든 객체는 Object 객체를 상속 받는데, 그런 이유로 모든 객체는 Object 객체의 프로퍼티를 가지고 있다.

23.2 Object API & Object 확장

Object API

<!DOCTPYE html>
<html>
<head> 
  	<title></title>
</head>
<body>
<script type ="text/javascript">
  //object.keys()
  var arr = ["a","b","c"];
console.log('Object.keys(arr)', Object.keys(arr));
//"0,1,2"

//Object.prototype.toSting
var o = new Object();
console.log('o.toString()', o.toString());

var a = new Array(1,2,3);
console.log('a.toString()', a.toString());
 </body>

Object 객체를 확장하면 모든 객체가 접근할 수 있는 API를 만들 수 있다.

Object.prototype.contain = function(neddle) {
    for(var name in this){
        if(this[name] === neddle){
            return true;
        }
    }
    return false;
}
var o = {'name':'egoing', 'city':'seoul'}
console.log(o.contain('egoing'));
var a = ['egoing','leezche','grapittie'];
console.log(a.contain('leezche'));

Object 객체는 모든 객체에 영향을 주기 때문에 확장하지 않는 것이 권장된다.

for(var name in o){
    console.log(name);  
}

결과

name
contain

확장한 프로퍼티인 contain이 포함되어 있다. 객체가 기본적으로 가지고 있을 것으로 예상하고 있는 객체 외에 다른 객체를 가지고 있는 것은 개발자들에게 혼란을 준다.

이 문제를 회피하기 위해서는 프로퍼티의 해당 객체의 소속인지를 체크해볼 수 있는 hasOwnProperty를 사용하면 된다.

for(var name in o){
    if(o.hasOwnProperty(name))
        console.log(name);  
}

hasOwnProperty는 인자로 전달된 속성의 이름이 객체의 속성인지 여부를 판단한다.
만약 prototype으로 상속 받은 객체라면 false가 된다.


24. 데이터 타입

24.1 원시 데이터 타입과 객체

데이터 타입이란 데이터의 형태를 의미한다.
객체가 아닌 데이터 타입을 원시 데이터 타입(primitive type)이라고 한다.

  • 숫자
  • 문자열
  • boolean(true/false)
  • null
  • undefined

그 외의 모든 데이터 타입들은 객체다.

24.2 래퍼객체

var str = 'coding';
console.log(str.length);        // 6
console.log(str.charAt(0));     // "C"

문자열은 분명히 프로퍼티와 메소드가 있지만 객체가 아니다.

내부적으로 문자열이 원시 데이터 타입이고 문자열과 관련된 어떤 작업을 하려고 할 때 자바스크립트는 임시로 문자열 객체를 만들고 사용이 끝나면 제거하기 때문이다.

var str = 'coding';
str.prop = 'everybody';
console.log(str.prop);      // undefined

str.prop를 하는 순간에 자바스크립트 내부적으로 String 객체가 만들어진다. prop 프로퍼티는 이 객체에 저장되고 이 객체는 곧 제거 된다.
그렇기 때문에 prop라는 속성이 저장된 객체는 존재하지 않게된다. 이러한 특징은 일반적인 객체의 동작 방법과는 다르다.

문자열과 관련해서 필요한 기능성을 객체지향적으로 제공해야 하는 필요 또한 있기 때문에 원시 데이터 형을 객체처럼 다룰 수 있도록 하기 위한 객체를 자바스크립트는 제공하고 있는데 그것이 레퍼객체(wrapper object)다.

레퍼객체로는 String, Number, Boolean이 있다.
null과 undefined는 레퍼 객체가 존재하지 않는다.

25. 참조

25.1 복제

전자화된 시스템의 가장 중요한 특징은 복제다.

var a = 1;
var b = a;
b = 2;
console.log(a); // 1

값을 변경한 것은 변수 b이기 때문에 변수 a에 담겨있는 값은 그대로이다.
변수 b의 값에 변수 a의 값이 복제된 것이다.

25.2 참조와 변수

var a = {'id':1};
var b = a;
b.id = 2;
console.log(a.id);  // 결과 : 2
b.id = 2;
System.out.println(a.id);   

변수 b에 담긴 객체의 id 값을 2로 변경하면 a.id의 값도 2가 된다.
이것은 변수 b와 변수 a에 담긴 객체가 서로 같다는 것을 의미하다.
이것이 바로 참조이다.(reference)

프로그래밍에서 광범위하게 사용하는 라이브러리라는 개념도 일종의 참조라고 할 수 있다.
공용 라이브러리를 사용하게 되면 하나의 라이브러리를 여러 애플리케이션에서 공유해서 사용하게 된다.
라이브러리의 내용이 변경되면 이를 참조하고 있는 애플리케이션에도 내용이 반영되게 된다.
또 우리가 변수를 사용하는 이유도 말하자면 참조를 위해서라고 할 수 있을 것이다.

아래 두 개의 구문의 차이점을 생각해보자.

a = 1;

a = {'id':1};

무엇일까? 전자는 데이터형이 숫자이고 후자는 객체다.
숫자는 원시 데이터형(기본 데이터형, Primitive Data Types)이다. 자바스크립트에서는 원시 데이터형을 제외한 모든 데이터 타입은 객체이다.
객체를 다른 말로는 참조 데이터 형(참조 자료형)이라고도 부른다.
기본 데이터형은 위와 같이 복제 되지만 참조 데이터형은 참조된다. 모든 객체는 참조 데이터형이다.

정리하면 변수에 담겨있는 데이터가 원시형이면 그 안에는 실제 데이터가 들어있고, 객체면 변수 안에는 데이터에 대한 참조 방법이 들어있다고 할 수 있다.

25.3 함수와 참조

다음은 원시 데이터 타입을 인자로 넘겼을 때의 동작 모습이다.

복제

var a = 1;
function func(b){
    b = 2;
}
func(a);
console.log(a); //결과 1 

다음은 참조 데이터 타입을 인자로 넘겼을 때 동작하는 장면이다.

var a = {'id':1};
function func(b){
    b = {'id':2}; // 참조링크가 끊기게됨 
}
func(a);
console.log(a.id);  // 1

함수 func의 파라미터 b로 전달된 값은 객체 a이다.
(b = a) b를 새로운 객체로 대체하는 것은 (b = {'id':2}) b가 가르키는 객체를 변경하는 것이기 때문에 객체 a에 영향을 주지 않는다.

참조


var a = {'id':1};
function func(b){
    b.id = 2;
}
func(a);
console.log(a.id);  // 결과 2

파라미터 b는 객체 a의 레퍼런스다.
이 값의 속성을 바꾸면 그 속성이 소속된 객체를 대상으로 수정작업을 한 것이 되기 때문에 b의 변경은 a에도 영향을 미친다.

profile
개발하는 감자

0개의 댓글