Reputation: 6768
There's something that's been bugging me about JavaScript closures. Variables created with the var
keyword still exist in memory once the constructor has completed its execution. Example:
function RangeCalculator(values) {
var min = Infinity;
var max = -Infinity;
for (var i = 0; i < values.length; ++i) {
min = Math.min(min, values[i]);
max = Math.max(max, values[i]);
}
this.range = max - min;
this.getMin = function() {
return min;
};
this.getMax = function() {
return max;
};
}
r = new RangeCalculator([1, 2, 3, 4, 5]);
console.log("min: " + r.getMin() + ", max: " + r.getMax());
<p>Check the console</p>
In that code, min
and max
aren't accessible from anywhere except functions defined within the constructor. This allows making private member variables in JavaScript.
But what if I just wanted to use the min and max variables to help me count the range, but didn't need them afterward. What if I remove the getMin and getMax functions. Will all the var
-declared variables used in the constructor still exist and take space in memory, including the i
from the for loop?
What if I wrap that code in a self-executing anonymous function?
function RangeCalculator(values) {
(function (t) {
var min = Infinity;
var max = -Infinity;
for (var i = 0; i < values.length; ++i) {
min = Math.min(min, values[i]);
max = Math.max(max, values[i]);
}
t.range = max - min;
})(this);
}
var r = new RangeCalculator([1, 2, 3, 4, 5]);
alert(r.range);
Upvotes: 0
Views: 73
Reputation: 13387
If information hiding is part of the custom type's concept, then the answer is definitely yes. Nevertheless a constructor should always be implemented as most lightweight as possible. All additional build logic should be part of a factory method. The given example code could be refactored towards something similar like the following ...
var NumberRange = (function (global) {
var
Number = global.Number,
Math = global.Math,
math_min = Math.min,
math_max = Math.max,
MIN_VALUE = Number.NEGATIVE_INFINITY,
MAX_VALUE = Number.POSITIVE_INFINITY,
collectLimitingValues = function (collector, value) {
collector.minValue = math_min(collector.minValue, value);
collector.maxValue = math_max(collector.maxValue, value);
return collector;
},
NumberRange = function NumberRange (min, max) {
this.range = (max - min);
this.getMin = function () {
return min;
};
this.getMax = function () {
return max;
};
},
createNumberRange = function (numberValueList) {
// right place for sanitizing all arguments.
var rangeLimitMap = numberValueList.reduce(
collectLimitingValues, {
minValue: MAX_VALUE,
maxValue: MIN_VALUE,
}
);
return (new NumberRange(
rangeLimitMap.minValue,
rangeLimitMap.maxValue
));
}
;
return {
create: createNumberRange
};
}(window));
var r = NumberRange.create([1, 2, 3, 4, 5]);
console.log("min: " + r.getMin() + ", max: " + r.getMax());
<p>Check the console</p>
Upvotes: 1