2010-05-25 3 views
1

Недавно я увидел следующий код, который создает класс в JavaScript:Вопрос о конкретной схеме определения класса Javascript

var Model.Foo = function(){ 
    // private stuff 
    var a, b; 

    // public properties 
    this.attr1 = ''; 
    this.attr2 = ''; 

    if(typeof Model.Foo._init === 'undefined'){ 
    Model.Foo.prototype = { 
     func1 : function(){ //...}, 
     func2 : function(){ //... }, 
     //other prototype functions 
    } 
    } 
    Model.Foo._init = true; 
} 

// Instantiate and use the class as follows: 
var foo = new Model.Foo(); foo.func1(); 

Я предполагаю, что переменная _init используются, чтобы убедиться, что мы не определяем прототип снова , Кроме того, я считаю, что код более читабельен, так как я помещаю все в функциональный блок (так что в oop-talk все атрибуты и методы находятся в одном месте). Вы видите какие-либо проблемы с кодом выше? Любые подводные камни использования этого шаблона, если мне нужно создать много классов в большом проекте?

ответ

1

Это просто кажется излишне сложным. Вам нужно быть дисциплинированным, чтобы не использовать какие-либо параметры или локальные переменные Model.Foo в реализации расширения прототипа. Его нечетным является перезапись всего объекта .prototype, а не просто добавление отдельных элементов. Почему бы просто не сделать это обычным способом?

var Model.Foo = function(){ 
    // private stuff 
    var a, b; 

    // public properties 
    this.attr1 = ''; 
    this.attr2 = ''; 
} 

Model.Foo.prototype.func1 = function(){ //...}; 
Model.Foo.prototype.func2 = function(){ //... }; 

чередуются, позволяющие в случае, переменные-члены частные

var Model.Foo = function(){ 
    // private stuff 
    var a, b; 

    // public properties 
    this.attr1 = ''; 
    this.attr2 = ''; 

    this.func1 = function(){ //...}; 
    this.func2 = function(){ //... }; 
} 
+0

Итак, я подумал, что проще использовать частные атрибуты в прототипах функций (с закрытием). Как бы вы предложили использовать частный аут? Что-то вроде 'this.func() {alert (a);}' внутри функции класса? Почему бы вам не использовать private attr в прототипах? – fenderplayer

+0

Я бы не использовал частные атрибуты или параметры для конструктора в методе прототипа, потому что они являются особыми для создаваемого экземпляра, тогда как методы прототипа будут применяться ко всем экземплярам. Тогда первый вызов Model.Foo() будет иметь некоторый уникальный эффект, кажется, трудно поддерживать. –

+0

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

2

Это странный шаблон Javascript, который я бы никогда не использовал для разработки объектно-ориентированного JS-кода. Во-первых, Model.Foo._init === 'undefined' никогда не оценивает true, если Model.Foo._init ничего, кроме строки 'undefined'; поэтому код

Model.Foo.prototype = { 
    func1 : function(){ /* ... */}, 
    func2 : function(){ /* ... */}, 
    //other prototype functions 
} 

не запускается, если это условие не выполняется. (Возможно, автор хотел добавить typeof, как и в typeof Model.Foo._init === 'undefined'? Я не знаю.)

Обращаясь к вашей обеспокоенности по поводу того, «что [мы] уверены, что мы не будем определять прототипы снова», это уже достигнуто с помощью:

Model.Foo = function() { 
    // private stuff 
    var a, b; 

    // public properties 
    this.attr1 = ''; 
    this.attr2 = ''; 
}; 

Model.Foo.prototype = { 
    func1 : function() { /* ... */}, 
    func2 : function() { /* ... */} 
    //,other prototype functions 
}; 

// Instantiate and use the class as follows: 
var foo = new Model.Foo(); 
foo.func1(); 

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

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

+0

да вы правы, его TypeOf .... мой плохой – fenderplayer

+0

, что если вы хотите использовать некоторые личные вещи в функции прототипа? – fenderplayer

+0

Если вам нужен метод 'func', который предупреждает о значении' a', вы можете использовать что-то вроде http://pastebin.com/wSff15cH. Обратите внимание, как строка 6 устанавливает 'this.func' (а не' Model.Foo.prototype.func') объект функции. Публичные свойства также могут быть методами, как демонстрирует пример. Однако имейте в виду, что определение 'func' больше не является тем же самым объектом' Function' для всех экземпляров 'Model.Foo'. Кроме того, значения всех локальных переменных, а также аргументы для конструктора не будут GC'd. Поэтому, если вы используете в своем коде множество экземпляров 'Model.Foo', то вы будете использовать много памяти. –

0

Несколько вещей, которые выделяются как потенциально хлопотно:

  1. Foo.prototype установлен в простой объект, который не может ничего расширить с помощью этого шаблона.
  2. Где используется «частный материал»? Каждый раз, когда вы создаете новый объект, вы создаете новые частные переменные, которые, по-видимому, могут использоваться только в функциях, определенных в Foo.prototype, которые должны запускаться только один раз.

Это своего рода беспорядок, и есть детали/примеры во всем мире лучше было сделать это.

0

Следующий пример иллюстрирует шаблон, который я лично разработанный в течение долгого времени.

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

Для детального обсуждения, пожалуйста, обратите внимание на JavaScript class patterns

Employee = (function(){ 

    // private static field 
    var staticVar; 

    // class function a.k.a. constructor 
    function cls() 
    { 
    // private instance field 
    var name = ""; 
    var self = this; 

    // public instance field 
    this.age = 10; 

    // private instance method 
    function increment() 
    { 
     // must use self instead of this 
     self.age ++; 
    } 

    // public instance method 
    this.getName = function(){ 
     return cls.capitalize(name); 
    }; 

    this.setName = function(name2){ 
     name = name2; 
    }; 

    this.increment = function(){ 
     increment(); 
    }; 

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

    // public static field 
    cls.staticVar = 0; 

    // public static method 
    cls.capitalize = function(name){ 
     return name.substring(0, 1).toUpperCase() + 
      name.substring(1).toLowerCase(); 
    }; 

    // private static method 
    function createWithName(name) 
    { 
    var obj = new cls(); 
    obj.setName(cls.capitalize(name)); 
    return obj; 
    } 

    return cls; 
})(); 

john = new Employee(); 
john.setName("john"); 

mary = new Employee(); 
mary.setName("mary"); 
mary.increment(); 

alert("John's name: " + john.getName() + ", age==10: "+john.getAge()); 
alert("Mary's name: " + mary.getName() + ", age==11: "+mary.getAge()); 
Смежные вопросы