2012-04-18 2 views
8

я получаю основы модуля рисунка и его использование закрытия, чтобы обеспечить для частных членов, но я не могу достаточно проглотить, почему следующий код делает то, что он делает:Javascript Модуль Pattern и новое ключевое слово

var Calculator = function() { 
    var priv = 0; 

    return { 
     changePriv: function() { priv++;}, 
     printPriv: function() { console.log(priv);} 
    } 
} 

var myCalc = Calculator(); 
myCalc.printPriv(); 
myCalc.changePriv(); 
myCalc.printPriv(); 

var myOtherCalc = Calculator(); 
myCalc.printPriv(); 

выход консоли

0 
1 
1 

Так целенаправленно опуская new ключевое слово здесь, первый вызов устанавливает myCalc на объект Calculator. Она начинается с priv значением 0, имеет, что увеличивается, а затем выводит его новое значение 1.

priv Но) ПОЧЕМУ следующий вызов Calculator() в конечном итоге возвращает ссылку на тот же объект (как о чем свидетельствует второй «1»)? Я знаю, что могу использовать здесь new и избегать этого, но не понимаю, зачем мне это нужно. Разве эта функция не использует синтаксис объектного литерала, чтобы по существу создать новый объект и затем вернуть его? b) Поскольку он, похоже, использует одно и то же пространство стека функций (это даже правильный способ думать об этом в JS?), Почему он не обнуляет переменную priv в этом процессе, прежде чем возвращать ссылку на тот же объект?

EDIT: Исправлена ​​неряшливая/глупая ошибка (спасибо scessor), которая теперь выводит новый/отдельный объект калькулятора даже без использования ключевого слова new. Таким образом, это очищает a) и b). Мой итоговый вопрос был бы «Имеет ли значение, пользуюсь ли я new или нет в вызове конструктора шаблонов модулей. Ответ: я думаю, это не имеет значения (?). (Джозеф: см. http://jsfiddle.net/MvMvy/5/ ... оператор InstanceOf просто не работает с шаблоном модуля в любом случае)

+2

По соглашению функции, начинающиеся с заглавной буквы, зарезервированы для конструкторов (т. Е. Функций, которые предполагается вызывать с помощью 'new'). Функция «Калькулятор» явно возвращает объект, поэтому вызов его с помощью «new» не имеет никакого отношения к тому, что он возвращает. – RobG

+0

Спасибо RobG. Это именно то, на что я надеялся получить подтверждение. – jeffersii

ответ

8

вы не выводим другой калькулятор myOtherCalc. А если вы хотите, чтобы сравнить их, заменить третье myCalc.printPriv(); с:

myOtherCalc.printPriv(); 

Тогда выход:

0 
1 
0 
3

You don't need to use new в вашем случае.

Обычно, если вы используете new, вы ожидаете, что то, что вы получаете, является экземпляром того конструктора, который вы вызвали. В вашем случае это произойдет не потому, что вы вручную вернули объект. Это не имеет смысла и вызовет проблемы, когда вы запутаете использование. Вскоре вы можете «проверить экземпляр» своих объектов и столкнуться с этим «несоответствием».

и вы получили опечатку в коде:

var myCalc = Calculator();  //create calculator 
myCalc.printPriv();    //"myCalc" private is 0 
myCalc.changePriv();    //increment 
myCalc.printPriv();    //"myCalc" private is 1 

var myOtherCalc = Calculator(); //another calculator 
myCalc.printPriv();    ///but you printed "myCalc" again 
+0

«не должно» и «не должно» - это разные заявления. Я бы сказал, что в его конкретном примере он не должен, однако ... Существуют версии шаблонов модулей, которые хорошо сочетаются с «новыми» и не сталкиваются с проблемой экземпляра, которую вы описываете. См .: http://carldanley.com/js-module-pattern/ – Frug

0

Там нет ничего общего с «новой» Оператор ... Здесь вы получите хорошо объяснил тему о прото/конструктору: http://en.wikibooks.org/wiki/JavaScript/Access_Control

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

function Calculator2() { 
var priv = 0; 
this.public = 0; 
this.getPriv = function(){ 
    return priv; 
} 
this.setPriv = function(val){ 
    priv = val; 
} 
} 
Calculator2.prototype.changePriv = function(){ 
this.setPriv(this.getPriv()+1); 
} 
Calculator2.prototype.printPriv = function(){ 
    console.log("priv = " + this.getPriv()); 
} 
Calculator2.prototype.changePublic = function(){ 
    this.public++; 
} 
Calculator2.prototype.printPublic = function(){ 
    console.log(this.public); 
} 

В этот случай вар собств всегда доступен через геттер и сеттер метода,

В следующем примере у вас есть частный вар Classname и другой общественный уаг __className:

<div id = "outputDiv" style="width:600px;height:400px;border:solid 1px #000"></div> 
<script type="text/javascript"> 
    //<![CDATA[ 

// Сценарий: вар SomeClass = функция (имя класса) {

var __className__ = className; 
    this.__className__ = "\"public default className\""; 
    var someString = new String(""); 

    this.setScopeText = function() { // void 
     someString = "A new instance of \"private [__classname__] : " + 
     __className__ + "\"" + 
     " has been created. Refering to [__className__]<br />" + 
     "A new instance of " + 
     this.__className__ + 
     " has been created. Refering to [this.__className__]"; 
     return someString; 
    }; 

    this.getScopeText= function(){ 
     return someString; 
    } 

    this.setOutput = function(elementId, someString){ 
     var outputPane = this.getSomePane(elementId); 
     outputPane.innerHTML += "<p>" + someString + "</p>"; 
    } 

    this.getSomePane = function(elementId){ 
     var outputP = document.getElementById(elementId); 
     return outputP; 
    } 

} 

SomeClass.prototype.changeClassNameVariable = function(str){ 
    this.__className__ = str; 
} 

// Конец декларации.

// тесты:

var sc = new SomeClass("foo"); 

sc.setOutput("outputDiv",sc.__className__); 
sc.setOutput("outputDiv",sc.setScopeText()); 
sc.setOutput("outputDiv",sc.getSomePane("outputDiv")); 

sc.__className__ = "\"Some name\""; 
sc.setOutput("outputDiv",sc.__className__); 
sc.setOutput("outputDiv",sc.setScopeText()); 

sc.changeClassNameVariable("bar"); 
sc.setOutput("outputDiv",sc.__className__); 
sc.setOutput("outputDiv",sc.setScopeText()); 

// заканчивается яваскрипт и секция CDATA

//]]> 
</script> 

Выход в "сНе: outputDiv":

"общественность по умолчанию имя класс"

Новый экземпляр «private [имя класса]: foo ". Ссылка на [className] Создан новый экземпляр «public default className». См. [Это. имя класса]

[объект HTMLDivElement]

"Некоторые называют"

Новый экземпляр "частной [Classname]: Foo" было создано. Ссылка на [className] Создан новый экземпляр «Некоторое имя». См. [Это. имя класса]

бар

новый экземпляр "частный [Classname]: Foo" было создано. Ссылка на [className] Создан новый экземпляр бара. См. [Это. имя класса]

->имя класса объявлен в конструктор никогда не меняется! -> это. className или SomeClass.prototype. className является общедоступным и может быть изменен.

Надеюсь, это может помочь понять цепочку и мой комментарий более четко ...

+0

В вашем примере не разрешены частные методы, которые являются точкой шаблона модуля. (getPriv доступен в любом месте - см. http://jsfiddle.net/VjnGq/1/) – jeffersii

+0

Вот почему я сказал: «Это пример бессмыслицы». Это было только для того, чтобы показать, как это работает ... getPriv доступен, однако, приватный нет, если не вызывается метод getPriv() ... – tatactic

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

  • Нет связанных вопросов^_^