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

Aad*_*hah 16 javascript coding-style naming-conventions

我是一名优秀的JavaScript程序员,并且遵守道格拉斯·克罗克福德所征集的编码惯例.然而,JavaScript从那时起已经发展,我相信命名约定现在已经过时了.

例如Crockford说:

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

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

你为什么要这样做?

  1. 因为视觉反馈很重要(向下滚动到链接文章中的可读性部分).
  2. 向后兼容性.您可以过滤出以for in循环中的下划线开头的属性.

让我们再举一个Crockford所说的例子:

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

正如我所看到的,以下约定存在两个问题:

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

一切都很好,但你问的真正问题是什么?看看这个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;
        }
    }
});
Run Code Online (Sandbox Code Playgroud)

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

var o = {}, x = 0;

define(o, {
    E: Math.E,
    get x() {
        return x;
    },
    set x(y) {
        x = y;
    }
});
Run Code Online (Sandbox Code Playgroud)

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));
    };
}());
Run Code Online (Sandbox Code Playgroud)

但是现在你不能制作一个属性non-enumerable,non-configurable或者non-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);
            }
        }
    };
}());
Run Code Online (Sandbox Code Playgroud)

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

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

Jan*_*nen 16

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

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

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

ALL_CAPS_WITH_UNDERSCORE虽然JS实际上没有常量,但命名类似常量值的约定也是如此.

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