Подтвердить что ты не робот

Какой лучший способ создания Javascript-классов?

Возможный дубликат:
Использование прототипа против этого в Javascript? Объектно-ориентированные вопросы в Javascript

Можете ли вы, пожалуйста, порекомендовать, какое из следующих является лучшим или их плюсы и минусы?

Способ 1

function User() {

    this.name = "my name";
    this.save = function() {

    };
}

Способ 2

function User() {

    this.name = "my name";
}

User.prototype.save = function() {

}
4b9b3361

Ответ 1

Исходя из фона в Java и PHP, я изначально боролся со всей концепцией класса в javascript. Вот несколько вещей, о которых нужно подумать:

Строительство

Во-первых, поскольку вы, вероятно, будете определять свои классы как..

Customer = function () {}
Customer.prototype = new Person();

В конечном итоге вы столкнетесь со всеми кошмарами кода, если вы определяете свойства и методы во время построения. Причина заключается в том, что кусок кода, например Customer.prototype = new Person();, требует, чтобы Person вызывался в конструкторе Customer для истинного наследования.. в противном случае вам будет нужно знать, что изначально устанавливается в оригинале. Возьмем следующий пример:

Person = function (name) {
    this.name = name;
    this.getName = function () {return this.name}
}
Customer = function (name) {
    this.name = name;
}
Customer.prototype = new Person();

Теперь мы собираемся обновить Person, чтобы установить, являются ли они "новыми":

Person = function (name, isNew) {
    this.name = name;
    this.isNew = isNew;
    this.getName = function () {return (this.isNew ? "New " : "") + this.name; }
}

Теперь на любом "классе", который наследуется от Лица, вы должны обновить конструктор, чтобы следовать форме. Вы можете обойти это, сделав что-то вроде:

Customer = function () {
    Person.apply(this, arguments);
}

Это вызовет "Человек" в рамках нового "Заказчика", что позволит вам не знать о конструкции Person.

Speed ​​

http://jsperf.com/inherited-vs-assigned

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

Person = function (name) {
    this.name = name;
    this.getName = function () {return this.name}
}

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

Общие свойства

Это всегда меня. Скажем, у вас есть что-то вроде следующего:

Person = function () {
    this.jobs = {};
    this.setJob = function (jobTitle, active) {this.jobs[jobTitle] = active; }
}

Employee = function () {}
Employee.prototype = new Person();

var bob = new Employee();
bob.setJob('janitor', true);

var jane = new Employee();
console.log(jane.jobs);

Угадайте, что? Джейн дворник! Без шуток! Вот почему. Поскольку вы не определили this.jobs как новый объект при создании экземпляра Employee, теперь он просто ищет цепочку прототипов, пока не найдет "задания" и не использует их как есть. Весело, правда?

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

Employee = function () { Person.apply(this); }

Это заставляет "Person" создавать новый "this.jobs".

Частные переменные Поскольку в javascript нет ничего действительно "private", единственный способ получить частные переменные - создать их в конструкторе, а затем сделать все, что опирается на них, инициализировать в конструкторе.

Person = function () {
    var jobs = {};
    this.setJob = function (jobTitle, active) {jobs[jobTitle] = active; }
    this.getJob = function (jobTitle) { return jobs[jobTitle]; }
}

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

Предложение

http://ejohn.org/blog/simple-javascript-inheritance/

Это супер базовый класс. Это легко. Оно работает. И он сделает то, что вам нужно, чтобы сделать 90% времени, не имея дело со всем безумством, которое может предложить javascript:)

Ответ 2

Best - очень субъективный термин.

Метод 1 дает возможность действительно частных переменных. например:

function User() {
   var name = "fred";
   this.getName = function () { return name;};
}

Метод 2 будет использовать меньше памяти, поскольку одна функция сохранения будет использоваться всеми объектами пользователя.

"Лучшее" будет определяться вашими конкретными требованиями.

Ответ 3

JavaScript - это язык, основанный на объекте, а не язык, основанный на классе. Совместное поведение, которое является концепцией класса, реализуется путем связывания прототипов.

Метод 1 не создает класс. Каждый раз, когда вы вызываете его, вы создаете атрибуты и функции, как определено, и они НЕ используются совместно с другими "экземплярами". Если вы замените this.save, то только один экземпляр изменит поведение.

Способ 2 реализует совместное поведение. Поэтому это то, что люди ассоциируют с классами и экземплярами. Если вы замените this.save на другую функцию, то все производные экземпляры немедленно будут иметь новое поведение.

Если "наилучший" означает отсутствие памяти, требующей переопределения функций и совместного использования общего поведения (это то, на что основано программирование на основе классов), способ 2 - путь.

Ответ 4

Как отмечали другие, существуют два основных отличия:

  • Метод 1 создаст новую функцию для каждого экземпляра User
  • Метод 1 будет иметь доступ к локальным переменным в области конструктора

Вот пример, чтобы продемонстрировать это:

function User() {

    var name = "my name";

    this.foo = function() {
        // one function per User instance
        // can access 'name' variable
    };
}

User.prototype.bar = function() {
    // one function shared by all User instances
    // cannot access 'name' variable
};

var a = new User();
var b = new User();

console.log(a.foo === b.foo); // false; each instance has its own foo()
console.log(a.bar === b.bar); // true; both instances use the same bar()