[OOP] OOP

트릴로니·2022년 8월 24일

자바스크립트

목록 보기
28/31
const elf = {
	name: 'Orwell',
    weapon: 'bow',
    acctack() {
    	return 'attack with' + elf.weapon
    }
}
elf.name
// 'Orwell'
elf.weapon
// 'attack with bow'

가정: elf라는 객체를 만들었는데 다른 name, 다른 weapon을 가지고 있는 객체를 만들고 싶다.

step1: factory function

  • factory 함수는 객체를 만들어 내는 공장같은 역할을 한다.
function createElf(name, weapon) {
	return {
    	name,
        weapon,
        attack() {
        	return 'attack with' + weapon
        }
    }
}

const peter = createElf('Peter', 'stones');
peter.attack();
// 'attack with stones'

const sam = createElf('Sam', 'fire');
sam.attack();
// 'attack with fire'

문제점

  • 만약 1000개의 객체를 createElf를 호출해서 만들 경우 메모리에 1000개의 객체가 생성된다.
  • name와 weapon은 객체마다 데이터가 다를 수 있으므로 메모리에 따로 할당되는 것이 맞다.
  • 그러나 attack 메소드의 경우 모든 객체마다 똑같다. 그러나 factory 함수로 객체를 만들경우 객체 안에 포함된 이 메소드가 매번 새로 생성이 된다.

해결방법

  • 메소드가 있는 객체를(elfFunctions) 따로 만들고 factory 함수로 객체(peter)를만든다.
  • peter객체의 attack에 elfFunction의 attack을 할당한다.
  • peter의 메소드 attack을 호출하면 attack메소드의 this는 peter를 가리킨다.(dynamic scope)
const elfFunctions = {
	attack() {
    	return 'attack with' + this.weapon
    }
}

function createElf(name, weapon) {
	return {
    	name,
        weapon,
    }
}

const peter = createElf('Peter', 'stones');
peter.attack = elfFunctions.attack
peter.attack();
// 'attack with stones';

step2: Object.create()

  • Object.create()는 프로토타입 체인을 만든다.
  • 프로토타입 상속받을 객체를 넣어준다.
  1. newElf은 elfFunctions의 프로토타입 상속을 받은 빈 객체
  2. name과 weapon 프로터티를 넣어준다.
  3. newElf는 프로토타입 체인을 타고 elfFunctions의 attack에 접근 가능한다.
const elfFunctions = {
	attack() {
    	return 'attack with' + this.weapon
    }
}

function createElf(name, weapon) {
	let newElf = Object.create(elfFunctions);
    newElf.name = name;
    newElft.weapon = weapon;
    return newElf;
}

const peter = createElf('Peter', 'stones');
peter.attack();
// 'attack with stones'

const sam = createElf('Sam', 'fire');
sam.attack();
// 'attack with fire'

step3: constructor function(생성자 함수)

function Elf(name, weapon) {
	this.name = name;
    this.weapon = weapon;
}

const peter = new Elf('Peter', 'stones');
// this는 peter
peter.attack();
// 'attack with stones'

const sam = new Elf('Sam', 'fire');
// this sam
sam.attack();
// 'attack with fire'
  • 생성자 함수는 return문이 없다.
  • 생성자 함수의 이름은 대문자로 시작하고 new 키워드를 붙여서 호출한다.
  • 생성자 함수가 호출되면 자동적으로 객체가 반환된다.

생성자함수 원리

const Elf1 = new Function(
	'name',
    'weapon', 
    this.name = name;
    this.weapon = weapon;
    )
const sarah = new Elf1('Sarah', 'fireworks')
// {name: 'Sarah', weapon: 'fireworks'}
  • new 키워드를 붙여서 함수를 호출할 때 함수이므로 실행 컨텍스트가 생성되는데 이때 this도 같이 실행컨텍스트에 붙여진다.(모든 함수는 호출될 때 실행컨텍스트가 만들어지고 이 실행컨텍스트는 arguments 객체, this, 스코프체인등으로 구성된다.)

  • 함수가 전역에서 호출될 때 this는 window객체를 가리키게 되지만 new를 붙여 함수를 호출할 경우 실행컨텍스트가 생성될 때 this를 생성자 함수로 만들어질 객체를 가리키게 한다.

  • Elf는 함수이다. 모든 함수는 prototype property를 가지고 있다.

  • 일반적이 함수의 경우 이 prototype property가 쓸모가 없지만 생성자 함수의 경우 유용하다.

  • 내장 객체 prototype에 다양한 메소들를 저장하는 것 처럼 생성자 함수의 prototype에 다양한 메소드를 저장할 수 있다.

  1. attack 메소드를 Elf 생성자함수의 프로토타입 프로퍼티에 할당한다.
  2. Elf를 호출해 peter에 할당한다.
  3. perter에는 name과 weapon이 프로퍼티로 있는 객체가 할당된다.
  4. peter는 attack 메소드가 없지만 사용할 수 있다.
    => 프로토타입 체인을 타고 Elf에 있는 attack을 사용할 수 있다.
  • attack은 메모리에 한번만 할당되어 있지만 Elf 생성자 함수로 만들어진 객체는 모두 attak을 쓸 수 있으므로 메모리를 절약할 수 있다.
function Elf(name, weapon) {
	this.name = name;
    this.weapon = weapon;
}

Elf.prototype.attack = funtion() {
	return 'attack with' + this.weapon
    // this will be the calling object
}

const peter = new Elf('Peter', 'stones');
peter.attack();
// 'attack with stones'

화살표 함수와 prototype

  • 화살표함수의 this는 lexical scoping이다. 즉 어디서 호출했는 지가 아니라 어디서 선언되었는지에 따라 this가 결정된다.
  • 아래의 코드의 경우 감싸고 있는 객체가 없으므로 this는 global object를 가리킨다.
  • 어떤 객체가 호출하냐에 따라 this를 결정하는(dynamic scope) 함수 선언문을 사용해야 한다.
Elf.prototype.attack = () => {
	return 'attack with' + this.weapon
}

메소드의 내부 함수 this

  • 메소드 안에 있는 내부 함수는 this가 생성자 함수로 만들어진 객체를 가리키지 않는다.
    1. bind를 사용한다.
Elf.prototye.build = function() {
	function building() {
    	return this.name + 'builds a house';
    }
   	return building.bind(this)
}

conole.log(peter.build()())
  1. 변수에 this를 저장하고 내부함수에서 this 대신 이 변수를 쓴다.
Elf.prototye.build = function() {
	const self = this;
	function building() {
    	return self.name + 'builds a house';
    }
   	return building()
}

conole.log(peter.build())

0개의 댓글