Prototypal Inheritance: Subclasses
Subclasses
One of the benefits of implementing inheritance is that it allows you toreuse existing code. By establishing inheritance, we cansubclass, that is, have a "child" object take on most or all of a "parent" object's properties while retaining unique properties of its own.
Let's say we have a parentAnimal
object, which contains properties likeage
andweight
. That sameAnimal
object can also access methods likeeat
andsleep
.
Now, let's also say that we want to create aCat
child object. Just like you can with other animals, you can also describe a cat by itsage_or_weight, and you can also be certain that the cat_eats_and_sleeps_as well. When creating thatCat
object, then, we can simply re-write and re-implement all those methods and properties fromAnimal
-- or, we can save some time and prevent repeated code by havingCat
_inherit_those existing properties and methods fromAnimal
!
Not only canCat
take on properties and methods ofAnimal
, we can also giveCat
its own unique properties and methods as well! Perhaps aCat
has a uniquelives
property of9
, or it has a specializedmeow()
method that noAnimal
has.
By using prototypal inheritance,Cat
only needs to implementCat
-specific functionality, and just reuseAnimal
's existing functionality.
implementing inheritance(상속 구현)의 이점 중 하나는 기존 코드를 재사용할 수 있다는 것입니다. 상속을 설정함으로써 subclass를 만들 수 있습니다. 즉, "자식"object가 고유한 속성을 유지하면서 "부모"object의 속성 대부분 또는 전부를 가져갈 수 있습니다.
age과 weight과 같은 속성을 포함하는 상위 Animal object가 있다고 가정해 보겠습니다. 동일한 Animal object는 eat 및 sleep과 같은 method에 액세스할 수 있습니다.
자, Cat이라는 자식object를 만든다면, 다른 동물과 마찬가지로 cat의 age이나 weight을 설명할 수 있으며, cat이 eat 및 sleep도 확신 할 수 있습니다. 그런 다음 Cat object를 만들면 Animal에서 모든 method와 속성을 다시 작성하고 다시 구현할 수 있습니다. 또는 Cat이 Animal에서 기존 속성과 method를 상속받도록하여 반복 코드를 방지할 수 있습니다.
Cat은 Animal의 속성 및 method를 사용할 수 있을뿐만 아니라 Cat에 고유한 속성 및 method도 제공 할 수 있습니다. 아마도 cat는 독특한 lives 속성이 9이거나, animal에 없는 특수화된 meow() method가 있습니다.
Prototype inheritance를 사용함으로써 Cat은 Cat 고유의 기능을 구현하고 Animal의 기존 기능을 재사용하면 됩니다.
Inheritance Via Prototypes
Recall the prototype chain from the previous section:
Cat() constructor 함수는 "new"operator를 사용하여 호출됩니다.이 operator는 bailey instance (object)를 만듭니다. meow() method는 bailey object의 constructor 함수의 prototype에 정의되어 있습니다. prototype은 단지 하나의 object이며, 그 constructor에 의해 생성된 모든 object는 prototype에 비밀리에 연결됩니다. 따라서 bailey.meow()를 bailey 자신의 method처럼 실행할 수 있습니다!
When calling any property on any object, the JavaScript engine will first look for the property in the object itself (i.e., the object'sown, non-inherited properties). If the property is not found, JavaScript will then look at the object's prototype. If the property_still_isn't found in the object's prototype, JavaScript will continue the search up theprototype chain.
Again, inheritance in JavaScript is all about setting up this chain!
The Secret Link
As you know, an object's constructor function's prototype is first place searched when the JavaScript engine tries to access a property that doesn't exist in the object itself. Consider the followingbear
object with two properties,claws
anddiet
:
const bear = {
claws: true,
diet: 'carnivore'
};
We'll assign the followingPolarBear()
constructor function'sprototype
property tobear
:
function PolarBear() {
// ...
}
PolarBear.prototype = bear;
Let's now call thePolarBear()
constructor to create a new object, then give it two properties:
const snowball = new PolarBear();
snowball.color = 'white';
snowball.favoriteDrink = 'cola';
This is how thesnowball
object looks at this point:
{
color: 'white',
favoriteDrink: 'cola'
}
Note thatsnowball
has just two properties of its own:color
andfavoriteDrink
. However,snowball
_also _has access to properties that _don't _exist inside it:claws
anddiet
:
console.log(snowball.claws);
// true
console.log(snowball.diet);
// 'carnivore'
Sinceclaws
anddiet
both exist as properties in theprototype
object, they are looked up because objects are _secretly linked _to their constructor'sprototype
property.
Great! But you may be wondering: just _what _is this secret link that leads to theprototype
object? Right after objects are made from thePolarBear()
constructor (such assnowball
), they have immediate access to properties inPolarBear()
's prototype. How exactly is this possible?
As it turns out, the secret link issnowball
's__proto__
property (note the two underscores on each end).__proto__
is a property of all objects (i.e., instances) made by a constructor function, and points directly to that constructor'sprototype
object. Let's check out what it looks like!
console.log(snowball.__proto__);
// { claws: true, diet: 'carnivore' }
Since the__proto__
property refers to the same object asPolarBear
's prototype,bear
, comparing them returnstrue
:
console.log(snowball.__proto__ === bear);
// true
It is highly discouraged to reassign the__proto__
property, or even use it in any code you write. First, there compatibility issues across browsers. What's more: since the JavaScript engine searches and accesses properties along the prototype chain, mutating an object's prototype can lead to performance issues. The MDN article forprotoeven warns against using this property in red text at the very top of the page!
It's great toknowthe secret link for learning how functions and objects are interconnected, but you**should not use`\_proto_to manage inheritance**. If you ever just need to review an object's prototype, you can still use
Object.getPrototypeOf()`.
💡 What About Just Inheriting the Prototype? 💡
Let's say we want a
Child
object to inherit from aParent
object. Why shouldn't we just setChild.prototype = Parent.prototype
?First, recall that objects are passed byreference. This means that since the
Child.prototype
object and theParent.prototype
object refer to thesame object-- any changes you make toChild
's prototype will_also_be made toParent
's prototype! We don't want children being able to modify properties of their parents!On top of all this, no prototype chain will be set up. What if we want an object to inherit from any object we want, not just its prototype?
We still need a way to efficiently manage inheritance without mutating the prototype at all.
QUESTION 1 OF 4
Consider the following:
function GuineaPig (name) {
this.name = name;
this.isCute = true;
}
const waffle = new GuineaPig('Waffle');
What doeswaffle.__proto__
refer to?
GuineaPig.__proto__
GuineaPig.proto
GuineaPig.prototype
guineapig.proto
GuineaPig
SUBMIT: When the new instance of GuineaPig
is created, the special property waffle.__proto__
is set to GuineaPig.prototype
. This secret link allows instances of the GuineaPig
constructor to access properties of GuineaPig.prototype
. Keep in mind that you should never use the __proto__
in any code you write.
QUESTION 2 OF 4
Consider the following:
function Car (color, year) {
this.color = color;
this.year = year;
}
Car.prototype.drive = function () {
console.log('Vroom vroom!');
};
const car = new Car('silver', 1988);
What happens whencar.drive();
is executed? List the following events in the order that they occur:
BecauseCar.prototype.drive
_is_a defined property, it is returned.
The JavaScript engine then accesses thecar.__proto__
property.
The JavaScript engine does not finddrive
within thecar
object.
First, the JavaScript engine searches inside thecar
object for a property nameddrive
.
Since thecar.__proto__
property points toCar.prototype
, the JavaScript engine searches fordrive
in the prototype.
Finally, sincedrive
is invoked as a method oncar
, the value ofthis
is set tocar
.
ORDER
EVENT
1st: First, the JavaScript engine searches inside thecar
object for a property nameddrive
.
2nd: The JavaScript engine does not finddrive
within thecar
object.
3rd: The JavaScript engine then accesses thecar.__proto__
property.
4th: Since thecar.__proto__
property points toCar.prototype
, the JavaScript engine searches fordrive
in the prototype.
5th: BecauseCar.prototype.drive
_is_a defined property, it is returned.
6th: Finally, sincedrive
is invoked as a method oncar
, the value ofthis
is set tocar
.
SUBMIT: This is the prototype chain in action! As always: keep in mind that while the secret link is the __proto__
property, it should never be used (written) directly.
Object.create()
At this point, we've reached a few roadblocks when it comes to inheritance. First, even though__proto__
can access the prototype of the object it is called on, using it in any code you write is not good practice.
What's more: we also shouldn't inherit _only _the prototype; this doesn't set up the prototype chain, and any changes that we made to a child object will also be reflected in a parent object.
So how should we move forward?
There's actually a way for us to set up the prototype of an object ourselves: usingObject.create()
. And best of all, this approach lets us manage inheritance without altering the prototype!
Object.create()
takes in a single object as an argument, and returns a new object with its__proto__
property set to what argument is passed into it. From that point, you simply set the returned object to be the prototype of the child object's constructor function. Let's check out an example!
우리는 prototype만 상속받아서는 안됩니다. 이것은 prototype chain을 설정하지 않으며 우리가 자식 object에 변경한 사항은 부모 object에도 반영됩니다.
그렇다면 앞으로 어떻게 나아가야합니까?
Object.create()를 사용하여 object의 prototype을 직접 설정할 수있는 방법이 있습니다. 그리고 무엇보다도이 접근법은 prototype을 변경하지 않고 상속을 관리할 수 있게 해줍니다!
Object.create()는 단일 object를 argument로 사용하고 __proto__ 속성이 전달된 argument로 설정된 새 object를 반환합니다. 그 시점에서 반환된 object를 자식 object의 생성자 함수의 prototype으로 설정하기만하면 됩니다. 예를 들어 봅시다!
First, let's say we have amammal
object with two properties:vertebrate
andearBones
:
const mammal = {
vertebrate: true,
earBones: 3
};
Recall thatObject.create()
takes in a single object as an argument, and returns a new object. That new object's`\_proto_
property is set to whatever was originally passed into Object.create()
. Let's save that returned value to a variable,rabbit`:
const rabbit = Object.create(mammal);
We expect the newrabbit
object to be blank, with no properties of its own:
console.log(rabbit);
// {}
However,rabbit
should now be secretly linked tomammal
. That is, its__proto__
property should point tomammal
:
console.log(rabbit.__proto__ === mammal);
// true
Great! This means that now,rabbit
extendsmammal
(i.e.,rabbit
inherits frommammal
). As a result,rabbit
can accessmammal
's properties as if it were its own!
console.log(rabbit.vertebrate);
// true
console.log(rabbit.earBones);
// 3
Object.create()
gives us a clean method of establishing prototypal inheritance in JavaScript. We can easily extend the prototype chain this way, and we can have objects inherit from just about any object we want!
Object.create()는 JavaScript에서 prototype 상속을 설정하는 깔끔한 method를 제공합니다. 우리는 이 방법으로 prototype chain을 쉽게 확장할 수 있으며, 우리가 원하는 모든 object로부터 object를 상속받을 수 있습니다!
Let's check out a more involved example below:
Here's the code from the preceding video.
QUESTION 3 OF 4
Consider the following:
function Parent() {
// ...
}
function Child() {
// ...
}
Child.prototype = Object.create(Parent.prototype);
const child = new Child();
The following is then executed:
child instanceof Parent;
What is printed to the console?
Child
undefined
false
true
The console will throw an error.
SUBMIT: Object.create
() takes in a single object as an argument, and returns a new object. That new object's `__protoproperty is set to whatever was originally passed into
Object.create()`.
In this quiz,Parent.prototype
was the argument passed into Object.create()
. The return value of the expression Object.create(Parent.prototype)
; was then set to the value of the Child
constructor's prototype property. After that, we instantiate a new object:child
`.
The expressionchild instanceof Parent;
returns a boolean indicating whether the Parent
constructor exists in thechild
object's prototype chain. Since we know this is true after executing the first expression (i.e.,Child.prototype = Object.create(Parent.prototype);
), the console outputs true
.
QUESTION 4 OF 4
What is true aboutObject.create()
? Select all that apply:
It returns a new object whose
__proto__
property is set to the object passed intoObject.create()
Using
Object.create()
, we can have objects inherit from just about any object we want (i.e., not only theprototype
)Object.create()
allows us to implement prototypal inheritance without mutating the prototypeThe method is invoked directly_on_a single object
SUBMIT: Object.create()
is a practical approach to establish prototypal inheritance in JavaScript.
Summary
Inheritance in JavaScript is all about setting up the prototype chain. This allows us to subclass, that is, create a "child" object that inherits most or all of a "parent" object's properties and methods. We can then implement any of the child object's unique properties and methods separately, while still retaining data and functionality from its parent.
An object (instance) is secretly linked to its constructor function's prototype object through that instance's __proto__
property. You should never use the__proto__
in any code you write. Using __proto__
in any code, or even inheriting just the prototype directly, leads to some unwanted side effects.
To efficiently manage inheritance in JavaScript, an effective approach is to avoid mutating the prototype completely. Object.create()
allows us to do just that, taking in a parent object and returning a new object with its `\_proto_` property set to that parent object.
JavaScript의 상속은 모두 prototype 체인을 설정하는 것입니다. 이것은 하위 클래스로 만들 수 있습니다. 즉, "부모"object의 속성 및 method 대부분 또는 모두를 상속하는 "자식"object를 만듭니다. 그런 다음 부모로부터 데이터와 기능을 유지하면서 자식 object의 고유 한 속성과 method를 개별적으로 구현할 수 있습니다.
object (인스턴스)는 해당 인스턴스의 __proto__ 속성을 통해 생성자 함수의 prototype object에 몰래 연결됩니다. 당신이 쓰는 모든 코드에서 __proto__를 사용해서는 안됩니다. 임의의 코드에서 __proto__를 사용하거나 직접 prototype을 상속하는 경우에도 원치 않는 부작용이 발생합니다.
JavaScript에서 상속을 효율적으로 관리하려면 효과적인 prototype 변형을 피하는 것이 좋습니다. Object.create()는 부모 object를 가져 와서 `\ _proto_` 속성을 부모 object로 설정하여 새로운 object를 반환하는 것을 허용합니다.
Further Research
- Inheritance and the prototype chain on MDN
- Object.create() on MDN