[javascript] 프로토타입

zoe·2022년 9월 21일

Javascript

목록 보기
8/19

자바스크립트는 프로토타입 기반 언어이다.
여기서 프로토타입(prototype)이란, 원형 객체를 말한다.


프로토타입 체인

Every object in JavaScript has a built-in property, which is called its prototype.

자바스크립트에서 모든 객체는 prototype이라고 부르는 내장 속성이 있다.

The prototype is itself an object, so the prototype will have its own prototype, making what's called a prototype chain. The chain ends when we reach a prototype that has null for its own prototype.

prototype 자체가 객체이기 때문에, prototype은 다시 prototype을 가진다.
그래서 prototype의 prototype으로 계속해서 거슬러 올라가는게 가능해 지는데, 이것을 prototype chain이라고 한다.
이 prototype chain은 prototype 속성의 데이터가 null이 되는 지점에서 멈춘다. (Object prototype이 나오는 시점)

Note: The property of an object that points to its prototype is not called prototype. Its name is not standard, but in practice all browsers use __proto__. The standard way to access an object's prototype is the Object.getPrototypeOf() method.

Note: 객체에서 prototype을 가리키는 속성은 prototype이라고 부르지 않는다. 보통 모든 브라우저에서 __proto__를 속성명으로 사용하고 있다.
object의 prototype으로 접근하는 일반적인 방법은 Object.getPrototypeOf() 메소드를 사용하는 것이다.
// 혹은 .__proto__를 사용하여 접근할 수도 있다

When you try to access a property of an object: if the property can't be found in the object itself, the prototype is searched for the property. If the property still can't be found, then the prototype's prototype is searched, and so on until either the property is found, or the end of the chain is reached, in which case undefined is returned.

객체의 속성에 접근하고자 할 때: 만약 객체 자체 내의 속성들을 검사해서 일치하는 속성을 찾을 수 없다면, 다음으로 객체의 프로토타입이 검사된다. 객체의 프로토타입을 검사했는데도 여전히 속성을 찾을 수 없다면, 다음으로는 프로토타입의 프로토타입을 검사한다. 이런식으로 계속 되다가 속성 값을 찾을 수도 있고, 만약 프로토타입 체인이 끝날때까지 속성을 찾지 못하면 undefined가 리턴된다.

const myObj = {
	city: Seoul;
    greeting() {
    	console.log(`Greetings from ${this.city}`)
    }
}

myObj.__proto__ // Object.prototype
Object.getPrototypeOf(myObj) // Object.prototype

So when we call myObj.toString(), the browser:
1. looks for toString in myObj
2. can't find it there, so looks in the prototype object of myObject for toString
3. finds it there, and calls it.

위 코드를 참고해보자.
우리가 myObj.toString()을 호출하면, 브라우저는 다음과 같은 동작을 수행한다.

  1. myObj 객체 안에서 toString 속성을 찾아본다.
  2. myObj 안에서 toString 속성을 찾을 수 없기 때문에, 다음으로 myObj의 prototype 객체 안에서 속성을 찾아본다.
  3. 거기서 찾아서, 호출한다.

What is the prototype for myObj? To find out, we can use the function Object.getPrototypeOf():

그렇다면, myObj의 prototype은 무엇일까? 그것을 알아보려면 Object.getPrototypeOf() 함수를 사용하면 된다.

Object.getPrototypeOf(myObj); // Object {}

This is an object called Object.prototype, and it is the most basic prototype, that all objects have by default. The prototype of Object.prototype is null, so it's at the end of the prototype chain:

Object { }는 Object.prototype 이라고 불리는 객체이며, 모든 객체가 기본적으로 가지고 있는 가장 기본적인 prototype이다.
Object.prototype의 prototype은 null 이고, 이는 prototype chain의 끝을 의미한다.

The prototype of an object is not always Object.prototype. Try this:

객체의 prototype이 항상 Object.prototype인것은 아니다.
다음을 코드를 살펴보자.

const myDate = new Date();
let object = myDate;

do {
  object = Object.getPrototypeOf(object);
  console.log(object);
} while (object);

// Date.prototype
// Object { }
// null

This code creates a Date object, then walks up the prototype chain, logging the prototypes. It shows us that the prototype of myDate is a Date.prototype object, and the prototype of that is Object.prototype.

이 코드는 Date 객체를 생성한 다음, prototype chain을 거슬러 올라가며 prototype들을 출력한다.
출력된 결과를 살펴보면, myDate의 prototype은 Date.prototype 객체이고,
그 객체의 prototype이 Object.prototype임을 알 수 있다.

Shadowing properties

What happens if you define a property in an object, when a property with the same name is defined in the object's prototype? Let's see:

만약 객체의 내부에 어떤 속성을 정의했는데, 객체의 prototype에 똑같은 이름의 속성이 이미 정의되어 있다면 어떤 일이 일어날까?
한번 알아보자.

const myDate = new Date(1995, 11, 17);

console.log(myDate.getYear()); // 95

myDate.getYear = function() {
  console.log('something else!')
};

myDate.getYear(); // 'something else!'

This should be predictable, given the description of the prototype chain. When we call getYear() the browser first looks in myDate for a property with that name, and only checks the prototype if myDate does not define it. So when we add getYear() to myDate, then the version in myDate is called.

우리는 프로토타입 체인에 대해 이미 알고 있기 때문에, 아마 예상 결과를 어느정도 예측할 수 있었을 것이다.
우리가 getYear()를 호출하면, 브라우저는 먼저 myDate 내부에서 일치하는 이름의 속성을 찾아보고, 거기서 찾지 못해야만 prototype으로 넘어가서 찾아보게 된다. 그래서 getYear( )를 myDate에 추가하면, myDate 내에서 수정된 값이 호출된다.

// 한 마디로 myDate에서 추가된 getYear( ) 속성이 prototype의 getYear( ) 속성을 가리는 효과가 되는 것이다.

이것을 Shadowing property 현상이라고 부른다.

객체의 프로토타입 설정하기

1. create( )

The Object.create() method creates a new object and allows you to specify an object that will be used as the new object's prototype.

Object.create() 메소드는 새로운 객체를 생성하고, 이 새로운 객체의 프로토타입이 될 객체를 지정할 수 있도록 한다.

const personPrototype = {
  greet() {
    console.log('hello!');
  }
}

const carl = Object.create(personPrototype);
carl.greet();  // hello!

Here we create an object personPrototype, which has a greet() method. We then use Object.create() to create a new object with personPrototype as its prototype. Now we can call greet() on the new object, and the prototype provides its implementation.

여기서 우리는 greet() 메소드를 가진 personPrototype이라는 객체를 만들었다. 그 다음, Object.create()를 사용하여 personPrototype을 prototype으로 가지는 새 객체를 만들었다. 이제 우리는 새 객체에서 greet() 을 호출할 수 있고, prototype에 greet()이 들어있기 때문이다.

2. 생성자

In JavaScript, all functions have a property named prototype. When you call a function as a constructor, this property is set as the prototype of the newly constructed object (by convention, in the property named __proto__.

자바스크립트에서 모든 함수는 prototype이라는 속성을 가지고 있다. 함수를 생성자로 호출하면, 이 속성은 생성자에 의해 새로 생성된 객체의 prototype으로 설정된다.

So if we set the prototype of a constructor, we can ensure that all objects created with that constructor are given that prototype:

그래서 만약 우리가 생성자의 prototype을 설정한다면, 그 생성자를 이용하여 생성한 모든 객체는 그 prototype을 가지게 될 것이다.

const personPrototype = {
  greet() {
    console.log(`hello, my name is ${this.name}!`);
  }
}

function Person(name) {
  this.name = name;
}

Object.assign(Person.prototype, personPrototype);
// or
// Person.prototype.greet = personPrototype.greet;

Here we create:
1. an object personPrototype, which has a greet() method
2. a Person() constructor function which initializes the name of the person to create.

여기서 우리는
1. greet( ) 메소드를 가지고 있는 personPrototype
2. 생성할 사람의 이름을 초기화하는 생성자 함수 Person()
을 만들었다.

We then put the methods defined in personPrototype onto the Person function's prototype property using Object.assign.

그 다음, Object.assign을 이용해서 personPrototype 내에서 정의된 메소드를 Person 함수의 prototype 속성으로 넣어주었다.

After this code, objects created using Person() will get Person.prototype as their prototype, which automatically contains the greet method.

이 코드 이후, Person() 생성자 함수를 이용해서 생성된 객체들은, greet 메소드를 자동적으로 포함하고 있는 Person.prototype을 prototype으로 가지게 될 것이다.

2-1. Own properties

위에서 Person() 생성자 함수를 이용해서 생성한 객체들은
name 속성과 greet 메소드를 속성으로 가질 것이다.

name 속성은 생성자 함수 안에 설정되어 있기 때문에 Person 객체에서 바로 보여진다.

greet 메소드는 prototype 내에 설정되어 있다.

name 속성처럼 객체 내에 설정되어 바로 보여지는 속성을 Own property 라고 하고, 어떠한 속성이 own property인지 아닌지 알아보려면 Object.hasOwn()을 사용하면 된다.

Prototypes and inheritance

Prototypes are a powerful and very flexible feature of JavaScript, making it possible to reuse code and combine objects.

프로토타입은 자바스크립트에서 코드의 재사용과 객체의 결합을 가능하게 하는 매우 강력하고 유연한 특성중 하나이다.

In particular they support a version of inheritance. Inheritance is a feature of object-oriented programming languages that lets programmers express the idea that some objects in a system are more specialized versions of other objects.

특히, 프로토타입은 일종의 상속 특성을 가진다.
상속은 객체 지향 프로그래밍 언어의 특징 중 하나로,
프로그래머들이 하나의 체계 내에서 어떤 객체들이 다른 객체들의 원형이 된다는 것을 표현할 수 있도록 해준다.

For example, if we're modeling a school, we might have professors and students: they are both people, so have some features in common (for example, they both have names), but each might add extra features (for example, professors have a subject that they teach), or might implement the same feature in different ways. In an OOP system we might say that professors and students both inherit from people.

예를 들어, 우리가 학교를 짓는다고 하면, 교수님들과 학생들이 있어야 할 것이다. 교수님들과 학생들은 모두 '사람'이므로 어느정도 공통된 특성을 공유(예를 들어, 교수님들과 학생들 모두 이름이 있다.)하지만, 동시에 서로 다른 특성들을 추가할 수도 있고, 또는 같은 특성을 다른 방식으로 구현할 수도 있다.
객체 지향 프로그래밍에서 교수님과 학생들은 모두 '사람'으로부터 '상속' 받는다고 할 수 있다.

profile
Zoë Park

0개의 댓글