16

I've been a good JavaScript programmer and adhered to the coding conventions enlisted by Douglas Crockford. However JavaScript has evolved since then and I believe the naming conventions are now outdated.

For example Crockford said:

Do not use _ (underbar) as the first character of a name. It is sometimes used to indicate privacy, but it does not actually provide privacy. If privacy is important, use the forms that provide private members. Avoid conventions that demonstrate a lack of competence.

However JavaScript now allows you to create non-enumerable properties. Hence it makes sense (at least to me - you're allowed to disagree) to prefix non-enumerable properties with an underbar to indicate that the property is non-enumerable.

Why should you do so?

  1. Because visual feedback is important (scroll down to the readability section in the linked article).
  2. Backwards compatibility. You can filter out properties that begin with an underbar in for in loops.

Let's take another example of what Crockford said:

Global variables should be in all caps. (JavaScript does not have macros or constants, so there isn't much point in using all caps to signify features that JavaScript doesn't have.)

As I see it there are two problems with the following convention:

  1. Most JavaScript programmers don't write global variables in all caps. It's just not natural.
  2. JavaScript now allows you to create non-writable properties. Hence it makes sense to use all caps for such properties for the same reasons as I stated above for non-enumerable properties.

All that's well and fine, but what's the real question you ask? Look at the Object.defineProperties function. The problem is that you need to supply a property descriptor for each property you want to define. This is too verbose. For instance:

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;
        }
    }
});

Instead it would be much better if you could simply do:

var o = {}, x = 0;

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

The define function would be defined as follows:

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));
    };
}());

However now you can't make a property non-enumerable, non-configurable or non-writable easily. Hence I modified the define function as follows:

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);
            }
        }
    };
}());

Now properties beginning with an underbar are non-enumerable, properties ending with an underbar are non-configurable and data descriptor properties which don't have any lowercase alphabets are non-writable.

So my question is this - is there any way to make properties non-enumerable, non-configurable or non-writable easily while still adhering to Crockford's naming conventions? I know that my own naming conventions have more merits. However I don't want to abandon Crockford's conventions too hastily.

Bernhard Barker
  • 50,899
  • 13
  • 85
  • 122
Aadit M Shah
  • 67,342
  • 26
  • 146
  • 271
  • This is similar to: http://stackoverflow.com/questions/4484424/underscore-prefix-for-property-and-method-names-in-javascript – Jon Onstott Jun 28 '13 at 15:54

1 Answers1

16

I would suggest not following Crock's teaching word for word.

He does have some good advice, but it's worth taking it with a grain of salt.

For example, the underscore aspect is commonly used in various JS libraries which follow a more classical OOP style of programming. It is true it does not make a function or value truely private, but it tells any users it should be treated as such - that it's not a part of the public interface - in other words, the method could disappear in the next version of the library.

The convention for naming constant-like values is also ALL_CAPS_WITH_UNDERSCORE even though JS didn't actually have constants.

In the end, many JS devs are not purely JS-only and work with other languages too. Conventions like the above should be rather obvious for people like that, and what matters in the end is what's most practical for your project.

Jani Hartikainen
  • 40,227
  • 10
  • 60
  • 82