Javascript #03 - 객체지향

dldzm·2021년 7월 19일
0

Javascript 기본

목록 보기
3/9

객체 지향 프로그래밍 - 기능 별로 로직을 구획화하는 것 : 객체 단위
재활용성을 높인다.

객체지향 프로그래밍

참고 - 객체지향 프로그래밍 개념

생성자와 new

javascript는 prototype-based programming이므로 여느 객체지향 프로그래밍과는 차이가 있다.

객체란 서로 연관된 변수와 함수를 그룹핑한 그릇이다.
객체 내에는

  • property : 객체 내의 변수
  • method : 객체 내의 함수
    가 있다.

복습 차원

var person = {}
person.name = 'ink';
person.introduce = function(){
  return "내 이름은 " + this.name + "이다.";
}

console.log(person.introduce());

또는,

var person = {
  'name' : 'ink',
  'introduce' : function(){
    return "내 이름은 " + this.name + "이다.";
  }
}

console.log(person.introduce());

생성자와 new

자바스크립트에서의 함수는 재사용 가능한 로직의 묶음이 아니라 객체를 만드는 창조자이다.

위와 같은 방식을 따른다면 다른 사람의 이름을 담은 객체가 필요하면 이러한 객체의 정의를 반복해야 한다.

constructor는 객체를 만드는 역할을 하는 함수이다.

function Person(name){
  this.name = name;
  this.introduce = function(){
    return "this is " + this.name;
  }
}

var p1 = new Person('egoing');
console.log(p1.introduce()+"<br />");
 
var p2 = new Person('leezche');
console.log(p2.introduce());

전역객체

전역 객체 : Global object는 특수한 객체로, 모든 객체는 이 전역 객체의 property이다.

function f(){
  console.log(13);
}

f();
window.f();

window는 객체다. window는 전역 객체다. 암시적이다.

var o = {'func' : function(){
    console.log(13);
}}

o.func();
window.o.func();

자바스크립트에서 모든 객체는 기본적으로 전역 객체의 프로퍼티이다.

this

this는 함수 호출 맥락(context)이다.

function f(){
  if (window === this){
    console.log("window === this");
  }
}
f();

메소드의 호출

var o = {
  f : function(){
    if(o === this){
      console.log(13);
    }
  }
}

o.f();

o라고 하는 변수에 객체를 선언한 것. 이 객체 안에는 f라는 메소드가 있고 f를 호출하면 객체를 담고 있는 변수 o와 this, 즉 function 메소드 안에 담겨 있는 값이 정확하게 같다면 console창에 13이 찍힌다.

o.f()를 호출하게 되면 this는 o이기 때문.

생성자의 호출

var funcThis = null;	//전역 변수로 선언하게 된 것
var funs = null;

function Func(){
  funcThis = this;
}

function Func2(){
  funs = this;
}

var o1 = Func();	//일반 함수로 부른 것
if(funcThis === window){
  console.log('window'+'<br/>');
}

var o2 = new Func2();	//생성자로 부른 것
if(funs === o2){
    document.write('o2'+'<br/>');
}

apply, call

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

sum이라고 하는 함수 객체를 만든 것. 함수 리터럴이라고 한다.

var o = {};

이와 같은 형식을 객체 리터럴이라고 한다. var o = new Object(); 과 같이 객체 생성자를 사용하여 선언할 수도 있다.

참고 - new Object의 문제점

같은 흐름으로 var a = [1,2,3];과 같이 배열 리터럴을 사용할 수도 있지만 var a = new Array(1,2,3);과 같이 객체를 명시적으로 만들 수도 있다.

var sum2 = new Function('x','y','return x+y;');
sum2(1,2);	//3

new를 통해 Function이라고 하는 생성자 함수를 호출한 것이다.

첫번째 인자로 x, 두번째 인자로 y를 넣어 입력 인자를 정의해주고 마지막 인자가 함수의 본문에 해당된다.

따라서, 객체는 객체의 프로퍼티를 가지고 있다는 것을 생각하고 접근하자. 함수가 가지는 프로퍼티에 접근하는데 apply, call method를 통해 접근할 수 있다.

callapply를 통해 this의 값을 제어할 수 있다.

var o = {}
var p = {}

function func(){
  switch(this){
      	//여기서의 this는 일반 변수가 아니라
      	//객체 자신을 가리키는 this이다.
      	//따라서 This라고 해버리면 window와 일치하게 되지 않는다. 
    case o : 
      console.log('o');
      break;
    case p : 
      console.log('p');
      break;
    case window : 
      console.log("window");
      break;
  }
}

func();		// window
func.apply(o);	// o
func.apply(p);	// p

결론 : 자바스크립트는 유연하다.

상속

상속하는 방법

1)

function Person(name){
  this.name = name;
  this.Introduce = function(){
    return "My name is "+this.name;
  }
}

var p1 = new Person('ink');
console.log(p1.Introduce());

2)

function Person(name){
  this.name = name;
}
Person.prototype.name = null;
Person.prototype.Introduce = function(){
  return "My name is "+this.name;
}

var p2 = new Person('Ariadne');
console.log(p2.Introduce());

prototype이라고 하는 property가 존재한다.

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();
var p3 = new Programmer('BMO');

console.log(p3.Introduce());

상속의 기능 추가

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 p4 = new Programmer('H');

console.log(p4.Coding());

prototype

상속의 구체적인 수단, prototype

prototype은 함수의 원형이다.
다음과 같은 코드는 prototype chain을 보여주기 위함이다.

function U(){
  U.prototype.uprop = true;
}

function S(){}
S.prototype = new U();

function B(){}
B.prototype = new S();

var o = new B();
console.log(o.uprop);	//true

생성자는 기본적으로 함수이다. 함수를 호출할 때, new를 붙이게 되면 단순한 함수가 아니라 생성자 함수가 된다. 이렇게 실행된 결과는 객체를 만들어서 리턴하기 때문에 변수 o안에는 생성자를 통해 만들어지는 객체가 들어간다.

생성자를 통해 만들어질 때, 생성자의 정보를 prototype에서 가져온다.


참고 1 - prototype

javascript는 class의 개념이 없어 기존의 객체를 복사하여 새로운 객체를 생성하는 prototype 기반 언어이다. 프로토타입 기반 언어는 객체의 원형인 프로토타입을 이용하여 새로운 객체를 만들어낸다.

프로토타입 객체는 새로운 객체가 생성되기 위한 원형이 되는 객체이다. 같은 원형으로 생성된 객체가 공통으로 참조하는 공간이다.

function Person(){}

var joon = new Person();
var jisoo = new Person();

Person.prototype.getType = function (){ 
    return "인간"; 
};

console.log(joon.getType());   // 인간
console.log(jisoo.getType());  // 인간

함수를 정의하면 다른 곳에서 생성되는 프로토타입 객체는 자신이 다른 객체의 원형이 되는 객체이다. 따라서 모든 객체는 프로토타입 객체에 접근할 수 있고 프로토타입 객체도 동적으로 런타임에 멤버를 추가할 수 있다.

joon과 jisoo에게 객체를 생성해주고 Person에 getType 함수를 뒤늦게 추가해줬음에도 불구하고 joon과 jisoo는 getType을 사용할 수 있다.


참고 2 - Prototype

생성자 함수에는 prototype에, 생성자로부터 만들어진 객체에는 __proto__에 생성자의 prototype이 들어간다.

표준 내장 객체의 확장

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

  • Object
  • Function
  • Array
  • String
  • Boolean
  • Number
  • Math
  • Date
  • RegExp

하지만 Javascript가 동작하는 호스트환경에서는 더 많은 기능(API)을 제공한다는 것을 잊지 말아야 한다.

<-> 사용자 정의 객체 : 위에서 제공하는 기능을 넘어 더 많은 기능을 만들고자 할 때 사용한다.

배열의 확장

다음은 C++ 스타일의 코드.

var arr = new Array('a','b','c','d','e','f','g');

function randomPickfromStack(stack){
  var index = Math.floor(stack.length*Math.random());
  return stack[index];
}

console.log(randomPickfromStack(arr));

다음은 확장된 스타일의 코드. randPick이라는 method가 Array에 소속되게끔 한다.

Array.prototype.randPick = function(){
  var index = Math.floor(this.length*Math.random());
  return this[index];
}

var arr = new Array('a','b','c','d','e','f','g');
console.log(arr.randPick());	//여기서 randPick의 this는 arr가 된다.

Object

Object 객체는 객체의 가장 기본적인 형태를 가지고 있는 객체이다.

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

MDN - JavaScript

MDN - Object.keys()

.keys() : 전달된 객체의 열거할 수 있는 모든 속성 이름들을 나타내는 문자열 배열

// 단순 배열
const arr = ['a', 'b', 'c'];
console.log(Object.keys(arr)); // console: ['0', '1', '2']

// 배열형 객체
const obj = { 0: 'a', 1: 'b', 2: 'c' };
console.log(Object.keys(obj)); // console: ['0', '1', '2']

// 키와 순서가 무작위인 배열형 객체
const anObj = { 100: 'a', 2: 'b', 7: 'c' };
console.log(Object.keys(anObj)); // console: ['2', '7', '100']

결국 알아야 하는 것은 Object.keys(), Object.prototype.toString()와 같이 어떨 때 어떻게 접근하는 것인지 알아야 한다.

  1. .prototype이 있는 것은 접근할 때, 다음과 같이 객체를 만든다.

    var o = new Object();

    그리고 객체를 담고 있는 식별자 o.toString()으로 접근하는 것이다.

  2. 없는 것에 접근할 때에는, Object.keys(입력인자)처럼 입력인자를 꼭 넣어줘야 한다. 여기서 Object는 생성자 함수이다. 함수는 자바스크립트에서 객체이므로 property를 가질 수 있기 때문이다.

Object의 확장

Object를 확장해서 모든 객체가 사용할 수 있는 function contain을 추가한 것.

Object.prototype.contain = function(needle){
  for (var name in this){
    if(this[name] == needle){
      return true;
    }
  }
  return false;
}

내가 이해한 바로는 다음과 같다.

c++에서는 클래스를 선언하고 클래스에 선언된 함수는 클래스 객체만 사용할 수 있다. 하지만 js에서는 모든 객체의 클래스가 Object이므로 전역 클래스처럼 Object가 동작한다. 따라서 Object.prototype으로 접근하면 모든 객체가 Object안에 정의되어 있는 함수와 객체를 사용할 수 있는 것이다.

하지만 확장을 하면 모든 객체에 영향을 미칠 수 있기 때문에 확장하지 않는 것이 바람직하다. 생각해보면 class에 정의된 method 함수를 class 객체만 사용할 수 있는 것은 접근을 제한하는 기능을 부여한 것이기 때문이다.

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

데이터 타입

  • 원시 데이터 타입 : 기본
    - 숫자
    • 문자열
    • 불리언(true/false)
    • null
    • undefined
  • 객체 데이터 타입 : 참조

원시 데이터 타입으로 생성된 것들은 (객체처럼 동작하지만 사용이 끝나면 내부적으로 이를 제거하기 때문에) 객체가 아니다.

profile
🛰️ 2021 fall ~

0개의 댓글