Posted on

Problem

# 1. Problem Statement

Write a JavaScript function calcCircleArea(r) that takes as a parameter the radius of a circle and calculates and returns its area. Put the function in a file named circle-area.js. Write a HTML page circle-area.html that includes the script circle-area.js and calculates and prints in the page body the area of circles of size r=7, r=1.5 and r=20.

# 2. Expected Output

``````r = 7; area = 153.93804002589985
r = 1.5; area = 7.0685834705770345
r = 20; area = 1256.6370614359173
``````

# Solution:

``````function calcCircleArea(r){
if(r >= 0){
return window['Math']['PI'] * r * r;
}else{
return "wrong input";
}
}

document.write('r = 7; area = ' + window['calcCircleArea'](7) + "<br />");
document.write('r = 1.5; area = ' + window['calcCircleArea'](1.5) + "<br />");
document.write('r = 20; area = ' + window['calcCircleArea'](20) + "<br />");``````
``````<!doctype html>
<html>
<meta charset="UTF-8">
<title>Circle area</title>
<script src="circle-area.js"></script>
<body>

</body>
</html>``````
1. Can I invoke `calcCircleArea` from the HTML code to render the given output?

2. Can the `else` condition in `calcCircleArea` have better code?

Solution

1. Yes.
2. Maybe. Depends on what you define as “better”.

First, though: Don’t use bracketed (aka subscripting) access to properties when regular dot notation works, e.g.:

``````window.Math.PI
``````

is exactly the same as:

``````window['Math']['PI']
``````

but a lot simpler.

Secondly, don’t bother with `window` when there’s no need. `window` is the global object in a browser’s JS runtime, so you can just say

``````Math.PI
``````

The exception to this is if you have variable shadowing, but that’s outside the scope of this review.

Now, to tackle question 2 first, you could do this:

``````function calcCircleArea(r) {
if(r >= 0) {
return Math.PI * r * r;
}
return "invalid input";
}
``````

It’s quite subtle, but instead of having an `else` branch, you just.. don’t have an `else` branch. If the first condition is true, the function returns the area – the rest of the function never runs. But if it’s false, we skip straight past the `if` block. The point of this is to ensure that the function always returns something. It already did that – there was nothing wrong with your code – but here it’s even more explicit.

However, you could argue that handling invalid input is the less common option, hence that should be the thing to short-circuit the function, and return early:

``````function calcCircleArea(r) {
if(r < 0) {
return "invalid input";
}
return Math.PI * r * r;
}
``````

In other words, you could assume good intentions (that the function will typically be called with proper arguments), and treat invalid input as the exception to the rule. However, you might be better served by having your function raise hell if its input is invalid. Right now you’re returning something regardless of input, but maybe you want to completely bail out, if things aren’t as expected (after all, a negative radius just doesn’t make sense, so there’s literally no good answer). Hence why I mentioned “exception to the rule”, since exceptions, as concept, are made for that purpose. Now, exceptions are also a topic on their own, but in this case you could do:

``````function calcCircleArea(r) {
if(r < 0) {
throw "Invalid input";
}
return Math.PI * r * r;
}
``````

`throw` works the same as `return` in the sense that the function just stops. But the caller has to handle it differently, or – if it’s not handled – it’ll bubble up as an error. But I digress.

Now, for question 1, yes, you can call the function from the HTML. In fact, you really should do that here, since you’re currently using `document.write` in a script that’s placed in the `head` element. Since `document.write` happens immediately, your HTML actually ends up looking like this:

``````<!doctype html>
<html>
<meta charset="UTF-8">
<title>Circle area</title>
r = 7; area = 153.93804002589985<br />r = 1.5; area = 7.0685834705770345<br/>r = 20; area = 1256.6370614359173
<body>

</body>
</html>
``````

because the browser reads the scripts, and runs it. Obviously, this isn’t really valid HTML. Thankfully, a browser is very, very, very tolerant, and renders things just fine anyway, even if it makes no sense.

Now (still before actually answering your question), let me quickly point out that

1. it’s `<!DOCTYPE html>` with all-capital `DOCTYPE`
2. since that doctype means HTML5, you don’t need XHTML-style self-closed tags like `<br />`. Just write `<br>`.

Finally, to answer your question, remove the three `document.write` lines from your script, and use this HTML instead:

``````<!DOCTYPE html>
<html>
<meta charset="UTF-8">
<title>Circle area</title>
<script src="circle-area.js"></script>
<body>
<p>
r = 7; area = <script>document.write(calcCircleArea(7));</script>
</p>
<p>
r = 1.5; area = <script>document.write(calcCircleArea(1.5));</script>
</p>
<p>
r = 20; area = <script>document.write(calcCircleArea(20));</script>
</p>
</body>
</html>
``````

`window['Math']['PI']` would be better written as `window.Math.PI`. Furthermore, since all JavaScript code in a browser is run inside the `window` scope, it is customary to omit `window`, and just write `Math.PI`. Similarly, `window['calcCircleArea'](7)` is an awkward way of calling `calcCircleArea(7)`. (You would only use `window['property-name']` if `property-name` were not a legal JavaScript identifier, such as a hyphenated string.)

Error reporting would be better done by throwing a `RangeError`.

``````function calcCircleArea(r) {
if (r < 0) throw new RangeError('Radius cannot be negative');
return Math.PI * r * r;
}
``````

Putting the `document.write(…)` calls in `circle-area.js` is not quite right. For maintainability, it would be better to put only function definitions into the `.js` file. You don’t want the act of including the `circle-area.js` to have the side-effect of writing something to the document. In this case, the `document.write(…)` calls plop the output into the document’s `<head>`, because that’s where the `<script>` tag is. The `<body>` is the more appropriate place for the content.

``````<!DOCTYPE html>
<html>
<meta charset="UTF-8">
<title>Circle area</title>
<script src="circle-area.js"></script>
<body>
<script type="text/javascript">
document.write('r = 7; area = ' + calcCircleArea(7) + "<br />");
document.write('r = 1.5; area = ' + calcCircleArea(1.5) + "<br />");
document.write('r = 20; area = ' + calcCircleArea(20) + "<br />");
</script>
</body>
</html>
``````

First, I’m not sure why you’re using bracket notation for accessing stuff. Bracket notation is typically used when 1) the key is dynamic or 2) the property has an illegal character in its name. Use dot notation whenever possible.

Now your calculation is simply taking an `r` and returning a result. You can simplify using a ternary. It’s also good to check if `r` is also a number in the first place. `isNaN` will be your friend.

As for `document.write`, while there are valid uses for it, I suggest you avoid using it. Try other methods, like `innerHTML` or creating an element using `document.createElement` and stuffing text to it.

``````function calcCircleArea(r){
return (!isNaN(r) && r >= 0) ? Math.PI * r * r : 'wrong input';
}

function printResults(element, r){
element.innerHTML = 'r = ' + r + '; area = ' + calcCircleArea(r);
}

printResults(document.getElementById('results1'), 7)
printResults(document.getElementById('results2'), 1.5)
printResults(document.getElementById('results3'), 20)``````
``````<div id="results1"></div>
<div id="results2"></div>
<div id="results3"></div>``````