使用ExtJS扩展类时的私有成员

11

我在ExtJS论坛上做了一些关于扩展类中的私有方法和字段的研究,但是我没有找到任何真正的答案。

当我说一个扩展类时,我的意思是像这样的东西:

Ext.ux.MyExtendedClass = Ext.extend(Ext.util.Observable, {
    publicVar1: 'Variable visible from outside this class',
    constructor: function(config) { this.addEvents("fired"); this.listeners = config.listeners; }, // to show that I need to use the base class
    publicMethod1: function() { return 'Method which can be called form everywhere'; },
    publicMethod2: function() { return this.publicMethod1() + ' and ' + this.publicVar1; } // to show how to access the members from inside another member
});

这里的问题在于所有东西都是公开的。那么,我如何在MyExtendedClass的范围内添加一个新变量或方法,使其无法从外部访问但可以被公共方法访问?

3个回答

23
以下示例展示了使用“Upper Stage方式”定义特权私有和公共成员的方法,来源于Stack Overflow。同时还展示了如何定义私有静态成员(也称为类成员)和公共非特权成员。如果使用这两个后者而不是特权成员,我们将减少初始化时间,因为它们不会在每次创建新对象时进行解析:

Ext.ux.MyExtendedClass = Ext.extend(Ext.util.Observable, 
  (function() {
    // private static fields (can access only to scope: minimum privileges).
    var privStaticVar = 0;
    // private static functions (can access only to scope and arguments, but we can send them the scope by param)
    var privateFunc1 = function(me) { return me.name + ' -> ClassVar:' + privStaticVar; };
    var privateFunc2 = function(me) { return me.publicMethod1() + ' InstanceVar:' + me.getPrivateVar(); };
    return {
      constructor: function(config) {
        // privileged private/public members (can access to anything private and public)
        var privateVar = config.v || 0;
        var privInstFunc = function() { privateVar += 1; };
        this.name = config.name;
        this.incVariables = function(){ privInstFunc(); privStaticVar += 1; };
        this.getPrivateVar = function(){ return privateVar; };
      },
      // public members (can access to public and private static, but not to the members defined in the constructor)
      publicMethod1: function() { this.incVariables(); return privateFunc1(this); },
      publicMethod2: function() { return privateFunc2(this); }
    };
  }())
);

function test() {
  var o1 = new Ext.ux.MyExtendedClass({name: 'o1', v: 0});
  var o2 = new Ext.ux.MyExtendedClass({name: 'o2', v: 10});
  var s = o1.publicMethod2() + '<br>' + o1.publicMethod2() + '<br><br>' + o2.publicMethod2() + '<br>' + o2.publicMethod2();
  Ext.get("output").update(s);
}
<link href="//cdnjs.cloudflare.com/ajax/libs/extjs/3.4.1-1/resources/css/ext-all.css" rel="stylesheet"/>
<script src="//cdnjs.cloudflare.com/ajax/libs/extjs/3.4.1-1/adapter/ext/ext-base.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/extjs/3.4.1-1/ext-all.js"></script>

<p>Click the button to instantiate 2 objects and call each object 2 times:</p>

<button onclick="test();">Test</button>

<p>You can click the button again to repeat. You'll see that the static variable keep increasing its value.</p>

<p>&nbsp;</p>
<div id="output"></div>


4
这通常被称为“模块模式”,你可以在YUI博客上找到相关文章。 - seanmonstar
1
我相信privStaticVarprivateFunc1privateFunc2只会被解析一次(通过我所做的测试,我得到了正确的结果)。因为new关键字不会影响此模块模式的成员,它们在执行Ext.extend时就已经被解析(早于构造函数或任何其他方法出现)。此外,模块模式是单例模式,我认为这也可以解释。 - Mariano Desanze
我同意;之前的评论很抱歉。 - Upperstage
@Proton 模块模式不一定要生成单例。它更多地描述了将变量声明包装在自执行函数中,并返回具有访问这些变量的对象的操作。 - seanmonstar
@seanmonstar yuiblog/module-pattern说:“Douglas Crockford一直在教授一种有用的单例模式来实现这种纪律,我认为他的模式可能会对那些在YUI之上构建的人感兴趣。Douglas称之为“模块模式”。”但你是对的!因为我在这个类中使用它,而整个类并不是一个Singleton。尽管它具有Singleton的静态性。 - Mariano Desanze

4
我使用类似以下的东西。
  var toolbarClass = Ext.extend( Ext.Container,
  {
    /**
     * constructor (public)
     */
    constructor: function( config )
    {
      config = config || {};

      // PRIVATE MEMBER DATA ========================================
      var accountId = Ext.id( null, 'ls-accountDiv-');

      // PUBLIC METHODS ========================================
      this.somePublicMethod = function(){
         console.log( accountId );
      };

...

+1 它可以工作!但我刚意识到另一个看起来更好的解决方案。因为使用你的解决方案,每个实例的创建时间都会增加,而我相信我的解决方案不会。我现在要发布它,这样人们就可以说我是否正确了。 - Mariano Desanze
5
我很高兴参与这次交谈。可以说,在使用JavaScript开发时,关注数据隐藏的开发人员太少了。 - Upperstage

1

@Protron:你的回答太棒了!谢谢! 我更进一步,创建了自己的类扩展方法。

/**
 * Instead of call Ext.extend method to create your new class extensions, you can use
 * My.extend. It is almost the same thing, but you pass a function as body for your new class, not
 * an object. Ex.:
 *
 * MyNewExtCompoment = My.extend(Ext.Compoment, function() {
 *     var myPrivateVar = 0;
 *
 *     //private
 *     function reset() {
 *       myPrivateVar = 0;
 *     }
 *
 *     //public
 *     function add(value) {
 *       try{
 *         myPrivateVar = myPrivateVar + value;
 *       } catch(err){
 *         reset();
 *       }
 *       return myPrivateVar;
 *     }
 *
 *     return {
 *         add: add
 *     }
 * }, 'ux-my-new-component');
 *
 * @param extendedClass my extended class
 * @param newClassBodyFunction my new class body
 * @param newClassXtype (optional) the xtype of this new class
 */
My.extend = function(extendedClass, newClassBodyFunction, newClassXtype) {
    var newClass = Ext.extend(extendedClass, newClassBodyFunction.call());
    if(newClassXtype) {
        Ext.reg(newClassXtype, newClass);
    }
    return newClass;
}

这样我们可以省略一些额外的"()",并且可以免费使用"Ext.reg"。[]s

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接