Использование 'prototype' против 'this' в JavaScript?

Какая разница между

var A = function () {
    this.x = function () {
        //do something
    };
};

и

var A = function () { };
A.prototype.x = function () {
    //do something
};

Ответ 1

Примеры имеют очень разные результаты.

Прежде чем смотреть на различия, следует отметить следующее:

  • Прототип конструктора предоставляет способ обмена методами и значениями между экземплярами через свойство private [[Prototype]] экземпляра.
  • Функция это устанавливается тем, как функция вызывается или использованием bind (здесь не обсуждается). Если функция вызывается для объекта (например, myObj.method()), то это внутри метода ссылается на объект. Если это не установлено вызовом или использованием bind, по умолчанию используется глобальный объект (окно в браузере) или в строгом режиме, он остается неопределенным.
  • JavaScript является объектно-ориентированным языком, т.е. большинство значений являются объектами, включая функции. (Строки, числа и логические значения не являются объектами.)

Итак, вот такие фрагменты:

var A = function () {
    this.x = function () {
        //do something
    };
};

В этом случае переменной A присваивается значение, которое является ссылкой на функцию. Когда эта функция вызывается с помощью A(), функция this не устанавливается вызовом, поэтому по умолчанию используется глобальный объект, а выражение this.x является эффективным window.x. В результате ссылка на выражение функции в правой части назначается для window.x.

В случае:

var A = function () { };
A.prototype.x = function () {
    //do something
};

происходит что-то совсем другое. В первой строке переменной A назначается ссылка на функцию. В JavaScript все объекты функций по умолчанию имеют свойство prototype, поэтому нет отдельного кода для создания объекта A.prototype.

Во второй строке A.prototype.x присваивается ссылка на функцию. Это создаст свойство x, если оно не существует, или назначит новое значение, если оно существует. Таким образом, разница с первым примером, в котором свойство объекта x участвует в выражении.

Другой пример ниже. Это похоже на первый (и, возможно, о чем вы хотели спросить):

var A = new function () {
    this.x = function () {
        //do something
    };
};

В этом примере оператор new был добавлен перед выражением функции, поэтому функция вызывается как конструктор. Когда вызывается с new, функция this устанавливается для ссылки на новый Object, чье private [[Prototype]] свойство установлено для ссылки на открытый прототип конструктора. Таким образом, в операторе присваивания для этого нового объекта будет создано свойство x. При вызове в качестве конструктора функция возвращает свой объект this по умолчанию, поэтому нет необходимости в отдельном return this; выражение.

Чтобы проверить, что A имеет свойство x:

console.log(A.x) // function () {
                 //   //do something
                 // };

Это необычное использование new, поскольку единственный способ ссылаться на конструктор - через A.constructor. Было бы гораздо более распространенным сделать:

var A = function () {
    this.x = function () {
        //do something
    };
};
var a = new A();

Другим способом достижения подобного результата является использование выражения, вызываемого немедленно:

var A = (function () {
    this.x = function () {
        //do something
    };
}());

В этом случае A присваивает возвращаемое значение вызова функции с правой стороны. Здесь снова, так как это не установлено в вызове, оно будет ссылаться на глобальный объект, и this.x является эффективным window.x. Поскольку функция ничего не возвращает, значение A будет undefined.

Эти различия между двумя подходами также проявляются, если вы сериализуете и десериализуете свои объекты Javascript в/из JSON. Методы, определенные в прототипе объекта, не сериализуются при сериализации объекта, что может быть удобно, когда, например, вы хотите сериализовать только части данных объекта, но не его методы:

var A = function () { 
    this.objectsOwnProperties = "are serialized";
};
A.prototype.prototypeProperties = "are NOT serialized";
var instance = new A();
console.log(instance.prototypeProperties); // "are NOT serialized"
console.log(JSON.stringify(instance)); 
// {"objectsOwnProperties":"are serialized"} 

Смежные вопросы:

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

JavaScript не является языком низкого уровня. Возможно, не очень полезно думать о прототипировании или других шаблонах наследования как о способе явного изменения способа выделения памяти.

Ответ 2

Как говорили другие, первая версия, используя "this", приводит к каждому экземпляру класса A, имеющему собственную независимую копию метода функции "x". В то время как использование "prototype" будет означать, что каждый экземпляр класса A будет использовать ту же копию метода "x".

Вот какой код, чтобы показать эту тонкую разницу:

// x is a method assigned to the object using "this"
var A = function () {
    this.x = function () { alert('A'); };
};
A.prototype.updateX = function( value ) {
    this.x = function() { alert( value ); }
};

var a1 = new A();
var a2 = new A();
a1.x();  // Displays 'A'
a2.x();  // Also displays 'A'
a1.updateX('Z');
a1.x();  // Displays 'Z'
a2.x();  // Still displays 'A'

// Here x is a method assigned to the object using "prototype"
var B = function () { };
B.prototype.x = function () { alert('B'); };

B.prototype.updateX = function( value ) {
    B.prototype.x = function() { alert( value ); }
}

var b1 = new B();
var b2 = new B();
b1.x();  // Displays 'B'
b2.x();  // Also displays 'B'
b1.updateX('Y');
b1.x();  // Displays 'Y'
b2.x();  // Also displays 'Y' because by using prototype we have changed it for all instances

Как отмечали другие, существуют разные причины выбора одного или другого метода. Мой образец просто предназначен, чтобы четко продемонстрировать разницу.

Ответ 3

Возьмите эти 2 примера:

var A = function() { this.hey = function() { alert('from A') } };

против

var A = function() {}
A.prototype.hey = function() { alert('from prototype') };

Большинство людей здесь (особенно ответы с самым высоким рейтингом) пытались объяснить, чем они отличаются, не объясняя ПОЧЕМУ. Я думаю, что это неправильно, и если вы сначала поймете основы, разница станет очевидной. Давайте сначала попробуем объяснить основы...

а) Функция - это объект в JavaScript. КАЖДЫЙ объект в JavaScript получает внутреннее свойство (то есть вы не можете получить к нему доступ, как и к другим свойствам, за исключением, может быть, в браузерах, подобных Chrome), часто называемом __proto__ (вы можете фактически ввести anyObject.__proto__ в Chrome, чтобы увидеть, на что он ссылается. Это просто свойство, не более того. Свойство в JavaScript = переменная внутри объекта, ничего более. Что делают переменные? Они указывают на вещи.

Так на что же __proto__ это свойство __proto__? Ну, обычно другой объект (мы объясним, почему позже). Единственный способ заставить JavaScript для свойства __proto__ НЕ указывать на другой объект - это использовать var newObj = Object.create(null). Даже если вы сделаете это, свойство __proto__ STILL существует как свойство объекта, просто оно не указывает на другой объект, оно указывает на null.

Здесь большинство людей запутываются:

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

var A = [];
A.prototype // undefined
A = function() {}
A.prototype // {} // got created when function() {} was defined

A.prototype от свойства __proto__. В нашем примере "A" теперь имеет ДВА свойства, называемые "prototype" и __proto__. Это большая путаница для людей. Свойства prototype и __proto__ никоим образом не связаны, это разные вещи, указывающие на отдельные значения.

Вы можете задаться вопросом: почему JavaScript имеет свойство __proto__ созданное для каждого отдельного объекта? Ну, одним словом: делегирование. Когда вы вызываете свойство для объекта, а у объекта его нет, JavaScript ищет объект, на который ссылается __proto__ чтобы выяснить, есть ли у него его. Если его нет, он просматривает свойство __proto__ этого объекта и т.д. До тех пор, пока цепочка не закончится. Так называется прототип цепочки. Конечно, если __proto__ не указывает на объект, а вместо этого указывает на null, а жесткая удача, JavaScript понимает, что и возвратит вас undefined для свойства.

Вы также можете задаться вопросом, почему JavaScript создает свойство с именем prototype для функции при ее определении? Потому что он пытается обмануть вас, да обмануть вас, что он работает как языки на основе классов.

Давайте продолжим с нашим примером и создадим "объект" из A:

var a1 = new A();

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

Тот факт, что вы использовали оператор new перед вызовом функции A() сделал что-то ДОПОЛНИТЕЛЬНОЕ в фоновом режиме. new ключевое слово создало новый объект, который теперь ссылается на a1 и этот объект пуст. Вот что происходит дополнительно:

Мы говорили, что в каждом определении функции создается новое свойство с именем prototype (к которому вы можете обращаться, в отличие от свойства __proto__)? Ну, это свойство сейчас используется.

Итак, мы находимся в точке, где у нас есть свежеиспеченный пустой объект a1. Мы сказали, что все объекты в JavaScript имеют внутреннее свойство __proto__ которое указывает на что-то (у a1 оно есть), независимо от того, является ли оно нулевым или другим объектом. Оператор new устанавливает то свойство __proto__ чтобы оно указывало на свойство prototype функции. Прочитайте это снова. Это в основном это:

a1.__proto__ = A.prototype;

Мы сказали, что A.prototype - это не что иное, как пустой объект (если мы не изменим его на что-то еще до определения a1). Так что теперь в основном a1.__proto__ указывает на то же, на что указывает A.prototype, то есть на этот пустой объект. Они оба указывают на один и тот же объект, который был создан, когда произошла эта строка:

A = function() {} // JS: cool. let also create A.prototype pointing to empty {}

Теперь происходит другое, когда обрабатывается оператор var a1 = new A(). В основном A() выполняется, и если A что-то вроде этого:

var A = function() { this.hey = function() { alert('from A') } };

Все эти вещи внутри function() { } будут выполняться. Когда вы достигнете this.hey.., this изменится на a1 и вы получите это:

a1.hey = function() { alert('from A') }

Я не буду рассказывать, почему this меняется на a1 но это отличный ответ, чтобы узнать больше.

Итак, подведем итог: когда вы делаете var a1 = new A(), в фоновом режиме происходит 3 вещи:

  1. Совершенно новый пустой объект создается и присваивается a1. a1 = {}
  2. a1.__proto__ назначается так, чтобы указывать на то же, на что указывает A.prototype (еще один пустой объект {})

  3. Функция A() выполняется с this набором нового пустого объекта, созданного на шаге 1 (прочитайте ответ, на который я ссылался выше, чтобы узнать, почему this меняется на a1)

Теперь давайте попробуем создать еще один объект:

var a2 = new A();

Шаги 1,2,3 повторится. Вы что-то замечаете? Ключевое слово - повтор. Шаг 1: a2 будет новым пустым объектом, шаг 2: его свойство __proto__ будет указывать на то же, на что указывает A.prototype и, что наиболее важно, шаг 3: функция A() выполняется снова, а это означает, что a2 получит hey свойство, содержащее функцию. a1 и a2 имеют два свойства SEPARATE с именем hey которые указывают на 2 отдельные функции! Теперь у нас есть дубликаты функций в одних и тех же двух разных объектах, делающих одно и то же, упс... Вы можете представить, как это повлияет на память, если у нас есть 1000 объектов, созданных с new A, после того как все объявления функций занимают больше памяти, чем что-то вроде числа 2 Итак, как мы можем предотвратить это?

Помните, почему свойство __proto__ существует для каждого объекта? Таким образом, если вы извлекаете свойство yoMan для a1 (которое не существует), будет рассматриваться его свойство __proto__, которое, если оно является объектом (и в большинстве случаев это так), будет проверять, содержит ли оно yoMan, и если оно нет, он будет обращаться к этому объекту __proto__ и т.д. Если это произойдет, он примет значение этого свойства и отобразит его вам.

Поэтому кто-то решил использовать этот факт + тот факт, что при создании a1 его свойство __proto__ указывает на тот же (пустой) объект, на A.prototype указывает A.prototype и делает это:

var A = function() {}
A.prototype.hey = function() { alert('from prototype') };

Здорово! Теперь, когда вы создаете a1, он снова проходит все 3 шага, описанных выше, и на шаге 3 он ничего не делает, так как function A() имеет ничего для выполнения. И если мы сделаем:

a1.hey

Он увидит, что a1 не содержит hey и проверит свой __proto__ свойства __proto__ чтобы увидеть, есть ли он, что имеет место.

При таком подходе мы исключаем часть из шага 3, где функции дублируются при каждом создании нового объекта. Вместо того, чтобы a1 и a2 имели отдельное свойство hey, теперь ни у кого из них его нет. Который, я полагаю, ты сам уже понял. Это хорошо... если вы понимаете __proto__ и Function.prototype, подобные вопросы будут довольно очевидными.

ПРИМЕЧАНИЕ. Некоторые люди склонны не называть внутреннее свойство Prototype как __proto__, я использовал это имя в посте, чтобы четко отличить его от свойства Functional.prototype как две разные вещи.

Ответ 4

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

Причиной использования первой формы является доступ к "частным членам". Например:

var A = function () {
    var private_var = ...;

    this.x = function () {
        return private_var;
    };

    this.setX = function (new_x) {
        private_var = new_x;
    };
};

Из-за правил определения javascript private_var доступен для функции, назначенной this.x, но не за пределами объекта.

Ответ 5

Первый пример изменяет интерфейс только для этого объекта. Второй пример изменяет интерфейс для всего объекта этого класса.

Ответ 6

Конечная проблема с использованием this вместо prototype заключается в том, что при переопределении метода конструктор базового класса все равно будет ссылаться на переопределенный метод. Рассмотрим это:

BaseClass = function() {
    var text = null;

    this.setText = function(value) {
        text = value + " BaseClass!";
    };

    this.getText = function() {
        return text;
    };

    this.setText("Hello"); // This always calls BaseClass.setText()
};

SubClass = function() {
    // setText is not overridden yet,
    // so the constructor calls the superclass' method
    BaseClass.call(this);

    // Keeping a reference to the superclass' method
    var super_setText = this.setText;
    // Overriding
    this.setText = function(value) {
        super_setText.call(this, "SubClass says: " + value);
    };
};
SubClass.prototype = new BaseClass();

var subClass = new SubClass();
console.log(subClass.getText()); // Hello BaseClass!

subClass.setText("Hello"); // setText is already overridden
console.log(subClass.getText()); // SubClass says: Hello BaseClass!

против

BaseClass = function() {
    this.setText("Hello"); // This calls the overridden method
};

BaseClass.prototype.setText = function(value) {
    this.text = value + " BaseClass!";
};

BaseClass.prototype.getText = function() {
    return this.text;
};

SubClass = function() {
    // setText is already overridden, so this works as expected
    BaseClass.call(this);
};
SubClass.prototype = new BaseClass();

SubClass.prototype.setText = function(value) {
    BaseClass.prototype.setText.call(this, "SubClass says: " + value);
};

var subClass = new SubClass();
console.log(subClass.getText()); // SubClass says: Hello BaseClass!

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

var A = function (param1) {
    var privateVar = null; // Private variable

    // Calling this.setPrivateVar(param1) here would be an error

    this.setPrivateVar = function (value) {
        privateVar = value;
        console.log("setPrivateVar value set to: " + value);

        // param1 is still here, possible memory leak
        console.log("setPrivateVar has param1: " + param1);
    };

    // The constructor logic starts here possibly after
    // many lines of code that define methods

    this.setPrivateVar(param1); // This is valid
};

var a = new A(0);
// setPrivateVar value set to: 0
// setPrivateVar has param1: 0

a.setPrivateVar(1);
//setPrivateVar value set to: 1
//setPrivateVar has param1: 0

против

var A = function (param1) {
    this.setPublicVar(param1); // This is valid
};
A.prototype.setPublicVar = function (value) {
    this.publicVar = value; // No private variable
};

var a = new A(0);
a.setPublicVar(1);
console.log(a.publicVar); // 1

Ответ 7

Каждый объект связан с прототипом объекта. При попытке доступа к объекту, который не существует, JavaScript будет выглядеть в объекте-прототипе объекта для этого свойства и вернуть его, если он существует.

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


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

var A = function () {
    this.x = function () {
        //do something
    };
};

var a = new A();    // constructor function gets executed
                    // newly created object gets an 'x' property
                    // which is a function
a.x();              // and can be called like this

Во втором примере вы добавляете свойство объекта-прототипа, к которому указывают все экземпляры, созданные с помощью A.

var A = function () { };
A.prototype.x = function () {
    //do something
};

var a = new A();    // constructor function gets executed
                    // which does nothing in this example

a.x();              // you are trying to access the 'x' property of an instance of 'A'
                    // which does not exist
                    // so JavaScript looks for that property in the prototype object
                    // that was defined using the 'prototype' property of the constructor

В заключение, в первом примере копия функции назначается каждому экземпляру. Во втором примере одна копия функции разделяется всеми экземплярами.

Ответ 8

Какая разница? = > Много.

Я думаю, что версия this используется для включения инкапсуляции, т.е. скрытия данных. Это помогает манипулировать частными переменными.

Давайте посмотрим на следующий пример:

var AdultPerson = function() {

  var age;

  this.setAge = function(val) {
    // some housekeeping
    age = val >= 18 && val;
  };

  this.getAge = function() {
    return age;
  };

  this.isValid = function() {
    return !!age;
  };
};

Теперь структуру prototype можно применять следующим образом:

У разных взрослых разные возрасты, но все взрослые получают одинаковые права.
Поэтому мы добавляем его с использованием прототипа, а не этого.

AdultPerson.prototype.getRights = function() {
  // Should be valid
  return this.isValid() && ['Booze', 'Drive'];
};

Давайте посмотрим на реализацию сейчас.

var p1 = new AdultPerson;
p1.setAge(12); // ( age = false )
console.log(p1.getRights()); // false ( Kid alert! )
p1.setAge(19); // ( age = 19 )
console.log(p1.getRights()); // ['Booze', 'Drive'] ( Welcome AdultPerson )

var p2 = new AdultPerson;
p2.setAge(45);    
console.log(p2.getRights()); // The same getRights() method, *** not a new copy of it ***

Надеюсь, что это поможет.

Ответ 9

Прототип - это шаблон класса; который применяется ко всем будущим его экземплярам. В то время как это конкретный экземпляр объекта.

Ответ 10

Позвольте мне дать более полный ответ, который я узнал во время учебного курса JavaScript.

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

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

Вы показали два шаблона в своем вопросе. Я попытаюсь объяснить еще два и попытаться объяснить различия, если это уместно. Не стесняйтесь редактировать/продлевать. Во всех примерах речь идет о объекте автомобиля, который имеет местоположение и может двигаться.

Образец декоратора объекта

Не уверен, что этот шаблон по-прежнему актуальен в настоящее время, но он существует. И это хорошо знать об этом. Вы просто передаете объект и свойство функции декоратора. Декоратор возвращает объект с помощью свойства и метода.

var carlike = function(obj, loc) {
    obj.loc = loc;
    obj.move = function() {
        obj.loc++;
    };
    return obj;
};

var amy = carlike({}, 1);
amy.move();
var ben = carlike({}, 9);
ben.move();

Функциональные классы

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

В этом случае Car является функцией (также думать объект), который можно вызвать, как вы привыкли делать. Он имеет свойство methods (которое является объектом с функцией move). Когда вызывается Car, вызывается функция extend, которая делает некоторую магию, и расширяет функцию Car (мыслящий объект) с помощью методов, определенных в methods.

Этот пример, хотя и отличается, ближе всего подходит к первому примеру в вопросе.

var Car = function(loc) {
    var obj = {loc: loc};
    extend(obj, Car.methods);
    return obj;
};

Car.methods = {
    move : function() {
        this.loc++;
    }
};

var amy = Car(1);
amy.move();
var ben = Car(9);
ben.move();

Прототипные классы

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

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

Однако есть один интересный момент: Каждый объект prototype имеет свойство удобства constructor, которое указывает на функцию (объект мысли), к которой она привязана.

Относительно последних трех строк:

В этом примере Car ссылки на объект prototype, который связывается через constructor с Car сам, т.е. Car.prototype.constructor сам Car. Это позволяет вам определить, какая функция конструктора построила определенный объект.

amy.constructor поиск завершается с ошибкой и поэтому делегируется Car.prototype, который имеет свойство constructor. И поэтому amy.constructor Car.

Кроме того, amy является instanceof Car. Оператор instanceof работает, наблюдая, можно ли найти объект прототипа правого операнда (Car) в любом месте в цепочке прототипов левого операнда (amy).

var Car = function(loc) {
    var obj = Object.create(Car.prototype);
    obj.loc = loc;
    return obj;
};

Car.prototype.move = function() {
        this.loc++;
};

var amy = Car(1);
amy.move();
var ben = Car(9);
ben.move();

console.log(Car.prototype.constructor);
console.log(amy.constructor);
console.log(amy instanceof Car);

Некоторые разработчики могут быть сбиты с толку в начале. Пример ниже:

var Dog = function() {
  return {legs: 4, bark: alert};
};

var fido = Dog();
console.log(fido instanceof Dog);

Оператор instanceof возвращает false, поскольку прототип Dog не может быть найден в цепочке прототипов fido. fido - это простой объект, созданный с помощью литерала объекта, т.е. он просто передает Object.prototype.

Псевдоклассические шаблоны

Это действительно просто еще одна форма прототипа в упрощенной форме и более знакомая для тех, кто программирует на Java, например, поскольку использует конструктор new.

Он делает то же самое, что и в прототипальном шаблоне, это просто синтаксическая надпись над прототипным шаблоном.

Однако основное отличие заключается в том, что в механизмах JavaScript реализованы оптимизации, которые применяются только при использовании псевдоклассического шаблона. Подумайте о псевдоклассическом шаблоне, вероятно, более быстрой версии прототипа; объектные отношения в обоих примерах одинаковы.

var Car = function(loc) {
    this.loc = loc;
};

Car.prototype.move = function() {
        this.loc++;
};

var amy = new Car(1);
amy.move();
var ben = new Car(9);
ben.move();

Наконец, не должно быть слишком сложно понять, как может быть реализовано объектно-ориентированное программирование. Есть два раздела.

Один раздел, который определяет общие свойства/методы в прототипе (цепочке).

И еще один раздел, где вы помещаете определения, которые отличают объекты друг от друга (loc variable в примерах).

Это позволяет нам применять в JavaScript такие понятия, как суперкласс или подкласс.

Не стесняйтесь добавлять или редактировать. Еще раз, я мог бы сделать это вики-сообществом.

Ответ 11

Я знаю, что этому ответили до смерти, но я хотел бы показать фактический пример различий в скорости.

Функция непосредственно на объекте

Функция на прототипе

Здесь мы создаем 2 000 000 новых объектов с помощью метода print в Chrome. Мы сохраняем каждый объект в массиве. Помещение print на прототип занимает около 1/2.

Ответ 12

Я считаю, что @Matthew Crumley прав. Они функционально, если не структурно, эквивалентны. Если вы используете Firebug для просмотра объектов, созданных с помощью new, вы можете видеть, что они одинаковы. Однако, мое предпочтение было бы следующим. Я предполагаю, что это просто похоже на то, к чему я привык в С#/Java. То есть, определите класс, определите поля, конструктор и методы.

var A = function() {};
A.prototype = {
    _instance_var: 0,

    initialize: function(v) { this._instance_var = v; },

    x: function() {  alert(this._instance_var); }
};

EDIT Не означает, что область действия переменной была закрытой, я просто пытался проиллюстрировать, как я определяю свои классы в javascript. Имя переменной было изменено, чтобы отразить это.

Ответ 13

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

Я собрал jsperf, чтобы показать это. Существует огромное различие во времени, которое требуется для создания экземпляра класса, хотя это действительно актуально, если вы делаете много случаев.

http://jsperf.com/functions-in-constructor-vs-prototype

Ответ 14

Подумайте о статически типизированном языке, вещи в prototype являются статическими, а вещи в this связаны с экземплярами.