【问题标题】:Where to declare class constants?在哪里声明类常量?
【发布时间】:2011-01-25 02:08:28
【问题描述】:

我正在使用类成员来保存常量。例如:

function Foo() {
}

Foo.CONSTANT1 = 1;
Foo.CONSTANT2 = 2;

这很好用,只是它看起来有点杂乱无章,所有特定于Foo 的代码都在全局范围内。所以我考虑将常量声明移到 Foo() 声明中,但是这样代码不会在每次构造 Foo 时执行吗?

我来自 Java,其中所有内容都包含在类主体中,所以我认为 JavaScript 可能有类似的东西或一些模仿它的工作。

【问题讨论】:

    标签: javascript conventions


    【解决方案1】:

    您在代码中所做的只是将值 1 的名为 CONSTANT 的属性添加到名为 Foo 的函数对象,然后立即用值 2 覆盖它。

    我对其他语言不太熟悉,但我不相信 javascript 能够完成您似乎正在尝试的事情。

    您添加到Foo 的所有属性都不会执行。它们只是存储在该命名空间中。

    也许您想在Foo 上制作一些属性的原型?

    function Foo() {
    }
    
    Foo.prototype.CONSTANT1 = 1;
    Foo.prototype.CONSTANT2 = 2;
    

    虽然不是你想要的。

    【讨论】:

    • 已修复。我正在寻找一种在块内声明常量的方法,以便 A)它们组合在一起 B)它们只运行一次。
    • 把它放在原型上对你有什么好处吗?
    • @Tom:我明白了。是的,基本上您将Foo 对象用作命名空间。这会起作用,但也许更好的方法是将它们添加到prototype 对象中。这不是用每个新实例构建的。相反,它是Foo 的所有实例之间的共享对象。
    • @hvgotcodes:考虑到它们是常量,并且可能不会在原型继承链中的任何地方被覆盖,我不确定它确实如此。从this 查找可能更快,也可能不是。
    • @hvgotcodes:在prototype 上,它也不会一遍又一遍地初始化。就一次。如果它在prototype 对象中,您可以将其引用为this.CONSTANT1。如果您愿意,也可以通过Foo.prototype.CONSTANT1 直接引用它。如果它直接在Foo 上,那么是的,它将是Foo.CONSTANT1
    【解决方案2】:

    你必须像你说的那样做你的常量:

    function Foo() {
    }
    
    Foo.CONSTANT1 = 1;
    Foo.CONSTANT2 = 2;
    

    你就这样访问了:

    Foo.CONSTANT1;
    

    anInstanceOfFoo.__proto__.constructor.CONSTANT1;
    

    当您创建其他对象时,所有其他解决方案都会分配另一部分内存,因此它不是常量。 你不应该这样做:

    Foo.prototype.CONSTANT1 = 1;
    

    【讨论】:

    • 请注意,proto 并不总是可用的。此外,proto.constructor 并不总是您认为的那样,尤其是。在多级继承的情况下,如果类作者没有特别注意设置它。您可以简单地使用 anInstanceOfFoo.CONSTANT1,由于原始链,它会很好地解决。
    • 我偶尔会合并它们:Foo.value = Foo.prototype.value = 42;
    【解决方案3】:

    如果常量只在对象内部使用:

    function Foo() {
        var CONSTANT1 = 1,CONSTANT2 = 2;
    }
    

    如果没有,请这样做:

    function Foo(){
        this.CONSTANT1=1;
        this.CONSTANT2=2;
    }
    

    它更易读,更容易计算出函数的作用。

    【讨论】:

      【解决方案4】:

      如果你使用 jQuery,你可以使用 $.extend 函数对所有内容进行分类。

      var MyClass = $.extend(function() {
              $.extend(this, {
                  parameter: 'param',
                  func: function() {
                      console.log(this.parameter);
                  }
              });
              // some code to do at construction time
          }, {
              CONST: 'const'
          }
      );
      var a = new MyClass();
      var b = new MyClass();
      b.parameter = MyClass.CONST;
      a.func();       // console: param
      b.func();       // console: const
      

      【讨论】:

        【解决方案5】:

        您所做的很好(假设您意识到您的示例只是设置了两次相同的属性);它相当于 Java 中的静态变量(尽可能接近,至少不需要做很多工作)。此外,它并不完全是全局的,因为它在构造函数上,它被有效地命名为您的“类”。

        【讨论】:

          【解决方案6】:

          首先,我建议将您的类声明移到IIFE 中。这会清理代码,使其更加独立,并允许您在不污染全局命名空间的情况下使用局部变量。你的代码变成:

          var Foo = (function() {
            function Foo() {
            }
          
            Foo.CONSTANT1 = 1;
            Foo.CONSTANT2 = 2;
          
            return Foo;
          })();
          

          将常量作为属性直接分配给类的问题在于它们是可写的。看到这个sn-p:

          var output = document.getElementById("output");
          
          var Foo = (function() {
            function Foo() {
            }
          
            Foo.CONSTANT1 = 1;
            Foo.CONSTANT2 = 2;
          
            return Foo;
          })();
          
          Foo.CONSTANT1 = "I'm not very constant";
          
          output.innerHTML = Foo.CONSTANT1;
          <div id="output"></div>

          我发现的最佳解决方案是定义只读属性以访问类外的常量。

          var output = document.getElementById("output");
          
          var Foo = (function() {
            const CONSTANT1 = "I'm very constant";
          
            function Foo() {
            }
          
            Object.defineProperty(Foo, "CONSTANT1", {
              get: function() {
                return CONSTANT1;
              },
            });
          
            return Foo;
          })();
          
          Foo.CONSTANT1 = "some other value";
          
          output.innerHTML = Foo.CONSTANT1;
          <div id="output"></div>

          (从技术上讲,您可以放弃 const CONSTANT1 语句,只返回属性定义中的值,但我更喜欢这样,因为它更容易一目了然地查看所有常量。)

          【讨论】:

            【解决方案7】:

            您的常量只是变量,如果您尝试无意中覆盖它们,您将不知道。另请注意,Javascript 缺少“类”的概念。

            我建议您创建函数来返回您需要的常量值。

            要体验 Javascript,请找到 Javascript: the Good Parts 并学习惯用方式。 Javascript 非常与 Java 不同。

            【讨论】:

              【解决方案8】:

              还有命名空间

              var Constants = {
                  Const1: function () {
                      Const1.prototype.CONSTANT1 = 1;
                      Const1.prototype.CONSTANT2 = 2;
                  },
              
                  Const2: function () {
                      Const2.prototype.CONSTANT3 = 4;
                      Const2.prototype.CONSTANT4 = 3;
                  }
              };
              

              【讨论】:

              • 不是说必须写Constants.Const1.CONSTANT1才能访问吗?
              • 正确,这就是重点,仅当您希望将所有常量分组在一个命名空间下时才使用它 - 当您有很多 Const 函数并且您希望保持它们井井有条时很有用。
              【解决方案9】:

              您说您来自 Java - 为什么不将该类存储在 1 个文件中,然后将常量存储在文件末尾。这是我使用的:

              文件名:PopupWindow.js

              function PopupWindow() {
                  //private class memebers
                  var popup, lightbox;
                  //public class memeber or method (it is the same in JS if I am right)
                  this.myfuncOrmyMemeber = function() {};
              }
              
              //static variable
              PopupWindow._instance = null;
              //same thing again with constant-like name (you can't have "final" in JS if I am right, so it is not immutable constant but its close enough ;) - just remember not to set varibales with BIG_LETTERS :D)
              PopupWindow.MY_CONSTANT = 1;
              //yea, and same thing with static methods again
              PopupWindow._getInstance = function() {};
              

              所以唯一的区别是静态东西的位置。它在类花括号内并没有很好地对齐,但是谁在乎,它总是在 IDE 中按 ctrl+click(或者我使用 ctr+l 来显示所有类方法 - IntellijIdea 可以在 JS 中做到这一点,不知道其他 IDE 怎么样)所以你不会用你的眼睛搜索它;)

              是的,我在静态方法之前使用 _ - 这不是必需的,我不知道我为什么开始这样做 :)

              【讨论】: