Eloquent JavaScript #08# Bugs and Errors

Notes

一、strict modeapp

strict mode優點:更嚴格的檢查、刪除了一些有問題的語言特性。less

把 "use strict" 放在文件頂部(必須是文件頂部,放在其它地方就被當成字符串了)或者函數頂部開啓js strict模式。dom

示例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被悄悄地綁定到一個全局對象上而沒報錯。oop

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定義類。測試

 

二、js類型this

js在在運行時纔會涉及到類型。許多語言在編譯期就考慮類型了。spa

爲了減小js類型帶來的一些問題,有兩個簡單的解決方案:

① 註釋

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

② TypeScript 

能夠進行類型檢查,並編譯成js

 

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

 

四、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模式才生效");

 

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

 

六、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.

 

七、異常分支

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
相關文章
相關標籤/搜索