Позвольте мне дать вам более полный ответ, который я узнал во время курса обучения 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
, который имеет свойство конструктора. И так 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
в примерах).
Это то, что позволяет нам применять такие понятия, как суперкласс или подкласс в JavaScript.
Не стесняйтесь добавлять или редактировать. После завершения я могу сделать это вики-сообществом, может быть.