본문 바로가기

JavaScript

[JavaScript] 프로토타입

728x90
반응형

 

자바스크립트와 프로토타입

자바스크립트는 프로토 타입 기반 언어이다

클래스가 없었기 때문에 객체를 복제하고 참조함으로서 새로운 객체를 생성하는 방식이였는데,

ES6에서 클래스가 추가 되었다.

 

하지만 면접 질문에도 많이 나온다고하고

클래스에서도 프로토타입을 활용 한다고 하니 꼭 알아두어야 할 내용임은 틀림없어보인다.

 

 

 

1 . 생성자 함수를 참조하기

prototype, __proto__

 

프로토타입 정리

new 연산자를 사용해 생성자 함수를 새로운 변수에 할당할 경우
그로부터 생성된 인스턴스에는 숨겨진 프로퍼티인 __proto__가 자동으로 생성되어
생성자 함수의 porototype에 어떤 메서드나 프로퍼티가 있다면
new로 생성된 인스턴스에서도 마치 자신의 것처럼 접근 할 수 있다

 

  1   __proto__와 __proto__의 생략  

const Dog = function(name,age){
  this.name = name,
  this.age = age
}
 const mano = new Dog('mano',7)
 const _proto = mano.__proto__.constructor // ƒ Dog()
 const _no_proto = mano.constructor // ƒ Dog()
 _proto === _no_proto // true

 console.log(mano)
//Dog { 
//    name: 'mano', 
//    age: 7, 
//    __proto__: Dog { constructor: ƒ Dog()}
//    }

위의 예제와 같이 new연산자를 이용해 값이 할당된 mano에

__proto__로 생성자 함수의 내용이 참조되어있는것을 볼 수 있고,

 

 mano.__proto__.constructor ===  mano.constructor 인것을 보아

__proto__는 생략 가능 하다는 점도 알 수 있다.

 

 

  2   인스턴스에서 생성자의 메소드에 접근 + 일반 함수 사용 하는 이유

const Dog = function(name,age){
  this.name = name,
  this.age = age
}
//getName 추가
Dog.prototype.getName = function(){return this.name}

const mano = new Dog('mano',7)
mano.getName() //  'mano'
console.log(mano.__proto__.getName()) // undefined ( 생성자 자체를 가르키고 있어서 )


//this 확인하기
Dog.prototype.funcThis = function(){console.log(this)}
Dog.prototype.arrowThis = () =>console.log(this)

mano.funcThis() //  Dog {
//                   name: 'mano',    .... }
mano.arrowThis()  // window (전역객체)

 

예제의 Dog 생성자 함수에 getName이라는 메서드를 추가하였다. 

인스턴스를 생성하고 생성자 함수에 추가한 getName메서드를 

 mano.getName() 으로 사용하였더니 정상적으로 'mano'가 출력된다.

 console.log(mano.__proto__.getName( ))  이 undefined가 되는 이유는 name이 사용 되지 않은 생성자 함수 자체를 가르키기 때문이다

 mano.__proto__.getName === Dog.prototype.getName 이라는 뜻

 

그리고 this를 참조할때에 화살표 함수를 사용하면 어떻게 되는지 보여주기 위해서

funcThis와 arrowThis로 this 확인을 해 보았다.

 

일반 함수 사용

 mano.funcThis() 에서는

funcThis앞에 불린 mano객체가 this가 되어 원하는 값이 출력된다.

 

화살표 함수 사용

 mano.arrowThis() 에서는

화살표 함수는 생성자 함수를 호출한 Instance를 가리키지 않고

상위 컨택스트인 전역 객체 window를 가르키므로 원하는 값이 나오지 않게 된다.

그러므로 prototype에 메소드를 할당하는 경우에는 일반 함수를 할당하는 것이 좋은 방법이다.

 

const Cat = (name,age) => {
  this.name = name,
  this.age = age
}
const miru = new Cat
// dog is not a constructor 
// 화살표 함수로는 new 연산자를 사용할수 없음

+ ) 화살표 함수 에러 :  -- is not a constructor 

위와 같이 화살표함수로 생성자 함수를 만들면 에러가 나는데

화살표 함수는 프로토타입(prototype)을 가지고 있지 않기 때문이다.

 

 

2 . 자기 자신을 참조하기

prototype.constructor , __proto__.constructor

 

 

같은 constructor을 가리키는 값, 같은 prototpye에 접근하는 경로

 

//같은 constrictor을 가리키는 값
const textSomething = function(text){
  this.text = text
}
 const textStr = new textSomething('생성자함수')
// 일때,
 
 const a = textSomething
 const b = textStr.__proto__.constructor
 const c = textStr.constructor
 const d = Object.getPrototypeOf(textStr).constructor
 const e = textSomething.prototype.constructor
 
console.log(a,b,c,d,e)

//ƒ textSomething() , ƒ textSomething() , ƒ textSomething() , ƒ textSomething() , ƒ textSomething()

위의 예제를 확인해보면 a,b,c,d,e 서로 다른 방법으로 적혀있지만

모두 같은 textSomething을 가리키는 값이다

 

 

//같은 prototype의 객체에 접근 할 수 있는 경로
const countNum = function(num){
  this.count = num
}
countNum.prototype.printCount = function(){
  return this.count
}

 const num = new countNum(4)
// 일때, 
 
const a = countNum.prototype.printCount
const b = num.__proto__.printCount
const c = num.printCount
const d = Object.getPrototypeOf(num).printCount

console.log(a,b,c,d)
// ƒ () , ƒ () , ƒ () , ƒ () 

 

위의 예시의 a,b,c,ds는 prototype의 객체에 접근할 수 있는경로이고.

그 경로를 이용하여 constructor에 정의된 메서드를 사용 할 수 있다.

 

 

 

 

많은 예시들을 들어서 설명했지만 결론적으로 

 

new 연산자로 생성자로 생성된 인스턴스에는

생성자 함수(constructor)에 접근할 수 있는 경로로 __proto__가 참조되어있다. 

 

방법은 아래의 예제와 같고, 둘은 같은 값 , 생성자 함수를 가리키고있다.

const arr = new Array([2,3])

const arr1 = Array.prototype.constructor
const arr2 = arr.__proto__.constructor
arr1 === arr2  //true

 


✔️참고

[ 코어 자바스크립트  - 저자 정재남 ]

beomy.tistory.com/19

728x90
반응형