I’ve been trying to see if I can build my JavaScript objects as intuitively as possible while making sure it’s as ‘correct’ as possible. I’ve been running a bunch of different scenarios through Crockford’s JSLint.com and haven’t had much luck. I seem to fix one error, then another pops up because of the change. Below is about as good as I can get. Anyone have another take on this?
This is a typical way I structure an object:
function gizmo(id) {
/* private variables */
var myId = id;
/* private methods */
var init = function () {
if (myId < 1) {
setId(1);
}
};
var setId = function (newId) {
myId = newId;
};
// run 'constructor'
init();
/* public methods */
return {
getId: function () {
return myId;
},
setId: function (newId) {
setId(newId);
},
incrementId: function (inc) {
setId(myId + inc);
}
};
}
// creating an instance of gizmo
var myGizmo = gizmo(-2);
console.log(myGizmo.getId()); // outputs 1
myGizmo.setId(5);
console.log(myGizmo.getId()); // outputs 5
myGizmo.incrementId(2);
console.log(myGizmo.getId()); /// outputs 7
This seems to work well. However, when I run this through JSLint, it gives me an error stating that my two private functions are ‘Implied Globals.’
The best I can come up with is to declare my functions at the top with the variables like this:
function gizmo(id) {
/* private variables */
var myId = id,
init,
setId;
/* private methods */
init = function () {
if (myId < 1) {
setId(1);
}
};
setId = function (newId) {
myId = newId;
};
// run 'constructor'
init();
/* public methods */
return {
getId: function () {
return myId;
},
setId: function (newId) {
setId(newId);
},
incrementId: function (inc) {
setId(myId + inc);
}
};
}
I’m pretty sure it’s a bug in JSLint. It hasn’t seen
setIdyet, so it assumes it’s global. But in reality, it makes no difference, because allvars are hoisted, per ECMAScript 5 10.5. This means your first example and the second are the same semantically. A local variable declaration anywhere in the function is processed immediately, and the binding is initially set to haveundefinedvalue. But by the time the function (e.g. init) actually runs, the closed-in value is no longerundefined.To see that
setIdis initially undefined, but never refers to a global, do this test:It will alert undefined, then throw a
TypeErrorerror.