Преимущества использования прототипа, против определения методов прямо в конструкторе? [дубликат]


этот вопрос уже есть ответ здесь:

  • Использование "прототипа" против "этого" в 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 264

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);  
};

преимущества методов прототипа:

  1. когда вы определяете методы через прототип, они являются общими для всех экземпляров вашего класса. В результате общий размер таких экземпляров меньше, чем если бы вы определяли методы в конструкторе; есть тесты, которые показывают, как определение метода через прототип уменьшает общий размер html-страницы и, как следствие, скорость ее загрузки.

  2. еще одно преимущество методов, определенных через прототип-это когда вы используете унаследованные классы, вы можете переопределить такие методы и в переопределенном методе производного класса вы можете вызвать метод базового класса с тем же именем, но с методами, определенными в конструкторе, вы не можете этого сделать.

прежде всего, вы должны использовать литерал объекта следующим образом:

var Class = {
  calc: function (a, b) {
    return a + b;
  }
};

эта нотация чище, а также делает очевидным, что в Javascript объекты-это просто хэши, а не что-то из рецепта, например, предопределенный класс.

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