본문 바로가기

Front-End: Web/JavaScript

[코딩애플] js part 2-3. Object 생성기계인 constructor를 만들어 써보자

반응형

객체지향1. Object 생성기계인 constructor를 만들어 써보자

constructor 문법의 용도

1. Object를 마구 복사하고 싶을 때 사용(별로 쓸데없음)

비슷한 object를 여러개 만들 때, 오브젝트 복사를 도와준다.

var 학생1 = { name: 'Kim', age: 15 }
var 학생2 = { name: 'Kim', age: 15 }
var 학생3 = { name: 'Kim', age: 15 }
...

비슷한 학생 object를 여러개 만들려면, **contstructor라는 object 생성 기계**를 만들자.

constructor는 function 키워드를 빌려서 만든다. 함수와 다르다는 걸 보여주기 위해 관습적으로 첫글자를 대문자로 쓴다.

function Student(){ ... }

일단 알아보기 쉽게 한글인 기계 로 쓰자.

function 기계(){ // 이것은 constructor
	this.name = 'Kim';
    this.age = 15;        
}

이게 constructor이다. 이걸 쓰면 object 마구 쓰기 가능하다.

new 기계(); // 이러면 여기에 Object가 뽑힌다.

기계를 만드려면 **this**라는 키워드가 필요하다. 여기서 this는 **새로 생성되는 object**를 뜻한다.

this.name은 새로 생성되는 오브젝트의 name에 'Kim'이라는 값을 대입해주세요,

this.age는 새로 생성되는 오브젝트의 age에 15라는 값을 대입해주세요, 라는 의미다.

즉, 새로 생성되는 object에 값을 부여할 수 있다.

그럼 한 번 오브젝트를 뽑아보자.

var 학생1 = new 기계();
console.log(학생1); // 기계 {name: 'Kim', age: 15}

이러면 이제 학생1이라는 object가 뽑힌다. **'기계'는 이 object를 만든 constructor 이름**이다.

여러 학생을 만드려면 반복문을 돌려서 만들어도 된다.

object 안에 내용이 많을 수록 이득이다.

Q. 기계로 생성되는 모든 학생 object에 sayHi()함수도 추가하고 싶어요

학생1.sayHi(); // '안녕하세요 Kim 입니다' 출력되기

구현하려면 object에 함수를 추가하면 된다.

var 학생1 = {
	name: 'Kim',
    age: 15,
    sayHi: function(){
        console.log('안녕하세요 ' + this.name + ' 입니다');
    }
}

이게 모든 학생들에게도 뜨게하고 싶다면, 학생1에 하드코딩하는게아니라 constructor 기계에 추가하면 된다.

function 기계(){
    this.name = 'Kim';
    this.age = 15;
    this.sayHi = function(){
        console.log('안녕하세요 ', this.name + ' 입니다');
    }
}

이제 이 함수를 실행하는 모든 학생들에게 sayHi함수를 쓸 수 있다.

이처럼 **문자나 함수나 별걸 다 넣어서 오브젝트 생성기계를 만들 수 있다**.

Q. 기계로 학생을 뽑을 때 name을 다르게 설정해주고 싶어요

function 기계(구멍){
    this.name = 구멍;
    this.age = 15;
    this.sayHi = function(){
        console.log('안녕하세요 ', this.name + ' 입니다');
    }
}

함수의 파라미터로 받을 수 있는 것처럼 **함수에 파라미터를 뚫어서** 구멍에서 뭔갈 받아서 쓸 수 있다.

function 기계(이름){
    this.name = 이름;
    this.age = 15;
    this.sayHi = function(){
        console.log('안녕하세요 ', this.name + ' 입니다');
    }
}
기계('Park'); // 새로운 object를 만들 때 이름자리에 Park 넣어서 만들어줌

그럼 학생 오브젝트를 생성해보자.

var 학생1 = new 기계('Park');
console.log(학생1); // 기계 {name: 'Park', age:15, sayHi: f}
학생1.sayHi(); // 안녕하세요 Park 입니다

var 학생2 = new 기계();
console.log(학생2); // 기계 {name: undefined, age:15, sayHi: f}

학생2는 name이 undefined가 나온다. 왜냐하면 함수에 파라미터를 주지 않으면 undefined가 되기 때문이다.

파라미터를 여러개 줄 수도 있다.

function 기계(이름, 나이){
    this.name = 이름;
    this.age = 나이;
    this.sayHi = function(){
        console.log('안녕하세요 ', this.name + ' 입니다');
    }
}

instane

this = 기계에서 새로생성되는 오브젝트

constructor(생성자)

object 생성기계

간단 연습문제

쇼핑몰에 쓸 상품데이터를 오브젝트로 여러 개 만들고 싶습니다. 그래서 하드코딩해봤는데

var product1 = { name : 'shirts', price : 50000 };
var product2 = { name : 'pants', price : 60000 };

앞으로 몇십개를 더 만들어야해서 하드코딩은 그만두고 constructor를 만들어서 오브젝트를 뽑아내려고 합니다.

Q1. 위처럼 생긴 상품오브젝트들을 뽑아낼 수 있는 constructor를 제작해보세요.그리고 실제 상품 두개를 뽑아보십시오.

function product(name, price){
    this.name = name;
    this.price = price;
}
var product1 = product('shirts', 50000);
var product2 = product('pants', 60000);

Q2. 상품마다 부가세() 라는 내부 함수를 실행하면 콘솔창에 상품가격 \* 10% 만큼의 부가세금액이 출력되도록 하고 싶으면 constructor를 어떻게 수정해야할까요?

예를 들면 product1.부가세() 이렇게 쓰면 콘솔창에 5000이 출력되어야합니다.

function Product(name, price){
    this.name = name;
    this.price = price;
    this.부가세 = function(){
        console.log(this.price * 0.1);
    }
}
var product1 = new Product('shirts', 50000);
var product2 = new Product('pants', 60000);

객체지향2. prototype(기계 유전자, 원형)

prototype를 사용해서 <u>상속</u>기능 만들기

기계(부모, constructor)를 사용해서, 기계가 가지고 있는 name, age, sayHi 등 속성들을 학생들(자식, instance)물려받았다.

이렇게 부모의 속성을 자식이 물려받는 기능이 하나 더 있다. prototype이다. 이건 **자바스크립트에만 있는 문법**이다.

constructor(기계)를 만들면 prototype이라는 공간이 자동으로 생긴다. 한 번 확인해보자.

![](.\images\07.png)

만든 적도 없는데 생겨있다! 얘가 바로 기계 유전자다.

내가 키가 큰 이유는 부모의 키 큰 유전자를 받았기 떄문이다. prototype도 기계의 유전자다. 그래서 **prototype에 값을 추가하면 모든 자식들이 물려받을 수 있다**.

function 기계(이름, 나이){
    this.name = 이름;
    this.age = 나이;
    this.sayHi = function(){
        console.log('안녕하세요 ', this.name + ' 입니다');
    }
}

기계.prototype.gender = '남';

var 학생1 = new 기계('Park');

{기계.prototype} 오브젝트에 'gender'는 '남'인 key값을 추가한거다.

![](.\images\08.png)

학생1을 콘솔해보면 gender이 없다. 안보이지만 gender 속성을 가지고 있다. 신기해!

prototype의 원리

1. 왜 자식은 부모 유전자에 등록된 값을 사용가능한가

원리는 그냥 자바스크립트가 그렇게 동작한다고 알면 된다. 자바스크립트는 오브젝트를 이 순서로 해석하고 자료를 출력한다.

학생1.gender;
  1. 학생1이 직접 gender를 가지고 있는가? (가지고 있으면 출력, 없으면 2로 이동)
  2. 그럼 학생1의 부모 유전자(기계.prototype)가 gender를 가지고 있는가? (가지고 있으면 출력)

즉, **내가 gender가 없으면 부모 유전자에서 찾는구나~** 생각하자!

2. toString, sort 등 자바스크립트 내장함수를 사용가능한 이유

toString()

  • Object/Array에 붙일 수 있는 내장함수
[1,2,3].toString(); // "1,2,3"
학생1.toString(); // "[Object object]"

array에 push, sort, toString, ... 등 내장함수를 쓸 수 있다. 대체 어떻게 해놨길래 모든 Object가 내장함수를 쓸 수 있는 걸까? 학생1을 출력하면 toString이라는 메서드는 없는데 말이다.

그러면 자바스크립트에서 오브젝트를 해석하는 순서를 다시 봐야한다.

  1. 학생1이 toString()을 가지고 있는가?
  2. 그럼 부모 유전자에 있는가?
  3. 그럼 부모의 부모 유전자에 있는가?
  4. ...

컴퓨터는 실제 내부적으로 array를 이렇게 만든다.

var arr = [1,2,3];
var arr = new Array(1,2,3);

위와 아래는 동일하다. new 키워드를 만들면 기계로부터 오브젝트를 하나 뽑아낸다. 즉 array 만드는 기계로부터 하나 뽑은거다. arr은 이제 Array 기계가 가지고 있는 모든 기능들을 상속받는다. 부모 유전자에 sort, toString, map, ... 등 모든 내장함수를 가지고 있어서 오브젝트도 쓸 수 있는 거다. arr에 sort 이런거를 부여한 적이 없는데도 말이다.

확인해보고 싶으면 Array.prototype을 입력해서 Array의 유전자를 확인해보면 된다. map, sort, 등 모든 내장함수가 다 들어있다.

메서드를 구글에 검색하면 MDN에 Array.prototype.sort()라고 뜬다. Array.prototype! 부모 유전자에 sort함수가 있다! 이제 이해가 가나요?

Object도 마찬가지다.

var obj = { name: 'Kim'};
var obj = new Object();

위 코드는 동일하다. 모든 object 자료형은 Object 부모를 이용해 이렇게 만든다. 그리고 부모유전자를 올라가서 찾아본다.

  1. 학생1 (toString이 없네)
  2. 기계.prototype (toString이 없네)
  3. Object.prototype (toString이 있네! -> 실행)

prototype의 특징 몇가지

1. prototype은 함수(기계)에만 몰래 생성된다

var arr = [1,2,3];

![](.\images\09.png)

Array(기계)에는 있는데, arr에는 prototype이 없다고 뜬다.

2. 내 부모 유전자(부모의 prototype)를 검사하고 싶다면 '__ proto __'

![](.\images\10.png)

3. __ prototype __ 를 이용해 부모님 강제 등록하기

var 부모 = { name: 'Kim'};
var 자식 = {};
자식.__proto__ = 부모;

자식.name; // 'Kim'

나의 부모유전자는 이걸로 해주세요~ 라고 자식에서 지정할 수 있다.

4. 콘솔창에서 알려주는 prototype chain

자식에서 부모의 유전자를 보고 싶다면 __ proto __ 에서 볼 수 있다.

학생1의 부모는 기계니까 기계의 유전자가 보인다.

![](.\images\11.png)

그리고 기계의 부모는 Object 생성자다. 그래서 Object의 유전자가 보인다.

![](.\images\12.png)

constructor, prototype 연습문제

0. 오브젝트 자료 여러개를 만들고 싶습니다.

제일 잘하는게 하드코딩이기 때문에 하드코딩해봤습니다.

var 학생1 = { name : 'Kim', age : 20 }
var 학생2 = { name : 'Park', age : 21 }
var 학생3 = { name : 'Lee', age : 22 }

하드코딩해서 3개를 만들긴 했는데 앞으로 만들일이 더 많이 생길 것 같아서 constructor를 제작하려고 합니다.

**constructor문법을 사용해서 위의 오브젝트와 똑같은 오브젝트 3개를 한번 뽑아보십시오.**

**+ 여기에 학생1.sayHi()라고 사용하면 "안녕 나는 Kim이야" 라는 글자가 콘솔창에 나오도록 sayHi()라는 함수도 constructor 안에 추가해보세요.**

➡️

function Student (name, age){
    this.name = name;
    this.age = age;
    this.sayHi: function(){
        console.log('안녕 나는' + this.name + '이야')
    }
}

var 학생1 = new Student('Kim', 20);
var 학생2 = new Student('Park', 21);
var 학생3 = new Student('Lee', 22);

1. 다음 코드의 출력 결과는 무엇일까요?

function Parent(){
  this.name = 'Kim';
}
var a = new Parent();

a.__proto__.name = 'Park';
console.log(a.name)

**➡️ 'Kim'**

첫 4 줄에 의해서 a = {name: 'Kim'}이 되고,

a.__ proto __.name = 'Park'; 이건 **부모 prototype에 {name: 'Park'} 이걸 추가하라는 뜻**이다.

그럼 이제 a.name 이라고 사용했을 때,

**내가 직접 가지고 있는 {name: 'Kim'}** 이걸 우선 출력해준다. (이미 a는 name에 'Kim'을 가지고 있는 상태이기 때문)

2. 함수가 안들어가요 엉엉

위에 0번 문제에서 Student라는 부모에 sayHi라는 함수를 하나 추가하라고 했죠?

그래서 sayHi()라고 사용하면 "안녕 나는 ~~이야" 라고 내 이름을 출력해주는 함수를 prototype에 추가했습니다.

하단처럼 만들었는데 의도한 대로 이름이 출력되지 않고 있습니다.

원인은 무엇일까요?

function Student(이름, 나이){
  this.name = 이름;
  this.age = 나이;
}

Student.prototype.sayHi = () => {
    console.log('안녕 나는 ' + this.name + '이야');
  }
var 학생1 = new Student('Kim', 20);

학생1.sayHi(); //왜 이 코드가 제대로 안나오죠?
 

**➡️화살표 함수로 만들었기 때문에 this.name이 constructor Student의 name이 아니기 때문이다.**

SayHi() 라는 함수를 prototype에 추가할 때 arrow function을 사용했다. 결론부터 말하자면 arrow function은 그냥 일반 function 대체품이 아니다. arrow function은 this 를 바깥에 있는 this를 그대로 사용하고 싶을 때 쓰는 함수라 했다.

암튼 sayHi() 함수를 만들 때 arrow function을 사용해서 내부에 있던 this 값이 이상해진거다.

Student.prototype.sayHi = () => {
	console.log(this); // {window}
}

window가 출력된다(strict mode에선 undefined). arrow function은 그냥 바깥 아메두나 있던 값을 가져와서 사용하기 때문이다. Student 함수에서 this는 바깥의 this인 window고, 그 window를 저기 화살표 함수 안에 적용했으니까 this가 window다.

(**object안에 들어있는 함수 안에 있는 this****함수를 부른 object**가 된다)

3. 모든 array에 적용할 수 있는 함수를 직접 새로 만들려면 어떻게 해야할까요?

모든 array에 붙일 수 있는,

array 내에 있는 3이라는 값을 제거해주는 유용한 함수를 하나 만들고 싶습니다.

var arr = [1,2,3];
arr.remove3();

console.log(arr); //[1,2]

이렇게 array뒤에 붙이기만 하면 array 내의 3이라는 모든 숫자 자료들이 삭제됩니다.

멋있게 이름은 remove3() 이라고 하겠습니다.

remove3()함수는 어떻게, 어디에 만들어야 모든 array에 쓸 수 있을까요?

**➡️Array.prototype.remove3 = function(){ ... } 에 만들어야 한다.**

Array.prototype.remove3 = function(){
	return this.filter(v => v !== 3)
}

애플코딩 풀이

모든 array 자로형은 부모가 ARray로 부터 new Array() 이런 식으로 만들어지기 때문에 Array라는 부모의 prototype에 있는 pop(), sort(), push(), ... 이런 함수들을 자유롭게 가져다쓸 수 있다.

그러면 우리도 Array의 prototype에 remove3이라는 함수를 하나 추가해주면 된다.

Array.prototype.remove3 = function(){
    this 에서 3을 찾아서 제거해주세요
}

구현해보자.

Array.prototype.remove3 = function(){
  for (var i = 0; i < this.length; i++) {
    if ( this[i] === 3 ) {
      this.splice(i,1);
    }
  }
};

var arr = [1,2,3,4];
arr.remove3();

console.log(arr); //[1,2,4]

객체지향1. Object 생성기계인 constructor를 만들어 써보자객체지향1. Object 생성기계인 constructor를 만들어 써보자

constructor 문법의 용도

1. Object를 마구 복사하고 싶을 때 사용(별로 쓸데없음)

비슷한 object를 여러개 만들 때, 오브젝트 복사를 도와준다.

var 학생1 = { name: 'Kim', age: 15 }
var 학생2 = { name: 'Kim', age: 15 }
var 학생3 = { name: 'Kim', age: 15 }
...

비슷한 학생 object를 여러개 만들려면, **contstructor라는 object 생성 기계**를 만들자.

constructor는 function 키워드를 빌려서 만든다. 함수와 다르다는 걸 보여주기 위해 관습적으로 첫글자를 대문자로 쓴다.

function Student(){ ... }

일단 알아보기 쉽게 한글인 기계 로 쓰자.

function 기계(){ // 이것은 constructor
	this.name = 'Kim';
    this.age = 15;        
}

이게 constructor이다. 이걸 쓰면 object 마구 쓰기 가능하다.

new 기계(); // 이러면 여기에 Object가 뽑힌다.

기계를 만드려면 **this**라는 키워드가 필요하다. 여기서 this는 **새로 생성되는 object**를 뜻한다.

this.name은 새로 생성되는 오브젝트의 name에 'Kim'이라는 값을 대입해주세요,

this.age는 새로 생성되는 오브젝트의 age에 15라는 값을 대입해주세요, 라는 의미다.

즉, 새로 생성되는 object에 값을 부여할 수 있다.

그럼 한 번 오브젝트를 뽑아보자.

var 학생1 = new 기계();
console.log(학생1); // 기계 {name: 'Kim', age: 15}

이러면 이제 학생1이라는 object가 뽑힌다. **'기계'는 이 object를 만든 constructor 이름**이다.

여러 학생을 만드려면 반복문을 돌려서 만들어도 된다.

object 안에 내용이 많을 수록 이득이다.

Q. 기계로 생성되는 모든 학생 object에 sayHi()함수도 추가하고 싶어요

학생1.sayHi(); // '안녕하세요 Kim 입니다' 출력되기

구현하려면 object에 함수를 추가하면 된다.

var 학생1 = {
	name: 'Kim',
    age: 15,
    sayHi: function(){
        console.log('안녕하세요 ' + this.name + ' 입니다');
    }
}

이게 모든 학생들에게도 뜨게하고 싶다면, 학생1에 하드코딩하는게아니라 constructor 기계에 추가하면 된다.

function 기계(){
    this.name = 'Kim';
    this.age = 15;
    this.sayHi = function(){
        console.log('안녕하세요 ', this.name + ' 입니다');
    }
}

이제 이 함수를 실행하는 모든 학생들에게 sayHi함수를 쓸 수 있다.

이처럼 **문자나 함수나 별걸 다 넣어서 오브젝트 생성기계를 만들 수 있다**.

Q. 기계로 학생을 뽑을 때 name을 다르게 설정해주고 싶어요

function 기계(구멍){
    this.name = 구멍;
    this.age = 15;
    this.sayHi = function(){
        console.log('안녕하세요 ', this.name + ' 입니다');
    }
}

함수의 파라미터로 받을 수 있는 것처럼 **함수에 파라미터를 뚫어서** 구멍에서 뭔갈 받아서 쓸 수 있다.

function 기계(이름){
    this.name = 이름;
    this.age = 15;
    this.sayHi = function(){
        console.log('안녕하세요 ', this.name + ' 입니다');
    }
}
기계('Park'); // 새로운 object를 만들 때 이름자리에 Park 넣어서 만들어줌

그럼 학생 오브젝트를 생성해보자.

var 학생1 = new 기계('Park');
console.log(학생1); // 기계 {name: 'Park', age:15, sayHi: f}
학생1.sayHi(); // 안녕하세요 Park 입니다

var 학생2 = new 기계();
console.log(학생2); // 기계 {name: undefined, age:15, sayHi: f}

학생2는 name이 undefined가 나온다. 왜냐하면 함수에 파라미터를 주지 않으면 undefined가 되기 때문이다.

파라미터를 여러개 줄 수도 있다.

function 기계(이름, 나이){
    this.name = 이름;
    this.age = 나이;
    this.sayHi = function(){
        console.log('안녕하세요 ', this.name + ' 입니다');
    }
}

instane

this = 기계에서 새로생성되는 오브젝트

constructor(생성자)

object 생성기계

간단 연습문제

쇼핑몰에 쓸 상품데이터를 오브젝트로 여러 개 만들고 싶습니다. 그래서 하드코딩해봤는데

var product1 = { name : 'shirts', price : 50000 };
var product2 = { name : 'pants', price : 60000 };

앞으로 몇십개를 더 만들어야해서 하드코딩은 그만두고 constructor를 만들어서 오브젝트를 뽑아내려고 합니다.

Q1. 위처럼 생긴 상품오브젝트들을 뽑아낼 수 있는 constructor를 제작해보세요.그리고 실제 상품 두개를 뽑아보십시오.

function product(name, price){
    this.name = name;
    this.price = price;
}
var product1 = product('shirts', 50000);
var product2 = product('pants', 60000);

Q2. 상품마다 부가세() 라는 내부 함수를 실행하면 콘솔창에 상품가격 \* 10% 만큼의 부가세금액이 출력되도록 하고 싶으면 constructor를 어떻게 수정해야할까요?

예를 들면 product1.부가세() 이렇게 쓰면 콘솔창에 5000이 출력되어야합니다.

function Product(name, price){
    this.name = name;
    this.price = price;
    this.부가세 = function(){
        console.log(this.price * 0.1);
    }
}
var product1 = new Product('shirts', 50000);
var product2 = new Product('pants', 60000);

객체지향2. prototype(기계 유전자, 원형)

prototype를 사용해서 <u>상속</u>기능 만들기

기계(부모, constructor)를 사용해서, 기계가 가지고 있는 name, age, sayHi 등 속성들을 학생들(자식, instance)물려받았다.

이렇게 부모의 속성을 자식이 물려받는 기능이 하나 더 있다. prototype이다. 이건 **자바스크립트에만 있는 문법**이다.

constructor(기계)를 만들면 prototype이라는 공간이 자동으로 생긴다. 한 번 확인해보자.

![](.\images\07.png)

만든 적도 없는데 생겨있다! 얘가 바로 기계 유전자다.

내가 키가 큰 이유는 부모의 키 큰 유전자를 받았기 떄문이다. prototype도 기계의 유전자다. 그래서 **prototype에 값을 추가하면 모든 자식들이 물려받을 수 있다**.

function 기계(이름, 나이){
    this.name = 이름;
    this.age = 나이;
    this.sayHi = function(){
        console.log('안녕하세요 ', this.name + ' 입니다');
    }
}

기계.prototype.gender = '남';

var 학생1 = new 기계('Park');

{기계.prototype} 오브젝트에 'gender'는 '남'인 key값을 추가한거다.

![](.\images\08.png)

학생1을 콘솔해보면 gender이 없다. 안보이지만 gender 속성을 가지고 있다. 신기해!

prototype의 원리

1. 왜 자식은 부모 유전자에 등록된 값을 사용가능한가

원리는 그냥 자바스크립트가 그렇게 동작한다고 알면 된다. 자바스크립트는 오브젝트를 이 순서로 해석하고 자료를 출력한다.

학생1.gender;
  1. 학생1이 직접 gender를 가지고 있는가? (가지고 있으면 출력, 없으면 2로 이동)
  2. 그럼 학생1의 부모 유전자(기계.prototype)가 gender를 가지고 있는가? (가지고 있으면 출력)

즉, **내가 gender가 없으면 부모 유전자에서 찾는구나~** 생각하자!

2. toString, sort 등 자바스크립트 내장함수를 사용가능한 이유

toString()

  • Object/Array에 붙일 수 있는 내장함수
[1,2,3].toString(); // "1,2,3"
학생1.toString(); // "[Object object]"

array에 push, sort, toString, ... 등 내장함수를 쓸 수 있다. 대체 어떻게 해놨길래 모든 Object가 내장함수를 쓸 수 있는 걸까? 학생1을 출력하면 toString이라는 메서드는 없는데 말이다.

그러면 자바스크립트에서 오브젝트를 해석하는 순서를 다시 봐야한다.

  1. 학생1이 toString()을 가지고 있는가?
  2. 그럼 부모 유전자에 있는가?
  3. 그럼 부모의 부모 유전자에 있는가?
  4. ...

컴퓨터는 실제 내부적으로 array를 이렇게 만든다.

var arr = [1,2,3];
var arr = new Array(1,2,3);

위와 아래는 동일하다. new 키워드를 만들면 기계로부터 오브젝트를 하나 뽑아낸다. 즉 array 만드는 기계로부터 하나 뽑은거다. arr은 이제 Array 기계가 가지고 있는 모든 기능들을 상속받는다. 부모 유전자에 sort, toString, map, ... 등 모든 내장함수를 가지고 있어서 오브젝트도 쓸 수 있는 거다. arr에 sort 이런거를 부여한 적이 없는데도 말이다.

확인해보고 싶으면 Array.prototype을 입력해서 Array의 유전자를 확인해보면 된다. map, sort, 등 모든 내장함수가 다 들어있다.

메서드를 구글에 검색하면 MDN에 Array.prototype.sort()라고 뜬다. Array.prototype! 부모 유전자에 sort함수가 있다! 이제 이해가 가나요?

Object도 마찬가지다.

var obj = { name: 'Kim'};
var obj = new Object();

위 코드는 동일하다. 모든 object 자료형은 Object 부모를 이용해 이렇게 만든다. 그리고 부모유전자를 올라가서 찾아본다.

  1. 학생1 (toString이 없네)
  2. 기계.prototype (toString이 없네)
  3. Object.prototype (toString이 있네! -> 실행)

prototype의 특징 몇가지

1. prototype은 함수(기계)에만 몰래 생성된다

var arr = [1,2,3];

![](.\images\09.png)

Array(기계)에는 있는데, arr에는 prototype이 없다고 뜬다.

2. 내 부모 유전자(부모의 prototype)를 검사하고 싶다면 '__ proto __'

![](.\images\10.png)

3. __ prototype __ 를 이용해 부모님 강제 등록하기

var 부모 = { name: 'Kim'};
var 자식 = {};
자식.__proto__ = 부모;

자식.name; // 'Kim'

나의 부모유전자는 이걸로 해주세요~ 라고 자식에서 지정할 수 있다.

4. 콘솔창에서 알려주는 prototype chain

자식에서 부모의 유전자를 보고 싶다면 __ proto __ 에서 볼 수 있다.

학생1의 부모는 기계니까 기계의 유전자가 보인다.

![](.\images\11.png)

그리고 기계의 부모는 Object 생성자다. 그래서 Object의 유전자가 보인다.

![](.\images\12.png)

constructor, prototype 연습문제

0. 오브젝트 자료 여러개를 만들고 싶습니다.

제일 잘하는게 하드코딩이기 때문에 하드코딩해봤습니다.

var 학생1 = { name : 'Kim', age : 20 }
var 학생2 = { name : 'Park', age : 21 }
var 학생3 = { name : 'Lee', age : 22 }

하드코딩해서 3개를 만들긴 했는데 앞으로 만들일이 더 많이 생길 것 같아서 constructor를 제작하려고 합니다.

**constructor문법을 사용해서 위의 오브젝트와 똑같은 오브젝트 3개를 한번 뽑아보십시오.**

**+ 여기에 학생1.sayHi()라고 사용하면 "안녕 나는 Kim이야" 라는 글자가 콘솔창에 나오도록 sayHi()라는 함수도 constructor 안에 추가해보세요.**

➡️

function Student (name, age){
    this.name = name;
    this.age = age;
    this.sayHi: function(){
        console.log('안녕 나는' + this.name + '이야')
    }
}

var 학생1 = new Student('Kim', 20);
var 학생2 = new Student('Park', 21);
var 학생3 = new Student('Lee', 22);

1. 다음 코드의 출력 결과는 무엇일까요?

function Parent(){
  this.name = 'Kim';
}
var a = new Parent();

a.__proto__.name = 'Park';
console.log(a.name)

**➡️ 'Kim'**

첫 4 줄에 의해서 a = {name: 'Kim'}이 되고,

a.__ proto __.name = 'Park'; 이건 **부모 prototype에 {name: 'Park'} 이걸 추가하라는 뜻**이다.

그럼 이제 a.name 이라고 사용했을 때,

**내가 직접 가지고 있는 {name: 'Kim'}** 이걸 우선 출력해준다. (이미 a는 name에 'Kim'을 가지고 있는 상태이기 때문)

2. 함수가 안들어가요 엉엉

위에 0번 문제에서 Student라는 부모에 sayHi라는 함수를 하나 추가하라고 했죠?

그래서 sayHi()라고 사용하면 "안녕 나는 ~~이야" 라고 내 이름을 출력해주는 함수를 prototype에 추가했습니다.

하단처럼 만들었는데 의도한 대로 이름이 출력되지 않고 있습니다.

원인은 무엇일까요?

function Student(이름, 나이){
  this.name = 이름;
  this.age = 나이;
}

Student.prototype.sayHi = () => {
    console.log('안녕 나는 ' + this.name + '이야');
  }
var 학생1 = new Student('Kim', 20);

학생1.sayHi(); //왜 이 코드가 제대로 안나오죠?
 

**➡️화살표 함수로 만들었기 때문에 this.name이 constructor Student의 name이 아니기 때문이다.**

SayHi() 라는 함수를 prototype에 추가할 때 arrow function을 사용했다. 결론부터 말하자면 arrow function은 그냥 일반 function 대체품이 아니다. arrow function은 this 를 바깥에 있는 this를 그대로 사용하고 싶을 때 쓰는 함수라 했다.

암튼 sayHi() 함수를 만들 때 arrow function을 사용해서 내부에 있던 this 값이 이상해진거다.

Student.prototype.sayHi = () => {
	console.log(this); // {window}
}

window가 출력된다(strict mode에선 undefined). arrow function은 그냥 바깥 아메두나 있던 값을 가져와서 사용하기 때문이다. Student 함수에서 this는 바깥의 this인 window고, 그 window를 저기 화살표 함수 안에 적용했으니까 this가 window다.

(**object안에 들어있는 함수 안에 있는 this****함수를 부른 object**가 된다)

3. 모든 array에 적용할 수 있는 함수를 직접 새로 만들려면 어떻게 해야할까요?

모든 array에 붙일 수 있는,

array 내에 있는 3이라는 값을 제거해주는 유용한 함수를 하나 만들고 싶습니다.

var arr = [1,2,3];
arr.remove3();

console.log(arr); //[1,2]

이렇게 array뒤에 붙이기만 하면 array 내의 3이라는 모든 숫자 자료들이 삭제됩니다.

멋있게 이름은 remove3() 이라고 하겠습니다.

remove3()함수는 어떻게, 어디에 만들어야 모든 array에 쓸 수 있을까요?

**➡️Array.prototype.remove3 = function(){ ... } 에 만들어야 한다.**

Array.prototype.remove3 = function(){
	return this.filter(v => v !== 3)
}

애플코딩 풀이

모든 array 자로형은 부모가 ARray로 부터 new Array() 이런 식으로 만들어지기 때문에 Array라는 부모의 prototype에 있는 pop(), sort(), push(), ... 이런 함수들을 자유롭게 가져다쓸 수 있다.

그러면 우리도 Array의 prototype에 remove3이라는 함수를 하나 추가해주면 된다.

Array.prototype.remove3 = function(){
    this 에서 3을 찾아서 제거해주세요
}

구현해보자.

Array.prototype.remove3 = function(){
  for (var i = 0; i < this.length; i++) {
    if ( this[i] === 3 ) {
      this.splice(i,1);
    }
  }
};

var arr = [1,2,3,4];
arr.remove3();

console.log(arr); //[1,2,4]

constructor 문법의 용도

1. Object를 마구 복사하고 싶을 때 사용(별로 쓸데없음)

비슷한 object를 여러개 만들 때, 오브젝트 복사를 도와준다.

var 학생1 = { name: 'Kim', age: 15 }
var 학생2 = { name: 'Kim', age: 15 }
var 학생3 = { name: 'Kim', age: 15 }
...

비슷한 학생 object를 여러개 만들려면, **contstructor라는 object 생성 기계**를 만들자.

constructor는 function 키워드를 빌려서 만든다. 함수와 다르다는 걸 보여주기 위해 관습적으로 첫글자를 대문자로 쓴다.

function Student(){ ... }

일단 알아보기 쉽게 한글인 기계 로 쓰자.

function 기계(){ // 이것은 constructor
	this.name = 'Kim';
    this.age = 15;        
}

이게 constructor이다. 이걸 쓰면 object 마구 쓰기 가능하다.

new 기계(); // 이러면 여기에 Object가 뽑힌다.

기계를 만드려면 **this**라는 키워드가 필요하다. 여기서 this는 **새로 생성되는 object**를 뜻한다.

this.name은 새로 생성되는 오브젝트의 name에 'Kim'이라는 값을 대입해주세요,

this.age는 새로 생성되는 오브젝트의 age에 15라는 값을 대입해주세요, 라는 의미다.

즉, 새로 생성되는 object에 값을 부여할 수 있다.

그럼 한 번 오브젝트를 뽑아보자.

var 학생1 = new 기계();
console.log(학생1); // 기계 {name: 'Kim', age: 15}

이러면 이제 학생1이라는 object가 뽑힌다. **'기계'는 이 object를 만든 constructor 이름**이다.

여러 학생을 만드려면 반복문을 돌려서 만들어도 된다.

object 안에 내용이 많을 수록 이득이다.

Q. 기계로 생성되는 모든 학생 object에 sayHi()함수도 추가하고 싶어요

학생1.sayHi(); // '안녕하세요 Kim 입니다' 출력되기

구현하려면 object에 함수를 추가하면 된다.

var 학생1 = {
	name: 'Kim',
    age: 15,
    sayHi: function(){
        console.log('안녕하세요 ' + this.name + ' 입니다');
    }
}

이게 모든 학생들에게도 뜨게하고 싶다면, 학생1에 하드코딩하는게아니라 constructor 기계에 추가하면 된다.

function 기계(){
    this.name = 'Kim';
    this.age = 15;
    this.sayHi = function(){
        console.log('안녕하세요 ', this.name + ' 입니다');
    }
}

이제 이 함수를 실행하는 모든 학생들에게 sayHi함수를 쓸 수 있다.

이처럼 **문자나 함수나 별걸 다 넣어서 오브젝트 생성기계를 만들 수 있다**.

Q. 기계로 학생을 뽑을 때 name을 다르게 설정해주고 싶어요

function 기계(구멍){
    this.name = 구멍;
    this.age = 15;
    this.sayHi = function(){
        console.log('안녕하세요 ', this.name + ' 입니다');
    }
}

함수의 파라미터로 받을 수 있는 것처럼 **함수에 파라미터를 뚫어서** 구멍에서 뭔갈 받아서 쓸 수 있다.

function 기계(이름){
    this.name = 이름;
    this.age = 15;
    this.sayHi = function(){
        console.log('안녕하세요 ', this.name + ' 입니다');
    }
}
기계('Park'); // 새로운 object를 만들 때 이름자리에 Park 넣어서 만들어줌

그럼 학생 오브젝트를 생성해보자.

var 학생1 = new 기계('Park');
console.log(학생1); // 기계 {name: 'Park', age:15, sayHi: f}
학생1.sayHi(); // 안녕하세요 Park 입니다

var 학생2 = new 기계();
console.log(학생2); // 기계 {name: undefined, age:15, sayHi: f}

학생2는 name이 undefined가 나온다. 왜냐하면 함수에 파라미터를 주지 않으면 undefined가 되기 때문이다.

파라미터를 여러개 줄 수도 있다.

function 기계(이름, 나이){
    this.name = 이름;
    this.age = 나이;
    this.sayHi = function(){
        console.log('안녕하세요 ', this.name + ' 입니다');
    }
}

instane

this = 기계에서 새로생성되는 오브젝트

constructor(생성자)

object 생성기계

간단 연습문제

쇼핑몰에 쓸 상품데이터를 오브젝트로 여러 개 만들고 싶습니다. 그래서 하드코딩해봤는데

var product1 = { name : 'shirts', price : 50000 };
var product2 = { name : 'pants', price : 60000 };

앞으로 몇십개를 더 만들어야해서 하드코딩은 그만두고 constructor를 만들어서 오브젝트를 뽑아내려고 합니다.

Q1. 위처럼 생긴 상품오브젝트들을 뽑아낼 수 있는 constructor를 제작해보세요.그리고 실제 상품 두개를 뽑아보십시오.

function product(name, price){
    this.name = name;
    this.price = price;
}
var product1 = product('shirts', 50000);
var product2 = product('pants', 60000);

Q2. 상품마다 부가세() 라는 내부 함수를 실행하면 콘솔창에 상품가격 \* 10% 만큼의 부가세금액이 출력되도록 하고 싶으면 constructor를 어떻게 수정해야할까요?

예를 들면 product1.부가세() 이렇게 쓰면 콘솔창에 5000이 출력되어야합니다.

function Product(name, price){
    this.name = name;
    this.price = price;
    this.부가세 = function(){
        console.log(this.price * 0.1);
    }
}
var product1 = new Product('shirts', 50000);
var product2 = new Product('pants', 60000);

객체지향2. prototype(기계 유전자, 원형)

prototype를 사용해서 <u>상속</u>기능 만들기

기계(부모, constructor)를 사용해서, 기계가 가지고 있는 name, age, sayHi 등 속성들을 학생들(자식, instance)물려받았다.

이렇게 부모의 속성을 자식이 물려받는 기능이 하나 더 있다. prototype이다. 이건 **자바스크립트에만 있는 문법**이다.

constructor(기계)를 만들면 prototype이라는 공간이 자동으로 생긴다. 한 번 확인해보자.

![](.\images\07.png)

만든 적도 없는데 생겨있다! 얘가 바로 기계 유전자다.

내가 키가 큰 이유는 부모의 키 큰 유전자를 받았기 떄문이다. prototype도 기계의 유전자다. 그래서 **prototype에 값을 추가하면 모든 자식들이 물려받을 수 있다**.

function 기계(이름, 나이){
    this.name = 이름;
    this.age = 나이;
    this.sayHi = function(){
        console.log('안녕하세요 ', this.name + ' 입니다');
    }
}

기계.prototype.gender = '남';

var 학생1 = new 기계('Park');

{기계.prototype} 오브젝트에 'gender'는 '남'인 key값을 추가한거다.

![](.\images\08.png)

학생1을 콘솔해보면 gender이 없다. 안보이지만 gender 속성을 가지고 있다. 신기해!

prototype의 원리

1. 왜 자식은 부모 유전자에 등록된 값을 사용가능한가

원리는 그냥 자바스크립트가 그렇게 동작한다고 알면 된다. 자바스크립트는 오브젝트를 이 순서로 해석하고 자료를 출력한다.

학생1.gender;
  1. 학생1이 직접 gender를 가지고 있는가? (가지고 있으면 출력, 없으면 2로 이동)
  2. 그럼 학생1의 부모 유전자(기계.prototype)가 gender를 가지고 있는가? (가지고 있으면 출력)

즉, **내가 gender가 없으면 부모 유전자에서 찾는구나~** 생각하자!

2. toString, sort 등 자바스크립트 내장함수를 사용가능한 이유

toString()

  • Object/Array에 붙일 수 있는 내장함수
[1,2,3].toString(); // "1,2,3"
학생1.toString(); // "[Object object]"

array에 push, sort, toString, ... 등 내장함수를 쓸 수 있다. 대체 어떻게 해놨길래 모든 Object가 내장함수를 쓸 수 있는 걸까? 학생1을 출력하면 toString이라는 메서드는 없는데 말이다.

그러면 자바스크립트에서 오브젝트를 해석하는 순서를 다시 봐야한다.

  1. 학생1이 toString()을 가지고 있는가?
  2. 그럼 부모 유전자에 있는가?
  3. 그럼 부모의 부모 유전자에 있는가?
  4. ...

컴퓨터는 실제 내부적으로 array를 이렇게 만든다.

var arr = [1,2,3];
var arr = new Array(1,2,3);

위와 아래는 동일하다. new 키워드를 만들면 기계로부터 오브젝트를 하나 뽑아낸다. 즉 array 만드는 기계로부터 하나 뽑은거다. arr은 이제 Array 기계가 가지고 있는 모든 기능들을 상속받는다. 부모 유전자에 sort, toString, map, ... 등 모든 내장함수를 가지고 있어서 오브젝트도 쓸 수 있는 거다. arr에 sort 이런거를 부여한 적이 없는데도 말이다.

확인해보고 싶으면 Array.prototype을 입력해서 Array의 유전자를 확인해보면 된다. map, sort, 등 모든 내장함수가 다 들어있다.

메서드를 구글에 검색하면 MDN에 Array.prototype.sort()라고 뜬다. Array.prototype! 부모 유전자에 sort함수가 있다! 이제 이해가 가나요?

Object도 마찬가지다.

var obj = { name: 'Kim'};
var obj = new Object();

위 코드는 동일하다. 모든 object 자료형은 Object 부모를 이용해 이렇게 만든다. 그리고 부모유전자를 올라가서 찾아본다.

  1. 학생1 (toString이 없네)
  2. 기계.prototype (toString이 없네)
  3. Object.prototype (toString이 있네! -> 실행)

prototype의 특징 몇가지

1. prototype은 함수(기계)에만 몰래 생성된다

var arr = [1,2,3];

![](.\images\09.png)

Array(기계)에는 있는데, arr에는 prototype이 없다고 뜬다.

2. 내 부모 유전자(부모의 prototype)를 검사하고 싶다면 '__ proto __'

![](.\images\10.png)

3. __ prototype __ 를 이용해 부모님 강제 등록하기

var 부모 = { name: 'Kim'};
var 자식 = {};
자식.__proto__ = 부모;

자식.name; // 'Kim'

나의 부모유전자는 이걸로 해주세요~ 라고 자식에서 지정할 수 있다.

4. 콘솔창에서 알려주는 prototype chain

자식에서 부모의 유전자를 보고 싶다면 __ proto __ 에서 볼 수 있다.

학생1의 부모는 기계니까 기계의 유전자가 보인다.

![](.\images\11.png)

그리고 기계의 부모는 Object 생성자다. 그래서 Object의 유전자가 보인다.

![](.\images\12.png)

constructor, prototype 연습문제

0. 오브젝트 자료 여러개를 만들고 싶습니다.

제일 잘하는게 하드코딩이기 때문에 하드코딩해봤습니다.

var 학생1 = { name : 'Kim', age : 20 }
var 학생2 = { name : 'Park', age : 21 }
var 학생3 = { name : 'Lee', age : 22 }

하드코딩해서 3개를 만들긴 했는데 앞으로 만들일이 더 많이 생길 것 같아서 constructor를 제작하려고 합니다.

**constructor문법을 사용해서 위의 오브젝트와 똑같은 오브젝트 3개를 한번 뽑아보십시오.**

**+ 여기에 학생1.sayHi()라고 사용하면 "안녕 나는 Kim이야" 라는 글자가 콘솔창에 나오도록 sayHi()라는 함수도 constructor 안에 추가해보세요.**

➡️

function Student (name, age){
    this.name = name;
    this.age = age;
    this.sayHi: function(){
        console.log('안녕 나는' + this.name + '이야')
    }
}

var 학생1 = new Student('Kim', 20);
var 학생2 = new Student('Park', 21);
var 학생3 = new Student('Lee', 22);

1. 다음 코드의 출력 결과는 무엇일까요?

function Parent(){
  this.name = 'Kim';
}
var a = new Parent();

a.__proto__.name = 'Park';
console.log(a.name)

**➡️ 'Kim'**

첫 4 줄에 의해서 a = {name: 'Kim'}이 되고,

a.__ proto __.name = 'Park'; 이건 **부모 prototype에 {name: 'Park'} 이걸 추가하라는 뜻**이다.

그럼 이제 a.name 이라고 사용했을 때,

**내가 직접 가지고 있는 {name: 'Kim'}** 이걸 우선 출력해준다. (이미 a는 name에 'Kim'을 가지고 있는 상태이기 때문)

2. 함수가 안들어가요 엉엉

위에 0번 문제에서 Student라는 부모에 sayHi라는 함수를 하나 추가하라고 했죠?

그래서 sayHi()라고 사용하면 "안녕 나는 ~~이야" 라고 내 이름을 출력해주는 함수를 prototype에 추가했습니다.

하단처럼 만들었는데 의도한 대로 이름이 출력되지 않고 있습니다.

원인은 무엇일까요?

function Student(이름, 나이){
  this.name = 이름;
  this.age = 나이;
}

Student.prototype.sayHi = () => {
    console.log('안녕 나는 ' + this.name + '이야');
  }
var 학생1 = new Student('Kim', 20);

학생1.sayHi(); //왜 이 코드가 제대로 안나오죠?
 

**➡️화살표 함수로 만들었기 때문에 this.name이 constructor Student의 name이 아니기 때문이다.**

SayHi() 라는 함수를 prototype에 추가할 때 arrow function을 사용했다. 결론부터 말하자면 arrow function은 그냥 일반 function 대체품이 아니다. arrow function은 this 를 바깥에 있는 this를 그대로 사용하고 싶을 때 쓰는 함수라 했다.

암튼 sayHi() 함수를 만들 때 arrow function을 사용해서 내부에 있던 this 값이 이상해진거다.

Student.prototype.sayHi = () => {
	console.log(this); // {window}
}

window가 출력된다(strict mode에선 undefined). arrow function은 그냥 바깥 아메두나 있던 값을 가져와서 사용하기 때문이다. Student 함수에서 this는 바깥의 this인 window고, 그 window를 저기 화살표 함수 안에 적용했으니까 this가 window다.

(**object안에 들어있는 함수 안에 있는 this****함수를 부른 object**가 된다)

3. 모든 array에 적용할 수 있는 함수를 직접 새로 만들려면 어떻게 해야할까요?

모든 array에 붙일 수 있는,

array 내에 있는 3이라는 값을 제거해주는 유용한 함수를 하나 만들고 싶습니다.

var arr = [1,2,3];
arr.remove3();

console.log(arr); //[1,2]

이렇게 array뒤에 붙이기만 하면 array 내의 3이라는 모든 숫자 자료들이 삭제됩니다.

멋있게 이름은 remove3() 이라고 하겠습니다.

remove3()함수는 어떻게, 어디에 만들어야 모든 array에 쓸 수 있을까요?

**➡️Array.prototype.remove3 = function(){ ... } 에 만들어야 한다.**

Array.prototype.remove3 = function(){
	return this.filter(v => v !== 3)
}

애플코딩 풀이

모든 array 자로형은 부모가 ARray로 부터 new Array() 이런 식으로 만들어지기 때문에 Array라는 부모의 prototype에 있는 pop(), sort(), push(), ... 이런 함수들을 자유롭게 가져다쓸 수 있다.

그러면 우리도 Array의 prototype에 remove3이라는 함수를 하나 추가해주면 된다.

Array.prototype.remove3 = function(){
    this 에서 3을 찾아서 제거해주세요
}

구현해보자.

Array.prototype.remove3 = function(){
  for (var i = 0; i < this.length; i++) {
    if ( this[i] === 3 ) {
      this.splice(i,1);
    }
  }
};

var arr = [1,2,3,4];
arr.remove3();

console.log(arr); //[1,2,4]

객체지향1. Object 생성기계인 constructor를 만들어 써보자

constructor 문법의 용도

1. Object를 마구 복사하고 싶을 때 사용(별로 쓸데없음)

비슷한 object를 여러개 만들 때, 오브젝트 복사를 도와준다.

var 학생1 = { name: 'Kim', age: 15 }
var 학생2 = { name: 'Kim', age: 15 }
var 학생3 = { name: 'Kim', age: 15 }
...

비슷한 학생 object를 여러개 만들려면, **contstructor라는 object 생성 기계**를 만들자.

constructor는 function 키워드를 빌려서 만든다. 함수와 다르다는 걸 보여주기 위해 관습적으로 첫글자를 대문자로 쓴다.

function Student(){ ... }

일단 알아보기 쉽게 한글인 기계 로 쓰자.

function 기계(){ // 이것은 constructor
	this.name = 'Kim';
    this.age = 15;        
}

이게 constructor이다. 이걸 쓰면 object 마구 쓰기 가능하다.

new 기계(); // 이러면 여기에 Object가 뽑힌다.

기계를 만드려면 **this**라는 키워드가 필요하다. 여기서 this는 **새로 생성되는 object**를 뜻한다.

this.name은 새로 생성되는 오브젝트의 name에 'Kim'이라는 값을 대입해주세요,

this.age는 새로 생성되는 오브젝트의 age에 15라는 값을 대입해주세요, 라는 의미다.

즉, 새로 생성되는 object에 값을 부여할 수 있다.

그럼 한 번 오브젝트를 뽑아보자.

var 학생1 = new 기계();
console.log(학생1); // 기계 {name: 'Kim', age: 15}

이러면 이제 학생1이라는 object가 뽑힌다. **'기계'는 이 object를 만든 constructor 이름**이다.

여러 학생을 만드려면 반복문을 돌려서 만들어도 된다.

object 안에 내용이 많을 수록 이득이다.

Q. 기계로 생성되는 모든 학생 object에 sayHi()함수도 추가하고 싶어요

학생1.sayHi(); // '안녕하세요 Kim 입니다' 출력되기

구현하려면 object에 함수를 추가하면 된다.

var 학생1 = {
	name: 'Kim',
    age: 15,
    sayHi: function(){
        console.log('안녕하세요 ' + this.name + ' 입니다');
    }
}

이게 모든 학생들에게도 뜨게하고 싶다면, 학생1에 하드코딩하는게아니라 constructor 기계에 추가하면 된다.

function 기계(){
    this.name = 'Kim';
    this.age = 15;
    this.sayHi = function(){
        console.log('안녕하세요 ', this.name + ' 입니다');
    }
}

이제 이 함수를 실행하는 모든 학생들에게 sayHi함수를 쓸 수 있다.

이처럼 **문자나 함수나 별걸 다 넣어서 오브젝트 생성기계를 만들 수 있다**.

Q. 기계로 학생을 뽑을 때 name을 다르게 설정해주고 싶어요

function 기계(구멍){
    this.name = 구멍;
    this.age = 15;
    this.sayHi = function(){
        console.log('안녕하세요 ', this.name + ' 입니다');
    }
}

함수의 파라미터로 받을 수 있는 것처럼 **함수에 파라미터를 뚫어서** 구멍에서 뭔갈 받아서 쓸 수 있다.

function 기계(이름){
    this.name = 이름;
    this.age = 15;
    this.sayHi = function(){
        console.log('안녕하세요 ', this.name + ' 입니다');
    }
}
기계('Park'); // 새로운 object를 만들 때 이름자리에 Park 넣어서 만들어줌

그럼 학생 오브젝트를 생성해보자.

var 학생1 = new 기계('Park');
console.log(학생1); // 기계 {name: 'Park', age:15, sayHi: f}
학생1.sayHi(); // 안녕하세요 Park 입니다

var 학생2 = new 기계();
console.log(학생2); // 기계 {name: undefined, age:15, sayHi: f}

학생2는 name이 undefined가 나온다. 왜냐하면 함수에 파라미터를 주지 않으면 undefined가 되기 때문이다.

파라미터를 여러개 줄 수도 있다.

function 기계(이름, 나이){
    this.name = 이름;
    this.age = 나이;
    this.sayHi = function(){
        console.log('안녕하세요 ', this.name + ' 입니다');
    }
}

instane

this = 기계에서 새로생성되는 오브젝트

constructor(생성자)

object 생성기계

간단 연습문제

쇼핑몰에 쓸 상품데이터를 오브젝트로 여러 개 만들고 싶습니다. 그래서 하드코딩해봤는데

var product1 = { name : 'shirts', price : 50000 };
var product2 = { name : 'pants', price : 60000 };

앞으로 몇십개를 더 만들어야해서 하드코딩은 그만두고 constructor를 만들어서 오브젝트를 뽑아내려고 합니다.

Q1. 위처럼 생긴 상품오브젝트들을 뽑아낼 수 있는 constructor를 제작해보세요.그리고 실제 상품 두개를 뽑아보십시오.

function product(name, price){
    this.name = name;
    this.price = price;
}
var product1 = product('shirts', 50000);
var product2 = product('pants', 60000);

Q2. 상품마다 부가세() 라는 내부 함수를 실행하면 콘솔창에 상품가격 \* 10% 만큼의 부가세금액이 출력되도록 하고 싶으면 constructor를 어떻게 수정해야할까요?

예를 들면 product1.부가세() 이렇게 쓰면 콘솔창에 5000이 출력되어야합니다.

function Product(name, price){
    this.name = name;
    this.price = price;
    this.부가세 = function(){
        console.log(this.price * 0.1);
    }
}
var product1 = new Product('shirts', 50000);
var product2 = new Product('pants', 60000);

객체지향2. prototype(기계 유전자, 원형)

prototype를 사용해서 <u>상속</u>기능 만들기

기계(부모, constructor)를 사용해서, 기계가 가지고 있는 name, age, sayHi 등 속성들을 학생들(자식, instance)물려받았다.

이렇게 부모의 속성을 자식이 물려받는 기능이 하나 더 있다. prototype이다. 이건 **자바스크립트에만 있는 문법**이다.

constructor(기계)를 만들면 prototype이라는 공간이 자동으로 생긴다. 한 번 확인해보자.

![](.\images\07.png)

만든 적도 없는데 생겨있다! 얘가 바로 기계 유전자다.

내가 키가 큰 이유는 부모의 키 큰 유전자를 받았기 떄문이다. prototype도 기계의 유전자다. 그래서 **prototype에 값을 추가하면 모든 자식들이 물려받을 수 있다**.

function 기계(이름, 나이){
    this.name = 이름;
    this.age = 나이;
    this.sayHi = function(){
        console.log('안녕하세요 ', this.name + ' 입니다');
    }
}

기계.prototype.gender = '남';

var 학생1 = new 기계('Park');

{기계.prototype} 오브젝트에 'gender'는 '남'인 key값을 추가한거다.

![](.\images\08.png)

학생1을 콘솔해보면 gender이 없다. 안보이지만 gender 속성을 가지고 있다. 신기해!

prototype의 원리

1. 왜 자식은 부모 유전자에 등록된 값을 사용가능한가

원리는 그냥 자바스크립트가 그렇게 동작한다고 알면 된다. 자바스크립트는 오브젝트를 이 순서로 해석하고 자료를 출력한다.

학생1.gender;
  1. 학생1이 직접 gender를 가지고 있는가? (가지고 있으면 출력, 없으면 2로 이동)
  2. 그럼 학생1의 부모 유전자(기계.prototype)가 gender를 가지고 있는가? (가지고 있으면 출력)

즉, **내가 gender가 없으면 부모 유전자에서 찾는구나~** 생각하자!

2. toString, sort 등 자바스크립트 내장함수를 사용가능한 이유

toString()

  • Object/Array에 붙일 수 있는 내장함수
[1,2,3].toString(); // "1,2,3"
학생1.toString(); // "[Object object]"

array에 push, sort, toString, ... 등 내장함수를 쓸 수 있다. 대체 어떻게 해놨길래 모든 Object가 내장함수를 쓸 수 있는 걸까? 학생1을 출력하면 toString이라는 메서드는 없는데 말이다.

그러면 자바스크립트에서 오브젝트를 해석하는 순서를 다시 봐야한다.

  1. 학생1이 toString()을 가지고 있는가?
  2. 그럼 부모 유전자에 있는가?
  3. 그럼 부모의 부모 유전자에 있는가?
  4. ...

컴퓨터는 실제 내부적으로 array를 이렇게 만든다.

var arr = [1,2,3];
var arr = new Array(1,2,3);

위와 아래는 동일하다. new 키워드를 만들면 기계로부터 오브젝트를 하나 뽑아낸다. 즉 array 만드는 기계로부터 하나 뽑은거다. arr은 이제 Array 기계가 가지고 있는 모든 기능들을 상속받는다. 부모 유전자에 sort, toString, map, ... 등 모든 내장함수를 가지고 있어서 오브젝트도 쓸 수 있는 거다. arr에 sort 이런거를 부여한 적이 없는데도 말이다.

확인해보고 싶으면 Array.prototype을 입력해서 Array의 유전자를 확인해보면 된다. map, sort, 등 모든 내장함수가 다 들어있다.

메서드를 구글에 검색하면 MDN에 Array.prototype.sort()라고 뜬다. Array.prototype! 부모 유전자에 sort함수가 있다! 이제 이해가 가나요?

Object도 마찬가지다.

var obj = { name: 'Kim'};
var obj = new Object();

위 코드는 동일하다. 모든 object 자료형은 Object 부모를 이용해 이렇게 만든다. 그리고 부모유전자를 올라가서 찾아본다.

  1. 학생1 (toString이 없네)
  2. 기계.prototype (toString이 없네)
  3. Object.prototype (toString이 있네! -> 실행)

prototype의 특징 몇가지

1. prototype은 함수(기계)에만 몰래 생성된다

var arr = [1,2,3];

![](.\images\09.png)

Array(기계)에는 있는데, arr에는 prototype이 없다고 뜬다.

2. 내 부모 유전자(부모의 prototype)를 검사하고 싶다면 '__ proto __'

![](.\images\10.png)

3. __ prototype __ 를 이용해 부모님 강제 등록하기

var 부모 = { name: 'Kim'};
var 자식 = {};
자식.__proto__ = 부모;

자식.name; // 'Kim'

나의 부모유전자는 이걸로 해주세요~ 라고 자식에서 지정할 수 있다.

4. 콘솔창에서 알려주는 prototype chain

자식에서 부모의 유전자를 보고 싶다면 __ proto __ 에서 볼 수 있다.

학생1의 부모는 기계니까 기계의 유전자가 보인다.

![](.\images\11.png)

그리고 기계의 부모는 Object 생성자다. 그래서 Object의 유전자가 보인다.

![](.\images\12.png)

constructor, prototype 연습문제

0. 오브젝트 자료 여러개를 만들고 싶습니다.

제일 잘하는게 하드코딩이기 때문에 하드코딩해봤습니다.

var 학생1 = { name : 'Kim', age : 20 }
var 학생2 = { name : 'Park', age : 21 }
var 학생3 = { name : 'Lee', age : 22 }

하드코딩해서 3개를 만들긴 했는데 앞으로 만들일이 더 많이 생길 것 같아서 constructor를 제작하려고 합니다.

**constructor문법을 사용해서 위의 오브젝트와 똑같은 오브젝트 3개를 한번 뽑아보십시오.**

**+ 여기에 학생1.sayHi()라고 사용하면 "안녕 나는 Kim이야" 라는 글자가 콘솔창에 나오도록 sayHi()라는 함수도 constructor 안에 추가해보세요.**

➡️

function Student (name, age){
    this.name = name;
    this.age = age;
    this.sayHi: function(){
        console.log('안녕 나는' + this.name + '이야')
    }
}

var 학생1 = new Student('Kim', 20);
var 학생2 = new Student('Park', 21);
var 학생3 = new Student('Lee', 22);

1. 다음 코드의 출력 결과는 무엇일까요?

function Parent(){
  this.name = 'Kim';
}
var a = new Parent();

a.__proto__.name = 'Park';
console.log(a.name)

**➡️ 'Kim'**

첫 4 줄에 의해서 a = {name: 'Kim'}이 되고,

a.__ proto __.name = 'Park'; 이건 **부모 prototype에 {name: 'Park'} 이걸 추가하라는 뜻**이다.

그럼 이제 a.name 이라고 사용했을 때,

**내가 직접 가지고 있는 {name: 'Kim'}** 이걸 우선 출력해준다. (이미 a는 name에 'Kim'을 가지고 있는 상태이기 때문)

2. 함수가 안들어가요 엉엉

위에 0번 문제에서 Student라는 부모에 sayHi라는 함수를 하나 추가하라고 했죠?

그래서 sayHi()라고 사용하면 "안녕 나는 ~~이야" 라고 내 이름을 출력해주는 함수를 prototype에 추가했습니다.

하단처럼 만들었는데 의도한 대로 이름이 출력되지 않고 있습니다.

원인은 무엇일까요?

function Student(이름, 나이){
  this.name = 이름;
  this.age = 나이;
}

Student.prototype.sayHi = () => {
    console.log('안녕 나는 ' + this.name + '이야');
  }
var 학생1 = new Student('Kim', 20);

학생1.sayHi(); //왜 이 코드가 제대로 안나오죠?
 

**➡️화살표 함수로 만들었기 때문에 this.name이 constructor Student의 name이 아니기 때문이다.**

SayHi() 라는 함수를 prototype에 추가할 때 arrow function을 사용했다. 결론부터 말하자면 arrow function은 그냥 일반 function 대체품이 아니다. arrow function은 this 를 바깥에 있는 this를 그대로 사용하고 싶을 때 쓰는 함수라 했다.

암튼 sayHi() 함수를 만들 때 arrow function을 사용해서 내부에 있던 this 값이 이상해진거다.

Student.prototype.sayHi = () => {
	console.log(this); // {window}
}

window가 출력된다(strict mode에선 undefined). arrow function은 그냥 바깥 아메두나 있던 값을 가져와서 사용하기 때문이다. Student 함수에서 this는 바깥의 this인 window고, 그 window를 저기 화살표 함수 안에 적용했으니까 this가 window다.

(**object안에 들어있는 함수 안에 있는 this****함수를 부른 object**가 된다)

3. 모든 array에 적용할 수 있는 함수를 직접 새로 만들려면 어떻게 해야할까요?

모든 array에 붙일 수 있는,

array 내에 있는 3이라는 값을 제거해주는 유용한 함수를 하나 만들고 싶습니다.

var arr = [1,2,3];
arr.remove3();

console.log(arr); //[1,2]

이렇게 array뒤에 붙이기만 하면 array 내의 3이라는 모든 숫자 자료들이 삭제됩니다.

멋있게 이름은 remove3() 이라고 하겠습니다.

remove3()함수는 어떻게, 어디에 만들어야 모든 array에 쓸 수 있을까요?

**➡️Array.prototype.remove3 = function(){ ... } 에 만들어야 한다.**

Array.prototype.remove3 = function(){
	return this.filter(v => v !== 3)
}

애플코딩 풀이

모든 array 자로형은 부모가 ARray로 부터 new Array() 이런 식으로 만들어지기 때문에 Array라는 부모의 prototype에 있는 pop(), sort(), push(), ... 이런 함수들을 자유롭게 가져다쓸 수 있다.

그러면 우리도 Array의 prototype에 remove3이라는 함수를 하나 추가해주면 된다.

Array.prototype.remove3 = function(){
    this 에서 3을 찾아서 제거해주세요
}

구현해보자.

Array.prototype.remove3 = function(){
  for (var i = 0; i < this.length; i++) {
    if ( this[i] === 3 ) {
      this.splice(i,1);
    }
  }
};

var arr = [1,2,3,4];
arr.remove3();

console.log(arr); //[1,2,4]

객체지향1. Object 생성기계인 constructor를 만들어 써보자

constructor 문법의 용도

1. Object를 마구 복사하고 싶을 때 사용(별로 쓸데없음)

비슷한 object를 여러개 만들 때, 오브젝트 복사를 도와준다.

var 학생1 = { name: 'Kim', age: 15 }
var 학생2 = { name: 'Kim', age: 15 }
var 학생3 = { name: 'Kim', age: 15 }
...

비슷한 학생 object를 여러개 만들려면, **contstructor라는 object 생성 기계**를 만들자.

constructor는 function 키워드를 빌려서 만든다. 함수와 다르다는 걸 보여주기 위해 관습적으로 첫글자를 대문자로 쓴다.

function Student(){ ... }

일단 알아보기 쉽게 한글인 기계 로 쓰자.

function 기계(){ // 이것은 constructor
	this.name = 'Kim';
    this.age = 15;        
}

이게 constructor이다. 이걸 쓰면 object 마구 쓰기 가능하다.

new 기계(); // 이러면 여기에 Object가 뽑힌다.

기계를 만드려면 **this**라는 키워드가 필요하다. 여기서 this는 **새로 생성되는 object**를 뜻한다.

this.name은 새로 생성되는 오브젝트의 name에 'Kim'이라는 값을 대입해주세요,

this.age는 새로 생성되는 오브젝트의 age에 15라는 값을 대입해주세요, 라는 의미다.

즉, 새로 생성되는 object에 값을 부여할 수 있다.

그럼 한 번 오브젝트를 뽑아보자.

var 학생1 = new 기계();
console.log(학생1); // 기계 {name: 'Kim', age: 15}

이러면 이제 학생1이라는 object가 뽑힌다. **'기계'는 이 object를 만든 constructor 이름**이다.

여러 학생을 만드려면 반복문을 돌려서 만들어도 된다.

object 안에 내용이 많을 수록 이득이다.

Q. 기계로 생성되는 모든 학생 object에 sayHi()함수도 추가하고 싶어요

학생1.sayHi(); // '안녕하세요 Kim 입니다' 출력되기

구현하려면 object에 함수를 추가하면 된다.

var 학생1 = {
	name: 'Kim',
    age: 15,
    sayHi: function(){
        console.log('안녕하세요 ' + this.name + ' 입니다');
    }
}

이게 모든 학생들에게도 뜨게하고 싶다면, 학생1에 하드코딩하는게아니라 constructor 기계에 추가하면 된다.

function 기계(){
    this.name = 'Kim';
    this.age = 15;
    this.sayHi = function(){
        console.log('안녕하세요 ', this.name + ' 입니다');
    }
}

이제 이 함수를 실행하는 모든 학생들에게 sayHi함수를 쓸 수 있다.

이처럼 **문자나 함수나 별걸 다 넣어서 오브젝트 생성기계를 만들 수 있다**.

Q. 기계로 학생을 뽑을 때 name을 다르게 설정해주고 싶어요

function 기계(구멍){
    this.name = 구멍;
    this.age = 15;
    this.sayHi = function(){
        console.log('안녕하세요 ', this.name + ' 입니다');
    }
}

함수의 파라미터로 받을 수 있는 것처럼 **함수에 파라미터를 뚫어서** 구멍에서 뭔갈 받아서 쓸 수 있다.

function 기계(이름){
    this.name = 이름;
    this.age = 15;
    this.sayHi = function(){
        console.log('안녕하세요 ', this.name + ' 입니다');
    }
}
기계('Park'); // 새로운 object를 만들 때 이름자리에 Park 넣어서 만들어줌

그럼 학생 오브젝트를 생성해보자.

var 학생1 = new 기계('Park');
console.log(학생1); // 기계 {name: 'Park', age:15, sayHi: f}
학생1.sayHi(); // 안녕하세요 Park 입니다

var 학생2 = new 기계();
console.log(학생2); // 기계 {name: undefined, age:15, sayHi: f}

학생2는 name이 undefined가 나온다. 왜냐하면 함수에 파라미터를 주지 않으면 undefined가 되기 때문이다.

파라미터를 여러개 줄 수도 있다.

function 기계(이름, 나이){
    this.name = 이름;
    this.age = 나이;
    this.sayHi = function(){
        console.log('안녕하세요 ', this.name + ' 입니다');
    }
}

instane

this = 기계에서 새로생성되는 오브젝트

constructor(생성자)

object 생성기계

간단 연습문제

쇼핑몰에 쓸 상품데이터를 오브젝트로 여러 개 만들고 싶습니다. 그래서 하드코딩해봤는데

var product1 = { name : 'shirts', price : 50000 };
var product2 = { name : 'pants', price : 60000 };

앞으로 몇십개를 더 만들어야해서 하드코딩은 그만두고 constructor를 만들어서 오브젝트를 뽑아내려고 합니다.

Q1. 위처럼 생긴 상품오브젝트들을 뽑아낼 수 있는 constructor를 제작해보세요.그리고 실제 상품 두개를 뽑아보십시오.

function product(name, price){
    this.name = name;
    this.price = price;
}
var product1 = product('shirts', 50000);
var product2 = product('pants', 60000);

Q2. 상품마다 부가세() 라는 내부 함수를 실행하면 콘솔창에 상품가격 \* 10% 만큼의 부가세금액이 출력되도록 하고 싶으면 constructor를 어떻게 수정해야할까요?

예를 들면 product1.부가세() 이렇게 쓰면 콘솔창에 5000이 출력되어야합니다.

function Product(name, price){
    this.name = name;
    this.price = price;
    this.부가세 = function(){
        console.log(this.price * 0.1);
    }
}
var product1 = new Product('shirts', 50000);
var product2 = new Product('pants', 60000);

객체지향2. prototype(기계 유전자, 원형)

prototype를 사용해서 <u>상속</u>기능 만들기

기계(부모, constructor)를 사용해서, 기계가 가지고 있는 name, age, sayHi 등 속성들을 학생들(자식, instance)물려받았다.

이렇게 부모의 속성을 자식이 물려받는 기능이 하나 더 있다. prototype이다. 이건 **자바스크립트에만 있는 문법**이다.

constructor(기계)를 만들면 prototype이라는 공간이 자동으로 생긴다. 한 번 확인해보자.

![](.\images\07.png)

만든 적도 없는데 생겨있다! 얘가 바로 기계 유전자다.

내가 키가 큰 이유는 부모의 키 큰 유전자를 받았기 떄문이다. prototype도 기계의 유전자다. 그래서 **prototype에 값을 추가하면 모든 자식들이 물려받을 수 있다**.

function 기계(이름, 나이){
    this.name = 이름;
    this.age = 나이;
    this.sayHi = function(){
        console.log('안녕하세요 ', this.name + ' 입니다');
    }
}

기계.prototype.gender = '남';

var 학생1 = new 기계('Park');

{기계.prototype} 오브젝트에 'gender'는 '남'인 key값을 추가한거다.

![](.\images\08.png)

학생1을 콘솔해보면 gender이 없다. 안보이지만 gender 속성을 가지고 있다. 신기해!

prototype의 원리

1. 왜 자식은 부모 유전자에 등록된 값을 사용가능한가

원리는 그냥 자바스크립트가 그렇게 동작한다고 알면 된다. 자바스크립트는 오브젝트를 이 순서로 해석하고 자료를 출력한다.

학생1.gender;
  1. 학생1이 직접 gender를 가지고 있는가? (가지고 있으면 출력, 없으면 2로 이동)
  2. 그럼 학생1의 부모 유전자(기계.prototype)가 gender를 가지고 있는가? (가지고 있으면 출력)

즉, **내가 gender가 없으면 부모 유전자에서 찾는구나~** 생각하자!

2. toString, sort 등 자바스크립트 내장함수를 사용가능한 이유

toString()

  • Object/Array에 붙일 수 있는 내장함수
[1,2,3].toString(); // "1,2,3"
학생1.toString(); // "[Object object]"

array에 push, sort, toString, ... 등 내장함수를 쓸 수 있다. 대체 어떻게 해놨길래 모든 Object가 내장함수를 쓸 수 있는 걸까? 학생1을 출력하면 toString이라는 메서드는 없는데 말이다.

그러면 자바스크립트에서 오브젝트를 해석하는 순서를 다시 봐야한다.

  1. 학생1이 toString()을 가지고 있는가?
  2. 그럼 부모 유전자에 있는가?
  3. 그럼 부모의 부모 유전자에 있는가?
  4. ...

컴퓨터는 실제 내부적으로 array를 이렇게 만든다.

var arr = [1,2,3];
var arr = new Array(1,2,3);

위와 아래는 동일하다. new 키워드를 만들면 기계로부터 오브젝트를 하나 뽑아낸다. 즉 array 만드는 기계로부터 하나 뽑은거다. arr은 이제 Array 기계가 가지고 있는 모든 기능들을 상속받는다. 부모 유전자에 sort, toString, map, ... 등 모든 내장함수를 가지고 있어서 오브젝트도 쓸 수 있는 거다. arr에 sort 이런거를 부여한 적이 없는데도 말이다.

확인해보고 싶으면 Array.prototype을 입력해서 Array의 유전자를 확인해보면 된다. map, sort, 등 모든 내장함수가 다 들어있다.

메서드를 구글에 검색하면 MDN에 Array.prototype.sort()라고 뜬다. Array.prototype! 부모 유전자에 sort함수가 있다! 이제 이해가 가나요?

Object도 마찬가지다.

var obj = { name: 'Kim'};
var obj = new Object();

위 코드는 동일하다. 모든 object 자료형은 Object 부모를 이용해 이렇게 만든다. 그리고 부모유전자를 올라가서 찾아본다.

  1. 학생1 (toString이 없네)
  2. 기계.prototype (toString이 없네)
  3. Object.prototype (toString이 있네! -> 실행)

prototype의 특징 몇가지

1. prototype은 함수(기계)에만 몰래 생성된다

var arr = [1,2,3];

![](.\images\09.png)

Array(기계)에는 있는데, arr에는 prototype이 없다고 뜬다.

2. 내 부모 유전자(부모의 prototype)를 검사하고 싶다면 '__ proto __'

![](.\images\10.png)

3. __ prototype __ 를 이용해 부모님 강제 등록하기

var 부모 = { name: 'Kim'};
var 자식 = {};
자식.__proto__ = 부모;

자식.name; // 'Kim'

나의 부모유전자는 이걸로 해주세요~ 라고 자식에서 지정할 수 있다.

4. 콘솔창에서 알려주는 prototype chain

자식에서 부모의 유전자를 보고 싶다면 __ proto __ 에서 볼 수 있다.

학생1의 부모는 기계니까 기계의 유전자가 보인다.

![](.\images\11.png)

그리고 기계의 부모는 Object 생성자다. 그래서 Object의 유전자가 보인다.

![](.\images\12.png)

constructor, prototype 연습문제

0. 오브젝트 자료 여러개를 만들고 싶습니다.

제일 잘하는게 하드코딩이기 때문에 하드코딩해봤습니다.

var 학생1 = { name : 'Kim', age : 20 }
var 학생2 = { name : 'Park', age : 21 }
var 학생3 = { name : 'Lee', age : 22 }

하드코딩해서 3개를 만들긴 했는데 앞으로 만들일이 더 많이 생길 것 같아서 constructor를 제작하려고 합니다.

**constructor문법을 사용해서 위의 오브젝트와 똑같은 오브젝트 3개를 한번 뽑아보십시오.**

**+ 여기에 학생1.sayHi()라고 사용하면 "안녕 나는 Kim이야" 라는 글자가 콘솔창에 나오도록 sayHi()라는 함수도 constructor 안에 추가해보세요.**

➡️

function Student (name, age){
    this.name = name;
    this.age = age;
    this.sayHi: function(){
        console.log('안녕 나는' + this.name + '이야')
    }
}

var 학생1 = new Student('Kim', 20);
var 학생2 = new Student('Park', 21);
var 학생3 = new Student('Lee', 22);

1. 다음 코드의 출력 결과는 무엇일까요?

function Parent(){
  this.name = 'Kim';
}
var a = new Parent();

a.__proto__.name = 'Park';
console.log(a.name)

**➡️ 'Kim'**

첫 4 줄에 의해서 a = {name: 'Kim'}이 되고,

a.__ proto __.name = 'Park'; 이건 **부모 prototype에 {name: 'Park'} 이걸 추가하라는 뜻**이다.

그럼 이제 a.name 이라고 사용했을 때,

**내가 직접 가지고 있는 {name: 'Kim'}** 이걸 우선 출력해준다. (이미 a는 name에 'Kim'을 가지고 있는 상태이기 때문)

2. 함수가 안들어가요 엉엉

위에 0번 문제에서 Student라는 부모에 sayHi라는 함수를 하나 추가하라고 했죠?

그래서 sayHi()라고 사용하면 "안녕 나는 ~~이야" 라고 내 이름을 출력해주는 함수를 prototype에 추가했습니다.

하단처럼 만들었는데 의도한 대로 이름이 출력되지 않고 있습니다.

원인은 무엇일까요?

function Student(이름, 나이){
  this.name = 이름;
  this.age = 나이;
}

Student.prototype.sayHi = () => {
    console.log('안녕 나는 ' + this.name + '이야');
  }
var 학생1 = new Student('Kim', 20);

학생1.sayHi(); //왜 이 코드가 제대로 안나오죠?
 

**➡️화살표 함수로 만들었기 때문에 this.name이 constructor Student의 name이 아니기 때문이다.**

SayHi() 라는 함수를 prototype에 추가할 때 arrow function을 사용했다. 결론부터 말하자면 arrow function은 그냥 일반 function 대체품이 아니다. arrow function은 this 를 바깥에 있는 this를 그대로 사용하고 싶을 때 쓰는 함수라 했다.

암튼 sayHi() 함수를 만들 때 arrow function을 사용해서 내부에 있던 this 값이 이상해진거다.

Student.prototype.sayHi = () => {
	console.log(this); // {window}
}

window가 출력된다(strict mode에선 undefined). arrow function은 그냥 바깥 아메두나 있던 값을 가져와서 사용하기 때문이다. Student 함수에서 this는 바깥의 this인 window고, 그 window를 저기 화살표 함수 안에 적용했으니까 this가 window다.

(**object안에 들어있는 함수 안에 있는 this****함수를 부른 object**가 된다)

3. 모든 array에 적용할 수 있는 함수를 직접 새로 만들려면 어떻게 해야할까요?

모든 array에 붙일 수 있는,

array 내에 있는 3이라는 값을 제거해주는 유용한 함수를 하나 만들고 싶습니다.

var arr = [1,2,3];
arr.remove3();

console.log(arr); //[1,2]

이렇게 array뒤에 붙이기만 하면 array 내의 3이라는 모든 숫자 자료들이 삭제됩니다.

멋있게 이름은 remove3() 이라고 하겠습니다.

remove3()함수는 어떻게, 어디에 만들어야 모든 array에 쓸 수 있을까요?

**➡️Array.prototype.remove3 = function(){ ... } 에 만들어야 한다.**

Array.prototype.remove3 = function(){
	return this.filter(v => v !== 3)
}

애플코딩 풀이

모든 array 자로형은 부모가 ARray로 부터 new Array() 이런 식으로 만들어지기 때문에 Array라는 부모의 prototype에 있는 pop(), sort(), push(), ... 이런 함수들을 자유롭게 가져다쓸 수 있다.

그러면 우리도 Array의 prototype에 remove3이라는 함수를 하나 추가해주면 된다.

Array.prototype.remove3 = function(){
    this 에서 3을 찾아서 제거해주세요
}

구현해보자.

Array.prototype.remove3 = function(){
  for (var i = 0; i < this.length; i++) {
    if ( this[i] === 3 ) {
      this.splice(i,1);
    }
  }
};

var arr = [1,2,3,4];
arr.remove3();

console.log(arr); //[1,2,4]

객체지향1. Object 생성기계인 constructor를 만들어 써보자

constructor 문법의 용도

1. Object를 마구 복사하고 싶을 때 사용(별로 쓸데없음)

비슷한 object를 여러개 만들 때, 오브젝트 복사를 도와준다.

var 학생1 = { name: 'Kim', age: 15 }
var 학생2 = { name: 'Kim', age: 15 }
var 학생3 = { name: 'Kim', age: 15 }
...

비슷한 학생 object를 여러개 만들려면, **contstructor라는 object 생성 기계**를 만들자.

constructor는 function 키워드를 빌려서 만든다. 함수와 다르다는 걸 보여주기 위해 관습적으로 첫글자를 대문자로 쓴다.

function Student(){ ... }

일단 알아보기 쉽게 한글인 기계 로 쓰자.

function 기계(){ // 이것은 constructor
	this.name = 'Kim';
    this.age = 15;        
}

이게 constructor이다. 이걸 쓰면 object 마구 쓰기 가능하다.

new 기계(); // 이러면 여기에 Object가 뽑힌다.

기계를 만드려면 **this**라는 키워드가 필요하다. 여기서 this는 **새로 생성되는 object**를 뜻한다.

this.name은 새로 생성되는 오브젝트의 name에 'Kim'이라는 값을 대입해주세요,

this.age는 새로 생성되는 오브젝트의 age에 15라는 값을 대입해주세요, 라는 의미다.

즉, 새로 생성되는 object에 값을 부여할 수 있다.

그럼 한 번 오브젝트를 뽑아보자.

var 학생1 = new 기계();
console.log(학생1); // 기계 {name: 'Kim', age: 15}

이러면 이제 학생1이라는 object가 뽑힌다. **'기계'는 이 object를 만든 constructor 이름**이다.

여러 학생을 만드려면 반복문을 돌려서 만들어도 된다.

object 안에 내용이 많을 수록 이득이다.

Q. 기계로 생성되는 모든 학생 object에 sayHi()함수도 추가하고 싶어요

학생1.sayHi(); // '안녕하세요 Kim 입니다' 출력되기

구현하려면 object에 함수를 추가하면 된다.

var 학생1 = {
	name: 'Kim',
    age: 15,
    sayHi: function(){
        console.log('안녕하세요 ' + this.name + ' 입니다');
    }
}

이게 모든 학생들에게도 뜨게하고 싶다면, 학생1에 하드코딩하는게아니라 constructor 기계에 추가하면 된다.

function 기계(){
    this.name = 'Kim';
    this.age = 15;
    this.sayHi = function(){
        console.log('안녕하세요 ', this.name + ' 입니다');
    }
}

이제 이 함수를 실행하는 모든 학생들에게 sayHi함수를 쓸 수 있다.

이처럼 **문자나 함수나 별걸 다 넣어서 오브젝트 생성기계를 만들 수 있다**.

Q. 기계로 학생을 뽑을 때 name을 다르게 설정해주고 싶어요

function 기계(구멍){
    this.name = 구멍;
    this.age = 15;
    this.sayHi = function(){
        console.log('안녕하세요 ', this.name + ' 입니다');
    }
}

함수의 파라미터로 받을 수 있는 것처럼 **함수에 파라미터를 뚫어서** 구멍에서 뭔갈 받아서 쓸 수 있다.

function 기계(이름){
    this.name = 이름;
    this.age = 15;
    this.sayHi = function(){
        console.log('안녕하세요 ', this.name + ' 입니다');
    }
}
기계('Park'); // 새로운 object를 만들 때 이름자리에 Park 넣어서 만들어줌

그럼 학생 오브젝트를 생성해보자.

var 학생1 = new 기계('Park');
console.log(학생1); // 기계 {name: 'Park', age:15, sayHi: f}
학생1.sayHi(); // 안녕하세요 Park 입니다

var 학생2 = new 기계();
console.log(학생2); // 기계 {name: undefined, age:15, sayHi: f}

학생2는 name이 undefined가 나온다. 왜냐하면 함수에 파라미터를 주지 않으면 undefined가 되기 때문이다.

파라미터를 여러개 줄 수도 있다.

function 기계(이름, 나이){
    this.name = 이름;
    this.age = 나이;
    this.sayHi = function(){
        console.log('안녕하세요 ', this.name + ' 입니다');
    }
}

instane

this = 기계에서 새로생성되는 오브젝트

constructor(생성자)

object 생성기계

간단 연습문제

쇼핑몰에 쓸 상품데이터를 오브젝트로 여러 개 만들고 싶습니다. 그래서 하드코딩해봤는데

var product1 = { name : 'shirts', price : 50000 };
var product2 = { name : 'pants', price : 60000 };

앞으로 몇십개를 더 만들어야해서 하드코딩은 그만두고 constructor를 만들어서 오브젝트를 뽑아내려고 합니다.

Q1. 위처럼 생긴 상품오브젝트들을 뽑아낼 수 있는 constructor를 제작해보세요.그리고 실제 상품 두개를 뽑아보십시오.

function product(name, price){
    this.name = name;
    this.price = price;
}
var product1 = product('shirts', 50000);
var product2 = product('pants', 60000);

Q2. 상품마다 부가세() 라는 내부 함수를 실행하면 콘솔창에 상품가격 \* 10% 만큼의 부가세금액이 출력되도록 하고 싶으면 constructor를 어떻게 수정해야할까요?

예를 들면 product1.부가세() 이렇게 쓰면 콘솔창에 5000이 출력되어야합니다.

function Product(name, price){
    this.name = name;
    this.price = price;
    this.부가세 = function(){
        console.log(this.price * 0.1);
    }
}
var product1 = new Product('shirts', 50000);
var product2 = new Product('pants', 60000);

객체지향2. prototype(기계 유전자, 원형)

prototype를 사용해서 <u>상속</u>기능 만들기

기계(부모, constructor)를 사용해서, 기계가 가지고 있는 name, age, sayHi 등 속성들을 학생들(자식, instance)물려받았다.

이렇게 부모의 속성을 자식이 물려받는 기능이 하나 더 있다. prototype이다. 이건 **자바스크립트에만 있는 문법**이다.

constructor(기계)를 만들면 prototype이라는 공간이 자동으로 생긴다. 한 번 확인해보자.

![](.\images\07.png)

만든 적도 없는데 생겨있다! 얘가 바로 기계 유전자다.

내가 키가 큰 이유는 부모의 키 큰 유전자를 받았기 떄문이다. prototype도 기계의 유전자다. 그래서 **prototype에 값을 추가하면 모든 자식들이 물려받을 수 있다**.

function 기계(이름, 나이){
    this.name = 이름;
    this.age = 나이;
    this.sayHi = function(){
        console.log('안녕하세요 ', this.name + ' 입니다');
    }
}

기계.prototype.gender = '남';

var 학생1 = new 기계('Park');

{기계.prototype} 오브젝트에 'gender'는 '남'인 key값을 추가한거다.

![](.\images\08.png)

학생1을 콘솔해보면 gender이 없다. 안보이지만 gender 속성을 가지고 있다. 신기해!

prototype의 원리

1. 왜 자식은 부모 유전자에 등록된 값을 사용가능한가

원리는 그냥 자바스크립트가 그렇게 동작한다고 알면 된다. 자바스크립트는 오브젝트를 이 순서로 해석하고 자료를 출력한다.

학생1.gender;
  1. 학생1이 직접 gender를 가지고 있는가? (가지고 있으면 출력, 없으면 2로 이동)
  2. 그럼 학생1의 부모 유전자(기계.prototype)가 gender를 가지고 있는가? (가지고 있으면 출력)

즉, **내가 gender가 없으면 부모 유전자에서 찾는구나~** 생각하자!

2. toString, sort 등 자바스크립트 내장함수를 사용가능한 이유

toString()

  • Object/Array에 붙일 수 있는 내장함수
[1,2,3].toString(); // "1,2,3"
학생1.toString(); // "[Object object]"

array에 push, sort, toString, ... 등 내장함수를 쓸 수 있다. 대체 어떻게 해놨길래 모든 Object가 내장함수를 쓸 수 있는 걸까? 학생1을 출력하면 toString이라는 메서드는 없는데 말이다.

그러면 자바스크립트에서 오브젝트를 해석하는 순서를 다시 봐야한다.

  1. 학생1이 toString()을 가지고 있는가?
  2. 그럼 부모 유전자에 있는가?
  3. 그럼 부모의 부모 유전자에 있는가?
  4. ...

컴퓨터는 실제 내부적으로 array를 이렇게 만든다.

var arr = [1,2,3];
var arr = new Array(1,2,3);

위와 아래는 동일하다. new 키워드를 만들면 기계로부터 오브젝트를 하나 뽑아낸다. 즉 array 만드는 기계로부터 하나 뽑은거다. arr은 이제 Array 기계가 가지고 있는 모든 기능들을 상속받는다. 부모 유전자에 sort, toString, map, ... 등 모든 내장함수를 가지고 있어서 오브젝트도 쓸 수 있는 거다. arr에 sort 이런거를 부여한 적이 없는데도 말이다.

확인해보고 싶으면 Array.prototype을 입력해서 Array의 유전자를 확인해보면 된다. map, sort, 등 모든 내장함수가 다 들어있다.

메서드를 구글에 검색하면 MDN에 Array.prototype.sort()라고 뜬다. Array.prototype! 부모 유전자에 sort함수가 있다! 이제 이해가 가나요?

Object도 마찬가지다.

var obj = { name: 'Kim'};
var obj = new Object();

위 코드는 동일하다. 모든 object 자료형은 Object 부모를 이용해 이렇게 만든다. 그리고 부모유전자를 올라가서 찾아본다.

  1. 학생1 (toString이 없네)
  2. 기계.prototype (toString이 없네)
  3. Object.prototype (toString이 있네! -> 실행)

prototype의 특징 몇가지

1. prototype은 함수(기계)에만 몰래 생성된다

var arr = [1,2,3];

![](.\images\09.png)

Array(기계)에는 있는데, arr에는 prototype이 없다고 뜬다.

2. 내 부모 유전자(부모의 prototype)를 검사하고 싶다면 '__ proto __'

![](.\images\10.png)

3. __ prototype __ 를 이용해 부모님 강제 등록하기

var 부모 = { name: 'Kim'};
var 자식 = {};
자식.__proto__ = 부모;

자식.name; // 'Kim'

나의 부모유전자는 이걸로 해주세요~ 라고 자식에서 지정할 수 있다.

4. 콘솔창에서 알려주는 prototype chain

자식에서 부모의 유전자를 보고 싶다면 __ proto __ 에서 볼 수 있다.

학생1의 부모는 기계니까 기계의 유전자가 보인다.

![](.\images\11.png)

그리고 기계의 부모는 Object 생성자다. 그래서 Object의 유전자가 보인다.

![](.\images\12.png)

constructor, prototype 연습문제

0. 오브젝트 자료 여러개를 만들고 싶습니다.

제일 잘하는게 하드코딩이기 때문에 하드코딩해봤습니다.

var 학생1 = { name : 'Kim', age : 20 }
var 학생2 = { name : 'Park', age : 21 }
var 학생3 = { name : 'Lee', age : 22 }

하드코딩해서 3개를 만들긴 했는데 앞으로 만들일이 더 많이 생길 것 같아서 constructor를 제작하려고 합니다.

**constructor문법을 사용해서 위의 오브젝트와 똑같은 오브젝트 3개를 한번 뽑아보십시오.**

**+ 여기에 학생1.sayHi()라고 사용하면 "안녕 나는 Kim이야" 라는 글자가 콘솔창에 나오도록 sayHi()라는 함수도 constructor 안에 추가해보세요.**

➡️

function Student (name, age){
    this.name = name;
    this.age = age;
    this.sayHi: function(){
        console.log('안녕 나는' + this.name + '이야')
    }
}

var 학생1 = new Student('Kim', 20);
var 학생2 = new Student('Park', 21);
var 학생3 = new Student('Lee', 22);

1. 다음 코드의 출력 결과는 무엇일까요?

function Parent(){
  this.name = 'Kim';
}
var a = new Parent();

a.__proto__.name = 'Park';
console.log(a.name)

**➡️ 'Kim'**

첫 4 줄에 의해서 a = {name: 'Kim'}이 되고,

a.__ proto __.name = 'Park'; 이건 **부모 prototype에 {name: 'Park'} 이걸 추가하라는 뜻**이다.

그럼 이제 a.name 이라고 사용했을 때,

**내가 직접 가지고 있는 {name: 'Kim'}** 이걸 우선 출력해준다. (이미 a는 name에 'Kim'을 가지고 있는 상태이기 때문)

2. 함수가 안들어가요 엉엉

위에 0번 문제에서 Student라는 부모에 sayHi라는 함수를 하나 추가하라고 했죠?

그래서 sayHi()라고 사용하면 "안녕 나는 ~~이야" 라고 내 이름을 출력해주는 함수를 prototype에 추가했습니다.

하단처럼 만들었는데 의도한 대로 이름이 출력되지 않고 있습니다.

원인은 무엇일까요?

function Student(이름, 나이){
  this.name = 이름;
  this.age = 나이;
}

Student.prototype.sayHi = () => {
    console.log('안녕 나는 ' + this.name + '이야');
  }
var 학생1 = new Student('Kim', 20);

학생1.sayHi(); //왜 이 코드가 제대로 안나오죠?
 

**➡️화살표 함수로 만들었기 때문에 this.name이 constructor Student의 name이 아니기 때문이다.**

SayHi() 라는 함수를 prototype에 추가할 때 arrow function을 사용했다. 결론부터 말하자면 arrow function은 그냥 일반 function 대체품이 아니다. arrow function은 this 를 바깥에 있는 this를 그대로 사용하고 싶을 때 쓰는 함수라 했다.

암튼 sayHi() 함수를 만들 때 arrow function을 사용해서 내부에 있던 this 값이 이상해진거다.

Student.prototype.sayHi = () => {
	console.log(this); // {window}
}

window가 출력된다(strict mode에선 undefined). arrow function은 그냥 바깥 아메두나 있던 값을 가져와서 사용하기 때문이다. Student 함수에서 this는 바깥의 this인 window고, 그 window를 저기 화살표 함수 안에 적용했으니까 this가 window다.

(**object안에 들어있는 함수 안에 있는 this****함수를 부른 object**가 된다)

3. 모든 array에 적용할 수 있는 함수를 직접 새로 만들려면 어떻게 해야할까요?

모든 array에 붙일 수 있는,

array 내에 있는 3이라는 값을 제거해주는 유용한 함수를 하나 만들고 싶습니다.

var arr = [1,2,3];
arr.remove3();

console.log(arr); //[1,2]

이렇게 array뒤에 붙이기만 하면 array 내의 3이라는 모든 숫자 자료들이 삭제됩니다.

멋있게 이름은 remove3() 이라고 하겠습니다.

remove3()함수는 어떻게, 어디에 만들어야 모든 array에 쓸 수 있을까요?

**➡️Array.prototype.remove3 = function(){ ... } 에 만들어야 한다.**

Array.prototype.remove3 = function(){
	return this.filter(v => v !== 3)
}

애플코딩 풀이

모든 array 자로형은 부모가 ARray로 부터 new Array() 이런 식으로 만들어지기 때문에 Array라는 부모의 prototype에 있는 pop(), sort(), push(), ... 이런 함수들을 자유롭게 가져다쓸 수 있다.

그러면 우리도 Array의 prototype에 remove3이라는 함수를 하나 추가해주면 된다.

Array.prototype.remove3 = function(){
    this 에서 3을 찾아서 제거해주세요
}

구현해보자.

Array.prototype.remove3 = function(){
  for (var i = 0; i < this.length; i++) {
    if ( this[i] === 3 ) {
      this.splice(i,1);
    }
  }
};

var arr = [1,2,3,4];
arr.remove3();

console.log(arr); //[1,2,4]
반응형