Javascript, когда использовать прототипы

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

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

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

5 ответов


прототипы являются оптимизация.

отличным примером их использования является библиотека 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.

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

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

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

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

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

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

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

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

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


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

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.

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

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

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

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

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

теперь вы знаете, что каждый автомобиль должен будет ездить, включаться и т. д. Вместо того, чтобы присоединять метод непосредственно к Car() class (который занимает память на каждый созданный экземпляр), вы можете прикрепить методы к прототипу вместо этого (создавая методы только один раз), поэтому предоставляя доступ к этим методам как к новому 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'

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

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

теперь точно почему вы бы сделали все эти вещи в основном являются функцией вашего собственного дизайна приложений и того, что вам нужно сделать в клиентском коде. (Совершенно другая история была бы кодом внутри сервера; гораздо легче представить себе более масштабный код " OO " там.)


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

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

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

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