https://developer.mozilla.org/en/Introduction_to_Object-Oriented_JavaScript

ел бы понять, когда уместно использовать методы-прототипы в js. Должны ли они всегда использоваться? Или есть случаи, когда их использование не является предпочтительным и / или приводит к снижению производительности?

При поиске вокруг этого сайта общих методов для пространств имен в js кажется, что большинство использует реализацию, не основанную на прототипах: просто используя объект или объект функции для инкапсуляции пространства имен.

Исходя из языка, основанного на классах, трудно не пытаться проводить параллели и думать, что прототипы похожи на «классы», а реализации пространства имен, которые я упомянул, похожи на статические методы.

Ответы на вопрос(5)

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

Скажем, у вас есть базаCar() класс / объект.

function Car() {
    // do some car stuff
}

Затем вы создаете несколькоCar() экземпляров.

var volvo = new Car(),
    saab = new Car();

Теперь вы знаете, что каждая машина должна будет двигаться, включаться и т. Д. Вместо того, чтобы прикреплять метод непосредственно кCar() класс (который занимает память для каждого созданного экземпляра), вы можете вместо этого присоединить методы к прототипу (создавая методы только один раз), таким образом предоставляя доступ к этим методам обоим новымvolvo а такжеsaab.

// just mapping for less typing
Car.fn = Car.prototype;

Car.fn.drive = function () {
    console.log("they see me rollin'");
};
Car.fn.honk = function () {
    console.log("HONK!!!");
}

volvo.honk();
// => HONK!!!
saab.drive();
// => they see me rollin'
 29er17 сент. 2012 г., 00:00
на самом деле это неверно. volvo.honk () не будет работать, потому что вы полностью заменили объект-прототип, а не расширили его. Если бы вы делали что-то подобное, это работало бы так, как вы ожидаете: Car.prototype.honk = function () {console.log ('HONK');} volvo.honk (); // «гудеть»
 hellatan17 сент. 2012 г., 23:00
@ 29er - в том, как я написал этот пример, вы правы. Порядок имеет значение. Если бы я сохранил этот пример как есть, тоCar.prototype = { ... } придется прийти, прежде чем позвонитьnew Car() как показано в этом jsfiddle:jsfiddle.net/mxacA , Что касается вашего аргумента, это будет правильный способ сделать это:jsfiddle.net/Embnp , Забавно то, что я не помню, чтобы отвечать на этот вопрос =)
 hellatan26 апр. 2014 г., 20:06
@ Джош, спасибо, что указал на это. Я обновил свой ответ, чтобы не перезаписывать прототип литералом объекта, как это должно было быть с самого начала.
 Josh Bedo08 янв. 2014 г., 06:16
@hellatan, вы можете исправить это, установив конструктор: Car, поскольку вы перезаписали свойство prototype литералом объекта.

если хотите объявить «нестатический» метод объекта.

var myObject = function () {

};

myObject.prototype.getA = function (){
  alert("A");
};

myObject.getB = function (){
  alert("B");
};

myObject.getB();  // This works fine

myObject.getA();  // Error!

var myPrototypeCopy = new myObject();
myPrototypeCopy.getA();  // This works, too.
 Amr Labib29 янв. 2018 г., 21:20
@keatsKelleher, но мы можем создать нестатический метод для объекта, просто определив метод внутри функции конструктора, используяthis примерthis.getA = function(){alert("A")} правильно ?
 GFoley8308 мая 2013 г., 12:26
+1 Отличный момент. Не учел это.

основанных на классе, то Person - это класс, walk () - метод Prototype. Поэтому walk () будет существовать только после того, как вы создадите новый объект с этим.

Поэтому, если вы хотите создать копии объекта, например Person u, можете создать много пользователей, Prototype - хорошее решение, так как экономит память, разделяя / наследуя одну и ту же копию функции для каждого объекта в памяти.

В то время как статика не очень помогает в таком сценарии.

function Person(){
this.name = "anonymous";
}

// its instance method and can access objects data data 
Person.prototype.walk = function(){
alert("person has started walking.");
}
// its like static method
Person.ProcessPerson = function(Person p){
alert("Persons name is = " + p.name);
}

var userOne = new Person();
var userTwo = new Person();

//Call instance methods
userOne.walk();

//Call static methods
Person.ProcessPerson(userTwo);

Так что это более похоже на метод экземпляра. Подход объекта подобен статическим методам.

https://developer.mozilla.org/en/Introduction_to_Object-Oriented_JavaScript

Решение Вопроса

оптимизация.

Отличным примером их правильного использования является библиотека jQuery. Каждый раз, когда вы получаете объект jQuery с помощью$('.someClass')этот объект имеет десятки "методов". Библиотека может достичь этого, возвращая объект:

return {
   show: function() { ... },
   hide: function() { ... },
   css: function() { ... },
   animate: function() { ... },
   // etc...
};

Но это будет означать, что каждый объект jQuery в памяти будет иметь десятки именованных слотов, содержащих одни и те же методы, снова и снова.

Вместо этого эти методы определены в прототипе, и все объекты jQuery «наследуют» этот прототип, чтобы получить все эти методы при очень небольших затратах времени выполнения.

Одна жизненно важная часть того, как jQuery делает это правильно, состоит в том, что это скрыто от программиста. Он рассматривается исключительно как оптимизация, а не как то, о чем вам следует беспокоиться при использовании библиотеки.

Проблема с JavaScript состоит в том, что функции голого конструктора требуют, чтобы вызывающая программа запомнила их с префиксомnew или иначе они обычно не работают. Для этого нет веских причин. JQuery делает это правильно, скрывая эту ерунду за обычной функцией,$, так что вам не нужно заботиться о том, как объекты реализованы.

Чтобы вы могли удобно создавать объект с указанным прототипом, ECMAScript 5 включает в себя стандартную функциюObject.create, Очень упрощенная версия будет выглядеть так:

Object.create = function(prototype) {
    var Type = function () {};
    Type.prototype = prototype;
    return new Type();
};

Он просто берет на себя труд написать функцию конструктора и затем вызвать ееnew.

Когда бы вы избежали прототипов?

Полезное сравнение с популярными ОО языками, такими как Java и C #. Они поддерживают два вида наследования:

интерфейс наследство, где тыimplement interface такой, что класс обеспечивает свою собственную уникальную реализацию для каждого члена интерфейса.реализация наследство, где тыextend a class это обеспечивает реализацию некоторых методов по умолчанию.

В JavaScript прототипическое наследование является своего родареализация наследование. Таким образом, в тех ситуациях, когда (в C # или Java) вы должны были бы получить базовый класс, чтобы получить поведение по умолчанию, которое вы затем вносите в небольшие изменения с помощью переопределений, тогда в JavaScript прототипическое наследование имеет смысл.

Однако, если вы находитесь в ситуации, когда вы использовали бы интерфейсы в C # или Java, вам не нужны какие-либо особые языковые функции в JavaScript. Нет необходимости явно объявлять что-то, представляющее интерфейс, и не нужно помечать объекты как «реализующие» этот интерфейс: <, / p>

var duck = {
    quack: function() { ... }
};

duck.quack(); // we're satisfied it's a duck!

Другими словами, если каждый «тип» объекта имеет свои собственные определения «методов», то нет никакого значения в наследовании от прототипа. После этого это зависит от того, сколько экземпляров вы выделите для каждого типа. Но во многих модульных конструкциях есть только один экземпляр данного типа.

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

 GFoley8308 мая 2013 г., 23:54
+1 Сравнение с jQuery было первым ясным и кратким объяснением того, когда и зачем использовать прототипы, которые я прочитал. Большое спасибо.
 opl19 янв. 2011 г., 17:37
В своем выступлении вы упоминаете, что «это зависит от того, сколько экземпляров вы выделите для каждого типа». Но пример, на который вы ссылаетесь, не использует прототипы. Где понятие выделения экземпляра (вы все еще использовали бы «новый» здесь)? Также: скажем, у метода кряка был параметр - будет ли каждый вызов duck.quack (param) вызывать создание нового объекта в памяти (может быть, он не имеет значения, имеет ли он параметр или нет)?
 opl19 янв. 2011 г., 18:50
Спасибо, я принял ваш ответ. Но у меня все еще есть небольшая путаница с вашей точкой (1): я не понимаю, что вы подразумеваете под «большим количеством экземпляров одного типа утки». Как вы сказали в (3) каждый раз, когда вы вызываете функцию JS, в памяти создается один объект - поэтому, даже если у вас есть только один тип утки, вы не будете выделять память каждый раз, когда вызываете функцию утки (в в каком случае всегда имеет смысл использовать прототип)?
 opl19 янв. 2011 г., 16:30
Хорошее объяснение. Тогда согласитесь ли вы, что, поскольку вы считаете прототипы оптимизацией, их всегда можно использовать для улучшения вашего кода? Мне интересно, есть ли случаи, когда использование прототипов не имеет смысла или влечет за собой снижение производительности.
 Daniel Earwicker19 янв. 2011 г., 18:02
1. Я имел в виду, что если бы было большое количество экземпляров утки одного типа, то имело бы смысл изменить пример так, чтобыquack Функция находится в прототипе, с которым связано множество экземпляров утки.2. Литеральный синтаксис объекта{ ... } создает экземпляр (нет необходимости использоватьnew с этим).3. При вызове любой функции JS в памяти создается хотя бы один объект - он называетсяarguments объект и сохраняет аргументы, переданные в вызове:developer.mozilla.org/en/JavaScript/Reference/...

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

Изменение методов в объектах-прототипах или добавление методов мгновенно изменяет природу всех экземпляров соответствующего типа (типов).

Сейчас точноПочему вы бы делали все эти вещи, в основном, в зависимости от вашего собственного дизайна приложения, и того, что вам нужно делать в коде на стороне клиента. (Совсем другая история - это код внутри сервера; гораздо проще представить более масштабный «ОО» -код там).

 opl19 янв. 2011 г., 16:23
поэтому, когда я создаю экземпляр нового объекта с помощью методов-прототипов (через ключевое слово new), тогда этот объект не получает новую копию каждой функции (просто вид указателя)? Если это так, почему бы вам не захотеть использовать прототип?
 hellatan19 янв. 2011 г., 16:27
как @marcel, d'oh ... =)
 Pointy19 янв. 2011 г., 16:56
@opi да, ты прав - копия не сделана. Вместо этого символы (имена свойств) на объекте-прототипе просто как бы «присутствуют» как виртуальные части каждого объекта-экземпляра. Единственная причина, по которой люди не захотят беспокоиться об этом, - это случаи, когда объекты недолговечны и различны, или где не так много «поведения», которым можно поделиться.

Ваш ответ на вопрос