Javascript模块模式和新关键字

时间:2012-04-18 05:51:20

标签: javascript closures new-operator module-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开始,递增,然后打印出新的priv值为1。

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

编辑:修正了草率/愚蠢的错误(谢谢scessor),即使不使用new关键字,它现在也会输出一个新的/不同的计算器对象。这样就可以清除a)和b)。我得到的问题是“在模块模式构造函数的调用中是否使用new是否重要。答案是,我认为无关紧要(?)。(Joseph:see { {3}} ... instanceof运算符无论如何都无法使用模块模式。)

3 个答案:

答案 0 :(得分:8)

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

myOtherCalc.printPriv();

然后输出是:

0
1
0

答案 1 :(得分: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

答案 2 :(得分: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);
}

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

在下一个示例中,您有一个私有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”中的输出:

“public default className”

已创建“private [ classname ]:foo”的新实例。参考[ className ] 已创建“public default className”的新实例。请参阅[this。 className ]

[object HTMLDivElement]

“有些名字”

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

已创建“private [ classname ]:foo”的新实例。参考[ className ] 已创建一个新的bar实例。请参阅[this。 className ]

- &GT;在构造函数中声明的 className 永远不会改变! - &GT;这个。 className 或SomeClass.prototype。 className 是公开的,可能会被更改。

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