Вопрос: Где используются прототипы, наследование в JS приложениях?

Лучший ответ: Здравствуйте.
На самом деле всё проще.
Не обижайтесь, но вы просто не так хорошо знаете сам javascript.
1. prototype - ссылка на прототип объекта. Array.prototype, Number.prototype.  В нём хранятся методы и свойства этого объекта, а также... (далее переходим к __proto__)
2. __proto__ - тоже ссылка на прототип. Например, введите в консоли [] и раскройте ветвь. У вас всего два свойства. Одно - length - количество элементов в массиве. Другое - __proto__. А где же все методы, которые мы можем использовать с массивами filter, map, slice и так далее? Они лежат в __proto__. Более подробно здесь. 
3. inheritance соответственно - наследование. JS построен на прототипной парадигме (надеюсь, я тут не наврал). Array наследуется от Object. Это можно легко увидеть, посмотрев Array.prototype. Там вы увидите тот самый __proto__, являющийся ссылкой на Object.prototype. Вся инфа по ссылке выше.
4, 5. call и apply постепенно уходят из обихода, но тем не менее про них важно знать и уметь ими пользоваться. Эти методы позволяют вызвать функцию в контексте, который вам необходим. 
Например вам нужно вызвать метод какого-то объекта, который работает с this в контексте другого объекта, у которого этого метода нет. Вы можете сделать следующее:var o_1 = {
	name: 'Peter',
	hello: function () {
		console.log('Hello, ' + this.name);
	}
};

var o_2 = {
	name: 'Jane'
};

o_1.hello.call(o_2); // Фактически вы говорите "вызови метод такой-то для объекта такого-то"
Для передачи аргументов в "заимствованную" функцию оба метода принимают аргументы, каждый по-своему.var o_1 = {
	name: 'Peter',
	hello: function () {
		console.log('Hello, ' + this.name);
	},
        sum: function (a, b) {
		console.log(`${this.name} sum a and b to ${a + b}`);
	}
};

var o_2 = {
	name: 'Jane'
};

o_1.sum.call(o_2, 2, 4);
o_1.sum.apply(o_2, [1, 2]);
Отличие между этими двумя методами в том, как они принимают аргументы, которые попадут в функцию.call принимает список аргументов, начиная со второго, а apply, соответственно, принимает массив.
Также, ничто не мешает вам вызвать функцию, которая не нуждается в контексте, для этого первым аргументом можно передать null.var o = {
	sum: function (a, b) {
		console.log(a + b);
	}
}
o.sum.call(null, 1, 2);
o.sum.apply(null, [1, 2]);
Подробнее тут.
6. bind тоже довольно простая штука. Отчасти он похож на предыдущие два метода, за исключением того, что он не вызывает функцию сразу же.
Основная его задача - вернуть функцию, которая будет вызвана для нужного вам контекста.var o = {
	a: 1,
	b: 2,
	sum: function () {
		console.log(this.a + this.b);
	}
};

var o2 = {
	a: 10,
	b: 20
};

var o2Sum = o.sum.bind(o2);

o2Sum();
Также с помощью bind можно каррировать функции.
Всё есть здесь
PS: надеюсь, код не содержит ошибок и я нигде не налажал и всё правильно рассказал.

Худший ответ: как я понимаю: есть классы, есть методы класса, если просто задать методы классу, то будет копи-паст (грубо говоря) методов на каждый созданный объект, прототипное наследование это как бы общий буфер для методов/свойств. Выходит сколько бы объектов не создали, при обращении к методу/свойству все объекты будут ссылать в одно место, если конечно не переназначили метод/свойство у конкретного экземпляра класса. "apply, call, bind" целые статьи посвящают, по сути это просто вызов функции с возможность передать аргументы и смены контекста вызова