Все функции Javascript имеют объект-прототип, который допускает прототипное наследование (объекты наследуются непосредственно от других объектов). Давайте взглянем.

function Example(){ 
  return 2
} 
Example.prototype // {constructor: ƒ} 
Example.protoype.name = 'An example' 
Example.prototype // {name: 'An example', constructor: ƒ} 
Example.name // 'An example'

И наоборот, все объекты имеют свойство __proto__, и *оно будет указывать на прототип их функции-конструктора*.

let exampleOne = new Example 
exampleOne // {} 
exampleOne.__proto__ // {name: 'An example', constructor: ƒ} 
exampleOne.name // 'An example'

Это важное откровение! Сам exampleOne является пустым объектом, но его __proto__ может указывать на объект-прототип, содержащий свойство name. Когда вызывается exampleOne.name, Javascript сначала проверяет, есть ли у exampleOne свойство с именем name. Это не так, поэтому Javascript будет искать в своем объекте __proto__ свойство name, которое он находит!

Используя прототип, объекты Javascript не наследуют напрямую свойства функций-конструкторов. Они просто имеют доступ к объекту-прототипу своей функции-конструктора.*

Вот почему мы можем создать объект, добавить новое свойство в прототип функции, и объект будет иметь к нему доступ; конечно, это имело бы смысл теперь, когда мы знаем, что свойство __proto__ объекта указывает на этот объект-прототип, но в противном случае это казалось бы волшебством, потому что эта функциональность не может быть реализована в классическом наследовании.

Чтобы еще больше доказать нашу точку зрения, мы можем создать еще один объект из нашего примера функции и сравнить их свойства __proto__.

let exampleTwo = new Example 
{name: 'not same object'} === {name: 'not same object'} // false 
exampleTwo.__proto__ === exampleTwo.proto__ // true

Два объекта __proto__ равны, то есть они указывают на *один и тот же объект в памяти*: прототип функции примера. На самом деле, сама функция не имеет значения, потому что это не класс; имеет значение только объект-прототип. Докажем это сейчас.

Example = 'Function Gone!' 
Example.prototype // undefined 
exampleOne.__proto__ // {name: 'An example', constructor: ƒ}

Мы изменили функцию, но объект-прототип все еще существует в памяти, поэтому наши объекты все еще имеют ссылку на него. Как мы видим, прототипы — это мощный инструмент наследования свойств. Имея только один объект-прототип, содержащий наши свойства, нашим экземплярам нет необходимости иметь собственный дублирующий набор одних и тех же свойств (если, конечно, мы не хотим внести коррективы в функциональность нашего объекта, и в этом случае мы можем просто дать объекта новое свойство, чтобы переопределить свойство в объекте-прототипе!).