对象常量

在一些比较现代的环境中可能会提供const来创建常量,但在其它的环境中,JavaScript是没有常量的。

一种常用的解决办法是通过命名规范,让不应该变化的变量使用全大写。这个规范实际上也用在JavaScript原生对象中:

  1. Math.PI; // 3.141592653589793
  2. Math.SQRT2; // 1.4142135623730951
  3. Number.MAX_VALUE; // 1.7976931348623157e+308

你自己的常量也可以用这种规范,然后将它们作为静态属性加到构造函数中:

  1. // 构造函数
  2. var Widget = function () {
  3. // 实现……
  4. };
  5. // 常量
  6. Widget.MAX_HEIGHT = 320;
  7. Widget.MAX_WIDTH = 480;

同样的规范也适用于使用字面量创建的对象,常量会是使用大写名字的属性。

如果你真的希望有一个不能被改变的值,那么可以创建一个私有属性,然后提供一个取值的方法(getter),但不给赋值的方法(setter)。这种方法在很多可以用命名规范解决的情况下可能有些矫枉过正,但不失为一种选择。

下面是一个通用的constant对象的实现,它提供了这些方法:

  • set(name, value)

    定义一个新的常量

  • isDefined(name)

    检查一个常量是否存在

  • get(name)

    取常量的值

在这个实现中,只允许基本类型的值成为常量。同时还要使用hasOwnProperty()小心地处理那些恰好是原生属性的常量名,比如toString或者hasOwnProperty,然后给所有的常量名加上一个随机生成的前缀:

  1. var constant = (function () {
  2. var constants = {},
  3. ownProp = Object.prototype.hasOwnProperty,
  4. allowed = {
  5. string: 1,
  6. number: 1,
  7. boolean: 1
  8. },
  9. prefix = (Math.random() + "_").slice(2);
  10. return {
  11. set: function (name, value) {
  12. if (this.isDefined(name)) {
  13. return false;
  14. }
  15. if (!ownProp.call(allowed, typeof value)) {
  16. return false;
  17. }
  18. constants[prefix + name] = value;
  19. return true;
  20. },
  21. isDefined: function (name) {
  22. return ownProp.call(constants, prefix + name);
  23. },
  24. get: function (name) {
  25. if (this.isDefined(name)) {
  26. return constants[prefix + name];
  27. }
  28. return null;
  29. }
  30. };
  31. }());

测试这个实现:

  1. // 检查是否定义
  2. constant.isDefined("maxwidth"); // false
  3. // 定义
  4. constant.set("maxwidth", 480); // true
  5. // 再次检查
  6. constant.isDefined("maxwidth"); // true
  7. // 尝试重定义
  8. constant.set("maxwidth", 320); // false
  9. // 看看这个值是否被改变
  10. constant.get("maxwidth"); // 480