Notes
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定义类。
js在在运行时才会涉及到类型。许多语言在编译期就考虑类型了。
为了减少js类型带来的一些问题,有两个简单的解决方案:
① 注释
// (VillageState, Array) → {direction: string, memory: Array} function goalOrientedRobot(state, memory) { // ... }
可以进行类型检查,并编译成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() == "مرحبا"; });
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模式才生效");
异常的一大优势:几乎无耦合地在多个函数中(调用栈)传递,中间函数什么都不需要知道,仅在最外层处理就行了。
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); }
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
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
————-- - --- -- - - -------—-- - -—-- - -
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