First of all, your code is pretty good. No big errors as you fear, there are comments, right indentation, anyone can understand it easily, and... it works !!!
Yet let me suggest a few improvements you could make to make it shine :
For all your functions : use a function declaration : it's easier to use since you can use them anywhere in your code (and not only after the var statement was actually evaluated), and the global namespace pollution is the same anyway.
The sum()
function just doesn't make sense as it stands : Why one would use sum(i, 3)
instead of i+3
?
It makes sense again with one or both of those features : type checking or accepting any number of arguments.
To type-check or not to is a big debate i won't enter into. I did here since it might be a good way to learn to be cautious about types even in 'typeless' Javascript.
So following code does both type checking and accepting any number of arguments :
// returns the sum of its arguments (0 if none).
// throws if any of them is not a number.
function sum() {
var result = 0;
for (var i=0; i<arguments.length; i++) {
var thisNumber = arguments[i];
if ((+thisNumber) !== thisNumber) {
throw('Error : argument ' + i + ' of sum is not a number ('+thisNumber + ').');
}
result+=thisNumber;
}
return result;
}
For range()
: change the arguments name to start
and end
makes understanding the function goal easier.
To give step
a default value, you don't want to test step
against null
, but rather against undefined
. (it worked because because you used ==
, but notice that by using '==null', you're just testing is ?? falsy ?
, so the wrong input 0
for step will silently be changed to 1
.).
You might want to check :
• that start
, end
, and step
(if provided) are meaningful numbers (see above).
• that sign(end-start)==sign(step)
so end
might indeed be reached.
• that start-end
is a multiple of step
. Otherwise you don't get end
in the range, which i find most annoying.
• that step is not === 0. In fact the previous check already checked that.
// returns an array filled with the range of numbers between start and end,
// using a optional step that defaults to 1.
// throws if the range cannot be built with the provided arguments.
function range(start,end, step){
// step defaults to 1
if (step === undefined) step = 1;
// type-check start, end, step here if you wish
// ...
// checking that step sign allows to reach the end
if ((end-start)*step<0) {
throw ('the sign of step does not allow to reach end value');
}
// checking that step value allows to reach the end value
// btw will check that step !==0 also
var stepCount = (end-start) / step;
if ( stepCount - Math.floor(stepCount) !==0) { // division has remainder ?
throw('cannot reach '+end+' starting from '+start+' with the step ' + step);
}
// build result array
var result = [];
for (var i = start; i != end ; i += step) { result.push(i); }
return result;
};
For rangeSum
i was surprised to see that you didn't re-use the range
function you just wrote : In fact you re-wrote a simple version of range
.
I think only two options are relevant :
1) re-use range
, and add an optional step
argument for free.
2) if you just want to do a most simple range sum function, go for a for
loop and sum by yourself.
I choosed (2) :
You might want to check :
• that start
, end
are meaningful numbers (see above).
• that that end can be reached with a step of 1 <==> that (start < end)
and start
, end
are integers. ( x === 0 | x )
// returns the sum of numbers ranging from start to end(included).
function rangeSum (start,end){
var result = 0;
// you might want to check some things here.
for (var i = start; i <= end; i++) { result += i; }
return result;
};
... But in fact, with just a little bit of math, you can write the simple version of rangeSum
in one line : :-)
function rangeSum(start, end) {
// you might want to check some things here.
return (end + 1 - start)*( end + start)/2 ;
}
Edit :
To allow easier understanding :
1) I used Math.floor
to floor the stepCount
. ( you might forget about the 0 | stepCount
dirty trick for now ). So when i write if ( stepCount - Math.floor(stepCount) !==0)
i test if the division has a remainder.
2) ((+thisNumber) !== thisNumber)
is a trick to test for thisNumber
not being a number or NaN
. How ?
a) On the left side, we convert thisNumber
to a number
, so since we use !==
, thisNumber
has to be from a different type from number => for now it's quite like testing if (typeof thisNumber === 'number')
.
b) But NaN
qualifies as a number ( ... ... ), so since NaN !== NaN
, the expression above does also consider thisNumber
as wrong if its value is NaN
.