Примеры имеют очень разные результаты.
Перед рассмотрением различий следует отметить следующее:
[[Prototype]]
экземпляра. myObj.method()
), то этот внутри метода ссылается на объект. Где этот не задан вызовом или с помощью bind , он по умолчанию ссылается на глобальный объект (окно в браузере) или в строгом режиме, остается неопределенным. Итак, вот фрагменты, о которых идет речь:
var A = function () {
this.x = function () {
//do something
};
};
В этом случае переменной A
присваивается значение, которое является ссылкой на функцию. Когда эта функция вызывается с помощью A()
, функция этой функции не задается вызовом, поэтому по умолчанию используется глобальный объект, и выражение this.x
эффективно window.x
. В результате ссылка на выражение функции с правой стороны назначается window.x
.
В случае:
var A = function () { };
A.prototype.x = function () {
//do something
};
происходит нечто совсем другое. В первой строке переменной A
присваивается ссылка на функцию. В JavaScript все объекты функций имеют свойство prototype по умолчанию, поэтому нет никакого отдельного кода для создания объекта A.prototype .
Во втором line, A.prototype.x назначается ссылка на функцию. Это создаст свойство x , если оно не существует, или назначьте новое значение, если это произойдет. Таким образом, разница с первым примером заключается в том, какое свойство объекта x участвует в выражении.
Другой пример приведен ниже. Это похоже на первое (и может быть то, о чем вы хотели спросить):
var A = new function () {
this.x = function () {
//do something
};
};
В этом примере оператор new
был добавлен перед выражением функции, чтобы вызвать функцию как конструктор. При вызове с new
функция этой функции установлена для ссылки на новый объект, чье личное свойство [[Prototype]]
установлено для ссылки на общедоступный прототип конструктора . Поэтому в операторе присваивания свойство x
будет создано на этом новом объекте. Когда вызывается как конструктор, функция по умолчанию возвращает свой этот объект , поэтому нет необходимости в отдельном заявлении 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"}
Связанные Вопросы:
Sidenote: не может быть значительной экономии памяти между двумя подходами, однако использование прототипа для совместного использования методов и свойств, скорее всего, будет использовать меньше памяти, чем каждый экземпляр имея свою собственную копию.
JavaScript не является языком низкого уровня. Возможно, не очень важно думать о прототипировании или других шаблонах наследования как способ явного изменения способа выделения памяти.