Причина использования .prototype в Javascript - PullRequest
4 голосов
/ 22 декабря 2009

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

Какие преимущества использования:

RobsObject = function(data){
    this.instanceID = data.instanceID;
    this._formButton = document.getElementById('formSubmit_' + this.instanceID);
    if(this._formButton)
    {
        //set a click listener that
        //points to this._onSubmit, this._onSuccess, and this.onFailure
    }
};

RobsObject.prototype = {
    _onSubmit: function(type, args)
    {
        //make an ajax call
    },

    _onSuccess: function(type, args)
    {
        //display data on the page
    },

    _onFailure: function(type, args)
    {
        //show an alert of some kind
    },
};

В отличие от объявления ваших функций внутри объекта, таких как:

RobsObject = function(data){
    this.instanceID = data.instanceID;
    this._formButton = document.getElementById('formSubmit_' + this.instanceID);
    if(this._formButton)
    {
        //set a click listener that
        //points to this._onSubmit, this._onSuccess, and this.onFailure
    }

    this._onSubmit = function(type, args)
    {
        //make an ajax call
    }

    this._onSuccess = function(type, args)
    {
        //display data on the page
    }

    this._onFailure = function(type, args)
    {
        //show an alert of some kind
    }
};

Спасибо.

Редактировать: Как многие из вас отмечали, что мои функции во втором фрагменте кода должны иметь «this» перед ними, чтобы быть публичными. И я добавил это. Просто ошибка с моей стороны.

Ответы [ 3 ]

14 голосов
/ 22 декабря 2009

Все, что объявлено в функции prototype функции конструктора, совместно используется всеми экземплярами этой функции конструктора. Если вы определяете функции в функции конструктора, то каждый экземпляр получает свою собственную копию функции, которая тратит впустую память (и потенциально может вызвать проблемы, если вы сравните свойства между двумя экземплярами позже).

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

MyObject = functon() {
  // ...

  this.myMethod = function() {
    // ...
  };
}

У Дугласа Крокфорда есть хорошее описание прототипического наследования, которое определенно стоит проверить: Прототипическое наследование в JavaScript .

ОБНОВЛЕНИЕ: краткое описание прототипа

Когда вы создаете новый объект с помощью функции конструктора, значение свойства prototype функции назначается как прототип нового объекта . (Да, имена сбивают с толку!) Это очень похоже на назначение суперкласса на языке классов (но не совсем! Читайте страницу Крокфорда!)

// MyObject constructor function:
MyObject = function() {
  this.a = 1;
}

// Define an object to use as a prototype.
var thePrototype = { b: 2 };

// Assign thePrototype as the prototype object for new instances of MyObject.
MyObject.prototype = thePrototype;

// Create an instance of MyObject.
var x = new MyObject();
// Everything in thePrototype is available to x.
console.log(x.b);

// x's prototype is a reference to thePrototype, so updating it affects x.
thePrototype.c = 3;
console.log(x.c);

// Setting properties on x always sets them *on x*, even if the property is
//  defined on the prototype:
x.b = 0;
y = new MyObject();
console.log(x.b);
console.log(y.b);
3 голосов
/ 22 декабря 2009

Ответ - память. Если вы поместите элементы внутри самого объекта, то КАЖДЫЙ экземпляр этого объекта будет содержать (в памяти) все элементы. С другой стороны, если вы используете прототип, он существует только один раз, и все экземпляры получат доступ к этим членам, как если бы они были их собственными.

0 голосов
/ 22 декабря 2009

В первом случае объект, построенный с new RobsObject(), имеет функции _onSubmit(), _onSuccess() в качестве своих свойств. Это так называемые публичные функции объекта.

Во втором случае эти функции не являются свойствами new RobsObject(). Тем не менее, они будут видны для любой из «публичных» функций (в вашем случае их нет). По сути, они являются частными функциями.

Однако, если вы написали свой второй фрагмент таким образом ...

RobsObject = function(data){
    this.instanceID = data.instanceID;
    this._formButton = document.getElementById('formSubmit_' + this.instanceID);
    if(this._formButton)
    {
        //set a click listener that
        //points to this._onSubmit, this._onSuccess, and this.onFailure
    }

    this._onSubmit = function(type, args)
    {
        //make an ajax call
    }

    this._onSuccess = function(type, args)
    {
        //display data on the page
    }

    this._onFailure = function(type, args)
    {
        //show an alert of some kind
    }
};

результат тот же.

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

Например,

function MyConstructor() {
    var myPrivate = function() {
    }

    this.myPublic1 = function() {
        myPrivate();
    }

    this.myPublic2 = function() {
        myPrivate();
    }

}

myPrivate() - это функция, видимая обеим общедоступным функциям.

...