JavaScript:
Bugs and Errors
Lecturer: Иo1lz
OUTLINE
- Preface
- Strict Mode
- Mistake Finding
- Debugging
- Error Propagation
- Exceptions
- Select Catching
Preface
- Flaws in computer programs are usually called bugs
-
We can roughly categorize bugs into 2 caution:
- caused by the thoughts being confused
- caused by mistakes introduced while converting a thought to code.
JavaScript’s looseness is a hindrance.
Its concept of bindings and properties is vague enough that it will rarely catch typos before actually running the program.
true * "monkey";
NaN
![](https://cdn-images-1.medium.com/max/2600/1*Kd0UGiDvgooFooCy28rs8Q.jpeg)
Strict Mode
JavaScript can be made a little stricter by enabling strict mode
function canYouSpotTheProblem(){
"use strict";
for (counter = 0; counter < 10; counter++){
console.log("Happy happy");
}
}
canYouSpotTheProblem();
putting the string "use strict"
- at the top of a file
- a function body.
About "THIS"
function Person(name){ this.name = name; }
let ferdinand = Person("Ferdinand");
console.log(name);
// -> Ferdinand
"use strict"
function Person(name){ this.name = name; }
let ferdinand = Person("Ferdinand"); // forget new
// -> TypeError: Cannot set property 'name' of undefined
Finding Mistake
![](http://www.bbc.co.uk/staticarchive/efb78c8d828ccff15187cebe66c69829009f8a15.gif)
There some ways to find the programming mistake:
- Types
- Carpet search
-
Automated test
Types
Add a comment before the function to describe its type
// (VillageState, Array) -> {direction: string, memory: Array}
function goalOrientedRobot(state, memory){
// ...
}
There are several JavaScript dialects that add types to the language and check them. The most popular one is called TypeScript.
Testing
the process of writing a program that tests another program.
function test(label, body){
if (!body()) console.log(`Failed: ${label}`);
}
test("convert Latin text to uppercase", () => {
return "hello".toUpperCase() == "HELLO";
});
test("convert Greek text to uppercase", () => {
return "χαιρετε".toUpperCase() == "ΧΑΙΡΕΤΕ";
});
test("don't convert case-less characters", () => {
return "مرحبا".toUpperCase() == "مرحبا";
});
test runners
There exist pieces of software that help you build and run collections of tests by providing a language suited to expressing tests and by outputting informative information when a test fails.
the more external objects that the code interacts with, the harder it is to set up the context in which to test it
Debugging
function numberToString(n, base = 10){
let result = "", sign = "";
if(n < 0){
sign = "-";
n = -n;
}
do{
result = String(n % base) + result;
n /= base;
}while(n > 0);
return sign + result;
}
console.log(numberToString(13, 10));
13
1.3
0.13
0.013
…
1.5e-323
13
1
0
![](https://stickershop.line-scdn.net/stickershop/v1/sticker/2221504/android/sticker.png)
![](http://i.imgur.com/Tqf6GC8.png)
Instead of n /= base, what we actually want is n = Math.floor(n / base) so that the number is properly “shifted” to the right.
function numberToString(n, base = 10){
let result = "", sign = "";
if(n < 0){
sign = "-";
n = -n;
}
do{
result = String(n % base) + result;
n = Math.floor(n / base);
}while(n > 0);
return sign + result;
}
console.log(numberToString(13, 10));
Error Propagation
Not all problems can be prevented by the programmer
// Run on the browser
function promptNumber(question){
let result = Number(prompt(question));
return result;
}
console.log(promptNumber("How many trees do you see?"));
// Run on the browser
function promptNumber(question){
let result = Number(prompt(question));
if(Number.isNaN(result)) return null;
else return result;
}
console.log(promptNumber("How many trees do you see?"));
In many situations, Returning a special value is a good way to indicate an error.
![](https://responsivereiding.files.wordpress.com/2019/07/but-lg.jpg)
function lastElement(array){
if(array.length == 0){
return {failed: true};
}else{
return {element: array[array.length - 1]};
}
}
what if the function can already return every possible kind of value?
Exceptions
When a function cannot proceed normally, what we would like to do is just stop what we are doing and immediately jump to a place that knows how to handle the problem.
This is what exception handling does.
// Run on the browser
function promptDirection(question){
let result = prompt(question);
if(result.toLowerCase() == "left") return "L";
if(result.toLowerCase() == "right") return "R";
throw new Error("Invalid direction: " + result);
}
function look(){
if(promptDirection("Which way? ") == "L"){
return "a house";
}else{
return "two angry bears";
}
}
try{
console.log("You see", look());
}catch(error){
console.log("Something went wrong: " + error);
}
Cleaning up after exceptions
The effect of an exception is another kind of control flow.
Every action that might cause an exception, which is pretty much every function call and property access, might cause control to suddenly leave your code.
// Run on the browser
const accounts = {
a: 100,
b: 0,
c: 20
};
function getAccount(){
let accountName = prompt("Enter an account name: ");
if(!accounts.hasOwnProperty(accountName)){
throw new Error(`No such account: {$accountName}`);
}
return accountName;
}
function transfer(from, amount){
// Transfers a sum of money from a given account to another
if(accounts[from] < amount) return;
accounts[from] -= account;
accounts[getAccount()] += amount;
}
function transfer(from, amount){
if(accounts[from]] < amount) return;
let progress = 0;
try{
accounts[from] -= amount;
progress = 1;
accounts[getAccount()] += amount;
progress = 2;
}finally{
if(progress == 1){
accounts[from] += amount;
}
}
}
Selecting Catching
When an exception makes it all the way to the bottom of the stack without being caught:
- In browsers, a description of the error typically gets written to the JavaScript console
- Node.js, it aborts the whole process when an unhandled exception occurs.
for(;;){
try{
let dir = promtDirection("Where?");
console.log("You chose ", dir);
break;
}catch(e){
console.log("Not a valid direction. Try again.");
}
}
class InputError extends Error {}
function promptDirection(question){
let result = prompt(question);
if(result.toLowerCase() == "left") return "L";
if(result.toLowerCase() == "right") return "R";
throw new InputError("Invalid direction: " + result);
}
for(;;){
try{
let dir = promptDirection("Where? ");
console.log("You chose ", dir);
break;
}catch(e){
if(e instanceof InputError){
console.log("Not a valid direction. Try again.");
}else{
throw e;
}
}
}
Thanks for listening.
JavaScript: Bugs and Errors
By Иo1lz
JavaScript: Bugs and Errors
This is the slide that refer from "Eloquent JavaScript" chapter 8.
- 119