Значение прототипа в javascript

Я написал короткий код наследования reader из Person:

<script>

/* Class Person. */
function Person(name) {
    this.name = name;
}

Person.prototype.getName = function() {
    return this.name;
}

var reader = new Person('John Smith');
alert(reader.getName());

</script>

В качестве альтернативы я могу удалить строку Person.prototype.getName = function() { return this.name; } и создать ее в объекте Person. Например

<script>
/* Class Person. */
function Person(name) {
    this.name = name;
    this.getName = function() { return this.name;}
}

var reader = new Person('John Smith');
alert(reader.getName());

</script>

Я получил тот же результат при вызове getName() в обоих случаях. Итак, как они отличаются?

Ответы

Ответ 1

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

Когда вы просто устанавливаете метод на this, каждый экземпляр объекта имеет свою собственную копию того же метода.

Использование prototype намного эффективнее. Обратите внимание, что, как правило, методы устанавливаются на прототипе, так как вы обычно хотите, чтобы все экземпляры использовали один и тот же метод, но свойства помещаются в сам экземпляр, поскольку обычно вы не хотите, чтобы все экземпляры имели одинаковые свойства.

Для вашего комментария, если вы поместите метод в конструкторскую функцию объекта, вы фактически создали "статический" метод. Ни один экземпляр объекта не будет иметь этот метод, все они должны получить к нему доступ в функции конструктора. Итак, в вашем случае Person.someMethod().

Ответ 2

Когда вы помещаете метод в конструктор и создаете объект из этого конструктора, каждый объект несет в себе собственную функцию getName. Для экземпляров 10 Person каждый несет свой собственный getName, поэтому 10 отдельных getName функций.

Если вы разместите getName в прототипе конструктора, эта же функция getName является общей/унаследованной во всех экземплярах. поэтому для 10 экземпляров Person каждый имеет getName, но относится только к функции 1 getName.

Использование прототипов сохраняет память, поскольку метод разделяется между экземплярами, поэтому используется только один.

Ответ 3

Различие заключается в том, что, когда вы помещаете его в прототип, все экземпляры Person используют один и тот же код для getName - вы можете изменить getName во всех экземплярах Person, назначив что-то еще:

Person.prototype.getName = function() { return 'Mr Jones' };

Кроме того, поскольку они имеют один и тот же код, он менее интенсивно с памятью: у вас есть только одна копия функции getName вместо одной копии на экземпляр.

Еще одно отличие состоит в том, что позже вы можете установить Person как прототип другого класса, скажем Man, и он наследует свойства/методы.

Обновление: Вот хороший пост, объясняющий другие свойства прототипов: fooobar.com/questions/337985/...

Ответ 4

Разница в том, что вы продолжаете расширять класс Person, подкласс не наследует метод getName()

Изменить: Я не был прав в приведенном выше описании. Просто протестирован на jsfiddle. Независимо от того, будем ли мы определять метод на прототипе или на самом экземпляре функции, он доступен для подклассов в цепочке.

Вот доказательство: http://jsfiddle.net/u8qrd/

Я понимаю, что есть преимущество производительности/памяти при подключении методов к прототипу. Априор из этого не существует какой-либо поведенческой разницы, когда дело доходит до наследования?

(надеюсь, что я не нарушаю правила SO, задавая здесь вопрос)

Ответ 5

В словах, основанных на классе, разница между объявлением функции через prototype и this будет примерно такой:

прототип:

функция экземпляра будет выглядеть так:

somefunc = function(){super()/*call the function of the super-class*/};

это:

функция экземпляра будет выглядеть так:

somefunc = function(){/* Do same stuff as in the prototype func declared */};

Теперь изменение функции на прототипе не повлияет на экземпляр.