【问题标题】:JavaScript Classes and Variable ScopeJavaScript 类和变量范围
【发布时间】:2010-12-21 20:02:24
【问题描述】:

我对 JS 比较陌生,并且在正确模拟 OOP 原则时遇到了问题。

我想我有两个问题。第一个问题是关于声明变量的多种方式。

假设我有一堂课:

function clazz(a)
{
    this.b = 2;
    var c = 3;
    this.prototype.d = 4; // or clazz.prototype.d = 4?
}

var myClazz = new clazz(1); 

我在以下评估中是否正确:

a 是实例特定的私有变量(即不同的 clazz 实例将具有唯一且独立的变量 'a')。它可以从 clazz 中访问为:'a'。

b 是一个特定于实例的公共变量。它可以从 clazz 内部以“this.b”访问,从 clazz 外部以“myClazz.b”访问。

c 是一个私有变量,它是静态的或特定于类的(即不同的 clazz 实例将共享相同的“c”变量)。它可以在任何 clazz 实例中作为“c”访问,并且 clazz 实例的更改会反映在所有 clazz 实例中。

d 是一个特定于静态/类的公共变量。它可以通过“clazz.prototype.d”或“myClazz.prototype.d”从任何地方访问。

我对变量方案的理解的总体问题是无法声明非静态的私有变量(即类的每个实例的唯一版本)。

第二个问题是关于不同类型的类声明。

我一直在使用:

var MySingleton = new function() {...};

创建单例。它是否正确?我也不确定在这种情况下“new”关键字的效果以及将 () 函数大括号附加到声明的末尾,如下所示:

var MySingleton = new function() {...}();

我一直在使用这种模式来声明一个类,然后实例化该类的实例:

function myClass() {...};
var classA = new myClass();
var classB = new myClass();

这是正确的方法吗?

【问题讨论】:

    标签: javascript variables class


    【解决方案1】:

    ab 你是对的:

    a 是一个参数,仅在constructor function 范围内可用。

    b是一个公共实例变量,可用于使用该构造函数创建的所有实例。

    c 是私有变量,只能在构造函数中访问。

    d 声明无效,因为prototype 对象仅用于constructor functions,如Clazz.prototype.d = 3;,如果您这样做,变量将被共享,但您可以分配特定实例上的值,默认值将被隐藏(通过原型链)。

    对于“私有变量”可以使用你声明c的方式,例如:

    function Clazz(){
        var c = 3; // private variable
    
        this.privilegedMethod = function () {
          alert(c);
        };
    }
    

    特权方法是公共的,但它们可以访问在构造函数中声明的“私有”变量。

    对于创建单例,最简单的方法可能是使用对象字面量,例如:

    var myInstance = {
      method1: function () {
        // ...
      },
      method2: function () {
        // ...
      }
    };
    

    如果你想在你的单例实例上使用私有成员,你可以:

    var myInstance = (function() {
      var privateVar = '';
    
      function privateMethod () {
        // ...
      }
    
      return { // public interface
        publicMethod1: function () {
          // all private members are accesible here
        },
        publicMethod2: function () {
        }
      };
    })();
    

    这被称为模块模式,它基本上允许您利用closures 的使用将私有成员封装在对象上。

    更多信息:

    编辑:关于您发布的语法:

    var mySingleton = new (function() {
      // ...
    })();
    

    通过使用new 运算符,您在一步中声明并使用了一个“匿名构造函数”,它将生成一个新的对象实例,它是有效,但我个人更喜欢“模块”模式方法来创建我自己的对象实例(并避免new)。

    另外,阅读new function () {},如果您不太了解new 运算符的工作原理,我认为这不是很直观并且可能会造成混淆。

    关于括号,它们是可选的,如果你不添加它们,new 运算符将调用不带参数的函数构造函数(参见ECMA-262,11.2.2)。 p>

    【讨论】:

    • 感谢您提供信息丰富的回复。跟进:单例声明的模块方法与原始帖子中引用的样式之间有什么明显区别?
    • 我会避免将对象属性称为“实例变量”。属性是对象中的条目,因此是数据的一部分,而变量是对数据的命名引用。
    【解决方案2】:

    好的,让我们回顾一下:

    1. 'a' 是传递给类的构造函数的参数。它只会在构造函数调用期间存在。这意味着您可能应该将其值存储在某个地方。

    2. 'b' 是公共实例成员。它是特定于实例的(不过,由于您在构造函数中分配值,所有实例最初都将具有相同的 'b' 值)。

    3. 'c' 是私有实例成员。但是,它只能在您的构造函数中访问,因为它仅在该范围内定义。除非您从构造函数内部的闭包中引用它,否则它的命运将与上面的“a”相似。

    4. 'd' 是公共实例成员。您的类的每个实例都会有一个成员“d”,最初的值为 4。但是请注意,将引用类型对象分配给类的原型成员(例如“d”)将使每个实例成员“d”引用同一个对象。示例:

      MyClass.prototype.d = { prop1: 'val1', prop2: 'val2' };        
      var a = new MyClass();
      var b = new MyClass();        
      a.d.prop1 = 'foo'; // is the same as: b.d.prop1 = 'foo';
      
    5. 类的静态成员使用以下方式定义:

      function MyClass()
      {
        // ...
      }    
      MyClass.staticMemeber = 'I am a static member';
      

      您可能不应该将 MyClass.prototype 视为存放静态成员/方法的地方。分配给类原型的所有内容反过来又是其每个实例的成员。

    6. 当 () 附加到函数定义时(就在块之后),函数就会被执行。这意味着:

      var myFunc = function() { alert('blah'); }();
      

      只会导致方法调用。以下代码:

       var MySingleton = new function() {...}();
      

      意思是“使用 function() 的返回值作为 MySingleton 的构造函数”。

    【讨论】:

      猜你喜欢
      • 2013-01-16
      • 1970-01-01
      • 2015-07-28
      • 2017-11-18
      • 2020-02-07
      • 2012-12-23
      • 2011-05-10
      相关资源
      最近更新 更多