Eloquent JavaScript #08# Bugs and Errors

Notes

1、strict mode

strict mode优势:更严格的检查、删除了一些有问题的语言特性。

把 "use strict" 放在文件顶部(必须是文件顶部,放在其它地方就被当成字符串了)或者函数顶部开启js strict模式。

示例1:没启用strict模式,js就会给你悄摸摸地加一个let上去...

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

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

示例2:没启用strict模式,name被悄悄地绑定到一个全局对象上而没报错。

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

// - -- - --修改↓分割线------------------------------------

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

PS. 上述情况,用class定义类具有和采用strict模式一样的效果,所以尽量用class定义类。

 

2、js类型

js在在运行时才会涉及到类型。许多语言在编译期就考虑类型了。

为了减少js类型带来的一些问题,有两个简单的解决方案:

① 注释

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

② TypeScript 

可以进行类型检查,并编译成js

 

3、js测试

采用第三方测试套件或者如下所示:

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.log或者debugger关键字:

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

debugger; // 从这一行开始进入浏览器debug模式

let x = add(1, 3);
prompt("只有在开发者模式下,debug模式才生效");

 

5、Exceptions

异常的一大优势:几乎无耦合地在多个函数中(调用栈)传递,中间函数什么都不需要知道,仅在最外层处理就行了。

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、异常分支

js不支持catch分支,而在try-catch的时候,同样会捕获undefined.call等造成的异常。

有些人可能会想只要比对e里面的信息就可以知道哪儿出现问题了,但是异常信息不是一个稳定的东西,一旦抛出的异常信息的表达改变,程序就不会正常工作,更可靠的解决方案如下(自定义空异常,只为了利用class区分,不加任何东西):

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

 

posted @ 2018-09-01 10:35  xkfx  阅读(216)  评论(0编辑  收藏  举报