JavaScript при использовании прототипов


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

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

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

5 81

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!

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

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

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

Так что если вы хотите создать копии объекта, как человек 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