Eloquent JavaScript #08# Bugs and Errors

Indexes

  • Notes

    1. strict mode
    2. jstype
    3. jstest
    4. Debugging
    5. Exceptions
    6. finally
    7. Anomalous branch
  • Excercise

    1. Retry
    2. The locked box

Notes

1、strict mode

strict modeAdvantages: more stringent checks and deletion of some problematic language features.

Put “use strict” at the top of the file (it must be at the top of the file and be treated as a string elsewhere) or open JS string mode at the top of the function.

Example 1: if strict mode is not enabled, JS will add a let to you silently.

function canYouSpotTheProblem() {
  "use strict";
  for (counter = 0; counter < 10; counter++) {
    console.log("Happy happy");
  }
}

canYouSpotTheProblem();
// → ReferenceError: counter is not defined

Example 2: if strict mode is not enabled, name is silently bound to a global object without error.

function Person(name) { this.name = name; }
let ferdinand = Person("Ferdinand"); // oops
console.log(name);
// → Ferdinand
console.log(window.name);
// → Ferdinand

// - -- - --Modify the dividing line.

"use strict";
function Person(name) { this.name = name; }
let ferdinand = Person("Ferdinand"); // forgot new
// → TypeError: Cannot set property 'name' of undefined

PS. In this case, defining a class with class has the same effect as using the string pattern, so try to define a class with class.

 

2、jstype

jsOnly types are involved when running. Many languages consider types in compile time.

In order to reduce some problems caused by JS type, there are two simple solutions:

① Notes

// (VillageState, Array) → {direction: string, memory: Array}
function goalOrientedRobot(state, memory) {
  // ...
}

② TypeScript 

Type checking can be done and compiled into JS.

 

3、jstest

Use the third party test suite or as follows:

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() == "مرحبا";
});

 

4、Debugging

console.logOr debugger keyword:

function add(a, b) {
    console.log(`add ${a} and ${b}`);
    return a + b;
}

debugger; // From this line, enter browser debug mode.

let x = add(1, 3);
prompt("Debug mode only works in developer mode.");

 

5、Exceptions

One big advantage of exceptions is that they are passed almost uncoupledly in multiple functions (call stacks), with the intermediate functions needing nothing to know, just in the outermost layer.

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);
}

 

6、finally

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;
    }
  }
}


//Writing programs that operate reliably 
//even when exceptions pop up in unexpected places 
//is hard. Many people simply don’t bother, 
//and because exceptions are typically reserved 
//for exceptional circumstances, the problem may 
//occur so rarely that it is never even noticed.
//Whether that is a good thing or a really bad thing 
//depends on how much damage the software will do when it fails.

 

7、Anomalous branch

jsThe catch branch is not supported, and the exception caused by undefined.call is also captured in try-catch.

Some people may want to know where the problem is just by comparing the information in e, but the exception information is not a stable thing. Once the expression of the exception information is changed, the program will not work properly. A more reliable solution is as follows (custom null exception, just to use the class area)No, nothing.

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;
    }
  }
}

 

Exercises

① Retry

class MultiplicatorUnitFailure extends Error {}

function primitiveMultiply(a, b) {
    if(Math.random() < 0.2) {
        return a * b;
    } else {
        throw new MultiplicatorUnitFailure("Klunk");
    }
}

function reliableMultiply(a, b) {
    let result = undefined;
    for (; result == undefined;) {
        try {
            result = primitiveMultiply(a, b);
        } catch(e) {
            if (e instanceof MultiplicatorUnitFailure) {                
            } else {
                throw e;
            }
        }        
    }
    return result;
}

console.log(reliableMultiply(8, 8));
// → 64

————– – —  — – –  ——-—– – -—– – –

② The locked box

const box = {
  locked: true,
  unlock() { this.locked = false; },
  lock() { this.locked = true;  },
  _content: [],
  get content() {
    if (this.locked) throw new Error("Locked!");
    return this._content;
  }
};

function withBoxUnlocked(body) {
  let locked = box.locked;
  if (!locked) {
    return body();
  }

  box.unlock();
  try {
    return body();
  } finally {
    box.lock();
  }
}

withBoxUnlocked(function() {
  box.content.push("gold piece");
});

try {
  withBoxUnlocked(function() {
    throw new Error("Pirates on the horizon! Abort!");
  });
} catch (e) {
  console.log("Error raised:", e);
}

console.log(box.locked);
// → true

 

Leave a Reply

Your email address will not be published. Required fields are marked *