8

我了解了模块模式的基础知识以及它使用闭包来允许私有成员,但我不能完全理解为什么下面的代码会这样做:

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 开始,递增,然后打印出它的新priv值 1。

但是a)为什么下一个调用Calculator()最终返回对SAME对象的引用(如第二个'1'所示)?我知道我可以new在这里使用并避免这种情况,但不明白为什么我必须这样做。这个函数不是使用对象字面量语法来本质上创建一个新对象然后返回它吗?b) 既然它似乎确实使用了相同的函数堆栈空间(在 JS 中这是正确的思考方式吗?),为什么priv在返回对同一对象的引用之前不将进程中的变量清零?

编辑:更正了草率/愚蠢的错误(感谢 scessor),即使不使用new关键字,它现在也会输出一个新的/不同的计算器对象。这样就清除了a)和b)。我产生的问题将是“在调用模块模式构造函数时是否使用是否重要new。答案是,我想这并不重要(?)。(约瑟夫:见http://jsfiddle。 net/MvMvy/5/ ... instanceof 运算符根本不适用于模块模式。)

4

3 回答 3

9

您不输出其他计算器myOtherCalc:如果您想比较它们,请将第三个替换为myCalc.printPriv();

myOtherCalc.printPriv();

然后输出是:

0
1
0
于 2012-04-18T05:54:49.893 回答
3

你不需要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
于 2012-04-18T06:27:50.257 回答
0

与“新”运算符无关......在这里你得到一个关于 proto/constructor 的很好解释的主题: http ://en.wikibooks.org/wiki/JavaScript/Access_Control

但是这是一个无意义的示例,您可以这样做,因此您只能通过 getter 和 setter 方法访问 priv:

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);
}

在这种情况下,始终可以通过 getter 和 setter 方法访问 var priv,

在下一个示例中,您有一个 private var className和另一个 public var __className :

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

//脚本 : var SomeClass = function(className) {

    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());

// 结束 javascript 和 CDATA 部分

//]]>
</script>

在 "div:outputDiv" 中输出:

“公共默认类名”

“private [ classname ] : foo”的新实例已创建。参考 [ className ] 已创建“public default className”的新实例。参考[这个。类名]

[对象 HTMLDivElement]

“某个名字”

“private [ classname ] : foo”的新实例已创建。参考 [ className ] 已创建“某个名称”的新实例。参考[这个。类名]

酒吧

“private [ classname ] : foo”的新实例已创建。参考 [ className ] 创建了一个新的 bar 实例。参考[这个。类名]

->在构造函数中声明的类名永远不会改变!-> 这个。className或 SomeClass.prototype。className是公开的,可以更改。

我希望这可能有助于更清楚地理解链条和我的评论......

于 2012-04-18T07:05:50.730 回答