Преимущества использования прототипа, против определения методов прямо в конструкторе? [дубликат]
этот вопрос уже есть ответ здесь:
- Использование "прототипа" против "этого" в JavaScript? 14 ответов
мне интересно, есть ли какие-либо преимущества использования любого из них по сравнению с другими, и в какую сторону я должен идти?
конструктор подход:
var Class = function () {
this.calc = function (a, b) {
return a + b;
};
};
прототип подход:
var Class = function () {};
Class.prototype.calc = function (a, b) {
return a + b;
};
мне не нравится, что, используя прототип, определения методов отделены от класса, и я не знаю, есть ли какая-либо конкретная причина, по которой я должен использовать это только в первом подходе.
кроме того, есть ли какое-либо преимущество использования литерала функции для определения "класса", а не только определения функции:
var Class = function () {};
vs
function Class () {};
спасибо!
4 ответа:
методы, которые наследуются через цепочку прототипов, могут быть изменены универсально для всех экземпляров, например:
function Class () {} Class.prototype.calc = function (a, b) { return a + b; } // Create 2 instances: var ins1 = new Class(), ins2 = new Class(); // Test the calc method: console.log(ins1.calc(1,1), ins2.calc(1,1)); // -> 2, 2 // Change the prototype method Class.prototype.calc = function () { var args = Array.prototype.slice.apply(arguments), res = 0, c; while (c = args.shift()) res += c; return res; } // Test the calc method: console.log(ins1.calc(1,1,1), ins2.calc(1,1,1)); // -> 3, 3
обратите внимание, как меняется метод, применяемый в обоих случаях? Это потому что
ins1
иins2
одинаковые
преимущество подхода прототипа эффективность. Есть один
calc()
объект функции распределены между всемиClass
объекты (под которыми я подразумеваю объекты, созданные путем вызоваClass
конструктор). Другой способ (назначение методов в конструкторе) создает новый объект функции для каждого
var YourClass = function(){ var privateField = "somevalue"; this.publicField = "somevalue"; this.instanceMethod1 = function(){ //you may access both private and public field from here: //in order to access public field, you must use "this": alert(privateField + "; " + this.publicField); }; } YourClass.prototype.instanceMethod2 = function(){ //you may access only public field 2 from this method, but not private fields: alert(this.publicField); //error: drawaback of prototype methods: alert(privateField); };
преимущества методов прототипа:
когда вы определяете методы через прототип, они являются общими для всех экземпляров вашего класса. В результате общий размер таких экземпляров меньше, чем если бы вы определяли методы в конструкторе; есть тесты, которые показывают, как определение метода через прототип уменьшает общий размер html-страницы и, как следствие, скорость ее загрузки.
еще одно преимущество методов, определенных через прототип-это когда вы используете унаследованные классы, вы можете переопределить такие методы и в переопределенном методе производного класса вы можете вызвать метод базового класса с тем же именем, но с методами, определенными в конструкторе, вы не можете этого сделать.
прежде всего, вы должны использовать литерал объекта следующим образом:
var Class = { calc: function (a, b) { return a + b; } };
эта нотация чище, а также делает очевидным, что в Javascript объекты-это просто хэши, а не что-то из рецепта, например, предопределенный класс.
разница между определениями заключается в том, что при добавлении метода в прототип будет создан только один метод в памяти для всех экземпляров. Так что если у вас есть универсальный метод и объект, который создается/используется в нескольких экземплярах вы должны добавить метод в прототип.