Ещё до того как в JavaScript появилось само ключевое слово "class" в JavaScript существовал другой способ создания классов. Нужно было лишь написать функцию, использовать в ней ключевое слово "this" и при помощи ключевого слова "new" обратиться к этой функции, создав, таким образом, экземпляр класса. Например:
var Fn = function(tmp){
this.a = tmp
}
var inst = new Fn(3)
У любой функции есть специальный пустой объект-"заготовка" для создания экземпляров класса. Как раз ссылка на этот объект, лежит в свойстве "prototype" у любой функции. Свойство "prototype" есть только у функций. Когда к функции идет обращение при помощи ключевого слова "new", функция берет и помещает себя в этот пустой объект-"болванку" и вызывает сама себя. Таким образом, использованные в функции ключевые слова "this" будут указывать на этот объект и он заполняется.
Если добавить этому объекту какое-либо свойство или метод, то в дальнейшем это свойство или метод будет доступно всем экземплярам данного класса по праву "прототипного наследования". Для этого и используется свойство "prototype" функции. Например добавим этому объекту-"болванке" поле b = 10.
Fn.prototype.b = 10
Теперь у всех экземпляров класса Fn будет доступно поле b = 10.
Теперь о том что такое __proto__. Это тоже свойство. Оно есть у всех объектов, а в JavaScript всё является объектом. Даже просто число - это тоже объект класса Number. И функции - это тоже объекты. Так вот - свойство __proto__ хранит ссылку на прототип данного объекта. Если у объекта inst (из примера выше), вызвать свойство __proto__, мы получим ссылку на тот самый объект-"болванку".
inst.__proto__ // Object{b: 10}
Если вызвать свойство __proto__ у функции, то это будет ссылка на прототип самой функции, так как она является объектом.
Fn.__proto__ // function()
ВЫВОД: "prototype" - это свойство, содержащее ссылку на объект-"болванку", который функция использует для создания экземпляров класса. А __proto__ - это свойство, которое есть у всех объектов и оно содержит ссылку на прототип данного объекта.