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?
- Because visual feedback is important (scroll down to the readability section in the linked article).
- 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:
- Most JavaScript programmers don't write global variables in all caps. It's just not natural.
- 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.