javascript - 프로토타입(1)

김동하·2020년 9월 20일
0

javascript

목록 보기
18/58

prototype

function GrandMother(){}
GrandMother.prototype.GrandMotherProp = true;
 
function Mother(){}
Mother.prototype = new GrandMother();
 
function Me(){}
Me.prototype = new Mother();

const obj = new Me();
console.log(obj.GrandMotherProp);  // true

총 3개의 객체가 있다. GrandMother, Mother, Me 그리고 순서대로 Me는 Mother를 상속하고 Mother는 GrandMother를 상속한다.

객체 obj는 Me 생성자 함수로 객체를 만들고 GrandMotherProp에 접근하면 true가 나온다. Mother와 Me 에 GrandMotherProp가 없지만 GrandMother으로부터 상속받았기 때문에 obj 객체로 프로퍼티로 접근이 가능하다.

생성자는 기본적으로 함수다. 거기에 new를 붙이면 생성자 함수가 되고 객체를 리턴한다.

(어렵다)

prototype chain

function GrandMother(){}
GrandMother.prototype.GrandMotherProp = true;
 
function Mother(){}
Mother.prototype = new GrandMother();
 
function Me(){}
Me.prototype = new Mother();
Me.prototype.GrandMotherProp = 1;

const obj = new Me();

console.log(obj.GrandMotherProp);  // 1

실행 순서를 보자면 console.log에 담긴 obj 객체에 GrandMotherProp 프로퍼티가 있는지 확인한다. 없으면 obj 객체의 생성자를 알아낸다. Me의 prototype 객체를 살펴서 그 객체의 프로퍼티인GrandMotherProp 값이 1로 할당되었으므로 obj.GrandMotherProp는 1이 출력된다.

(아래는 생활코딩의 객체 지향 프로그래밍 강의를 듣고 정리한 것)

prototype

function Person(name, first, second) {
    this.name = name;
    this.first = first;
    this.second = second;
}

let kim = new Person("kim", 10, 20)
kim.sum = function() {
    return `modified : ${this.first + this.second}`
}
let lee = new Person("lee", 10, 10)
console.log(kim.sum()) // 30
console.log(lee.sum()) // 20

위 코드에서 만약 sum 메서드를 수정하고 싶다면 객체마다 모두 수정해줘야 한다. 생성자 안에서 메서드를 만드는 단점이다. Person이라는 생성자를 통해 만든 객체가 공통적으로 사용할 수 있는 함수, 프로퍼티를 만들면 더 편할 것이다.

Person.prototype.sum = function() {
        return this.first + this.second;
    }

Person이라는 생성자의 prototype을 sum 이라고 정의하는 것이다.

function Person(name, first, second) {
    this.name = name;
    this.first = first;
    this.second = second;
}

Person.prototype.sum = function() {
        return this.first + this.second;
}

let kim = new Person("kim", 10, 20)
let lee = new Person("lee", 10, 10)

console.log(kim.sum()) // 30
console.log(lee.sum()) // 20

프로토타입을 만드는 장점은 Person 생성자 함수 안에 sum 메서드가 없기 때문에 객체가 만들어질 때마다 생성되지 않기 때문에 효율적이다.

function Person(name, first, second) {
    this.name = name;
    this.first = first;
    this.second = second;
}

Person.prototype.sum = function() {
        return this.first + this.second;
}

let kim = new Person("kim", 10, 20)
kim.sum = function(){
  return "this : " +(this.first+this.second)
}
let lee = new Person("lee", 10, 10)

console.log(kim.sum()) // this : 30
console.log(lee.sum()) // 20

만약 kim의 sum만 다르게 동작하게 하고 싶다면 특정 객체만 다르게 수정이 가능하다.

자바스크립트는 객체의 메서드를 호출할 때 그 객체 자신이 그 메서드를 가지고 있는지 찾는다. 만약 그 객체가 가지고 있지 않다면 객체의 생성자 함수의 프로토타입에 sum 메서드가 있는지 찾는다.

상속

다른 언어의 상속은 sub class가 super class의 자식이 되고 sub class를 통해서 객체를 생성한다. 그래서 객체의 기능은 class 내에서 결정된다.

자바스크립트의 경우 객체가 객체에게서 상속을 받을 수 있다. 상속 관계 역시 유연하다. 다른 객체로부터 상속을 받고자 하면 link만 바꾸면 되는데 그것을 prototype link라고 한다. 그런 관점에서 상속을 주는 객체를 prototype object라고 한다.

let superObj = {superVal:"super"}
let subObj = {subval:"sub"}

전혀 관계 없는 두 객체가 있고 이 객체 사이에서 상속 관계를 정해주고 싶다면 간단하게 __proto__를 이용하면 된다 .

let superObj = {superVal:"super"}
let subObj = {subval:"sub"}
subObj.__proto__= superObj;

console.log(subObj.superVal) // super

그리고 subObj의 superVal를 출력해보면 super가 나오는 것을 알 수 있다. superObj의 프러퍼티를 상속받은 것이다. 즉,__proto__가 담고 있는 객체의 프러퍼티를 하위 객체에 물려준 것!

subObj.superVal = "sub"
console.log(superObj.superVal) // super

하지만 하위 객체의 값을 바꾼다고 상위 객체의 값이 바뀌지 않는다.

하지만 proto 는 표준 자바스크립트에서 인정하지 않고 있다.

Object.create()

let superObj = {superVal:"super"}
let subObj = Object.create(superObj)

subObj.subVal = "sub"
subObj.superVal = "sub"

console.log(superObj.superVal) // super

Object.create()를 이용해서 상속 관계를 정의할 수 있다.

proto 이용



kim = {
  name:"kim",
  first:10,
  seconde:20,
  sum :function(){
    return this.first + this.seconde
  }
}

lee= {
  name:"lee",
  first:10,
  seconde:10
}

lee.__proto__ = kim
console.log("kim.sum(): ", kim.sum()) //30
console.log("lee.sum(): ", lee.sum()) //20

객체 kim에 있는 sum 메서드를 __proto__를 이용하여 lee에 상속했다.

prototype vs ptoto

함수는 객체다.

function Person(){} 이렇게 함수를 선언하는 것과 const Person = new Function() 이렇게 생성자로 선언하는 것과 동일하다. 자바스크립트의 함수는 객체이기 때문에 프로퍼티를 가질 수 있다.

function Person(name, first, second){
  this.name = name;
  this.first = first;
  this.second = second
}

이렇게 함수를 정의하면 저 함수에 해당되는 Person이라는 객체가 생성된다. 동시에 Person의 prototype 객체도 생긴다. 두 객체는 서로 연관되어 있기 때문에 Person 객체 내부에는 prototype이라는 프로퍼티가 생성되고 Person의 prototype 객체를 가리킨다.

Person.prototype이 Person의 prototype 객체인 것이다. Person의 prototype 객체도 constructor라는 프로퍼티를 만들고 Person을 가리킨다. 상호 참조 관계다.

Person.prototype.sum = function(){}

을 선언했을 때 Person의 prototype 객체는 sum 메서드가 없으므로 생성하고 함수를 정의한다.

const kim = new Person("kim", 10, 20)

이렇게 kim이라는 객체를 생성하면 kim의 프로퍼티로는
name, first,second, __proto__가 부여된다. 자동으로 생성된 __proto__는 객체 kim를 생성한 Person의 prototype이 된다. 즉, kim.__proto__로 Person의 prototype 객체에 접근할 수 있는 것이다.

kim.sum() 에서 객체 kim은 sum 메서드가 없다. 그러면 자바스크립트는 __proto__를 통해서 Person의 prototype에 접근한다.

요점은 결국 어떤 객체가 가지고 있지 않은 프로퍼티를 사용하였을 때 그것이 어디에서부터 오는가를 찾는 일이다.

출처 : https://www.inflearn.com/course/%EC%A7%80%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EC%96%B8%EC%96%B4-%EA%B8%B0%EB%B3%B8/lecture/2569?tab=note&mm=close

https://www.youtube.com/watch?v=DHIlPmJUDzk&list=PLuHgQVnccGMAMctarDlPyv6upFUUnpSO3

https://poiemaweb.com/js-prototype

profile
프론트엔드 개발

0개의 댓글