在JavaScript中定义属性和命名约定

时间:2013-06-28 07:54:10

标签: javascript coding-style naming-conventions

我是一名优秀的JavaScript程序员,并且遵守coding conventions所招募的Douglas Crockford。然而,JavaScript从那时起已经发展,我相信命名约定现在已经过时了。

例如Crockford说:

  

请勿使用_(下划线)作为名称的第一个字符。它有时用于表示隐私,但实际上并不提供隐私。如果隐私很重要,请使用提供private members的表单。避免表现出缺乏能力的惯例。

但是JavaScript现在允许您创建不可枚举的属性。因此,有意义的是(至少对我来说 - 你被允许不同意)使用下划线为非可枚举属性添加前缀以指示该属性是不可枚举的。

你为什么要这样做?

  1. 因为visual feedback is important(向下滚动到链接文章中的可读性部分)。
  2. 向后兼容性。您可以在for in循环中过滤掉以下划线开头的属性。
  3. 让我们再举一个Crockford所说的例子:

      

    全局变量应该全部上限。 (JavaScript没有宏或常量,因此使用全部大写来表示JavaScript没有的功能没有多大意义。)

    我认为以下惯例存在两个问题:

    1. 大多数JavaScript程序员不会在全部大写中编写全局变量。这不自然。
    2. JavaScript现在允许您创建不可写属性。因此,对于此类属性使用全部大写是有意义的,其原因与我上面针对非可枚举属性所述的原因相同。

    3. 所有这一切都很好,但你问的真正问题是什么?查看Object.defineProperties函数。问题是您需要为要定义的每个属性提供属性描述符。这太冗长了。例如:

      var o = {}, x = 0;
      
      Object.defineProperties(o, {
          E: {
              value: Math.E,
              enumerable: true,
              configurable: true
          }
          x: {
              enumerable: true,
              configurable: true,
              get: function () {
                  return x;
              },
              set: function (y) {
                  x = y;
              }
          }
      });
      

      相反,如果您只是这样做会好得多:

      var o = {}, x = 0;
      
      define(o, {
          E: Math.E,
          get x() {
              return x;
          },
          set x(y) {
              x = y;
          }
      });
      

      define函数定义如下:

      var define = (function () {
          var defineProperty = Object.defineProperty;
          var has = Function.call.bind(Object.hasOwnProperty);
          var getDescriptorOf = Object.getOwnPropertyDescriptor;
      
          return function (obj, props) {
              for (var key in props)
                  if (has(props, key))
                      defineProperty(obj, key,
                          getDescriptorOf(props, key));
          };
      }());
      

      但是现在您无法轻松制作属性non-enumerablenon-configurablenon-writable。因此我修改了define函数,如下所示:

      var define = (function () {
          var defineProperty = Object.defineProperty;
          var has = Function.call.bind(Object.hasOwnProperty);
          var getDescriptorOf = Object.getOwnPropertyDescriptor;
      
          return function (obj, props) {
              for (var key in props) {
                  if (has(props, key)) {
                      var descriptor = getDescriptorOf(props, key);
      
                      if (key.charAt(0) === "_")
                          descriptor.enumerable = false;
      
                      if (key.charAt(key.length - 1) === "_")
                          descriptor.configurable = false;
      
                      if (has(descriptor, "value") && key === key.toUpperCase())
                          descriptor.writable = false;
      
                      defineProperty(obj, key, descriptor);
                  }
              }
          };
      }());
      

      现在以underbar开头的属性是不可枚举的,以underbar结尾的属性是不可配置的,并且没有任何小写字母的数据描述符属性是不可写的。

      所以我的问题是 - 有什么方法可以让属性不可枚举,不可配置或不可写,同时仍然坚持Crockford的命名约定?我知道我自己的命名约定有更多的优点。但是我不想匆匆放弃克罗克福德的惯例。

1 个答案:

答案 0 :(得分:16)

我建议不要一字不漏地跟随Crock的教学。

他确实有一些很好的建议,但值得一提。

例如,下划线方面通常用于各种JS库,这些库遵循更经典的OOP编程风格。确实它没有使一个函数或值真正私有,但它告诉任何用户它应该被视为这样 - 它不是公共接口的一部分 - 换句话说,该方法可能会在下一个版本中消失库。

命名类似常量值的约定也是ALL_CAPS_WITH_UNDERSCORE,即使JS实际上没有常量。

最后,许多JS开发人员不仅仅是纯粹的JS,也可以与其他语言一起使用。像上面这样的公约对于这样的人来说应该是相当明显的,最重要的是对你的项目最实用的东西。