JavaScript Strict Mode and Best Practices
“use strict”;
这不是一条语句,而是一个 literal 表达式,被 ECMAScript 5 之前版本的 JS 忽略。其作用是指令代码需要在严格模式下执行。
使用 strict mode,使得原先可以接受的 “bad syntax” 变成了真正的 error。
声明
- 在 JS 文件最开始的地方声明,则表示所有代码将在严格模式下被执行。
- 在 function 内部最开始的地方声明,则只有该函数内的代码需要在严格模式下被执行。
Not Allowed in Strict Mode
- 不声明,就使用一个变量或对象。(非严格模式下,这个变量会自动变为全局变量,现在则会报错)
- 使用
delete
操作符删除一个变量或对象、函数 - 函数中出现重复的形式参数名
- Octal numeric literals 不允许八进制常量
- 不可以给对象中,属性定义 writable 为 false 的属性赋值
- 也不可以给 get-only 的属性(比如一个只可以 return 值的函数)赋值
- 删除一个 undeletable 的属性
- 保留字 eval, arguments, implements, interface, let, package, private, public, protected, static, yield
- 不允许使用
with
语句
最佳实践
避免 Global 变量
- 最少程度地使用全局变量,因为全局变量可以被其他 scripts 重写,相对地,使用局部变量和使用闭包(参考 JS Scope closure 内容)
- 函数中所有的局部变量,必须使用
var
提前声明 - 尽管 JS 默认会把所有 declarations 移到顶端 (JS Hoisting),自己在写的时候,在最上面书写所有声明
- 最好在声明变量的时候,就初始化赋值,这样可以提供一目了然的 intended use(intended data type),避免 undefined 值
避免使用 new
总是将 Number、String or Boolean 类型的变量视为 primitive values,不要使用 new
来初始赋值。见下例:
var x = "John";
var y = new String("John");
(x === y) // is false because x is a string and y is an object.
所有类型变量的初始赋值:
var x1 = {}; // new object
var x2 = ""; // new primitive string
var x3 = 0; // new primitive number
var x4 = false; // new primitive boolean
var x5 = []; // new array object
var x6 = /()/; // new regexp object
var x7 = function(){}; // new function object
小心变量类型的自动转换
JS data type 是松散的类型。比如一个数字变量和一个字符串变量相加,加号视为字符串链接操作符,结果变为字符串。
var x = 5 + 7; // x.valueOf() is 12, typeof x is a number
var x = 5 + "7"; // x.valueOf() is 57, typeof x is a string
var x = "5" + 7; // x.valueOf() is 57, typeof x is a string
var x = 5 - 7; // x.valueOf() is -2, typeof x is a number
var x = 5 - "7"; // x.valueOf() is -2, typeof x is a number
var x = "5" - 7; // x.valueOf() is -2, typeof x is a number
var x = 5 - "x"; // x.valueOf() is NaN, typeof x is a number
var x = "Hello" - "Dolly"; // returns NaN
使用 === 进行比较
因为 ==
操作符总是在比较前将操作符两边的变量进行转换(to matching types),所以是不严格的比较。
给函数形参设定 default 值
如果调用函数时少传递了一个参数,这个 miss 掉的参数就会被赋值为 undefined,可以向下这样处理:
function myFunction(x, y) {
if (y === undefined) {
y = 0;
}
}
ES6允许为函数的参数设置默认值,即直接写在参数定义的后面 function log(x, y = 'World')
避免使用 eval()
该函数用来将 text 作为 JS code 允许其执行。因为它允许任何代码执行,会带来安全问题。
减少 loop 里的操作
循环中的每一条语句,包括 for 语句,在每一次循环遍历时都要执行一遍。
var i, l, arr = [];
l = arr.length;
for (i = 0; i < l; i++) {}
把获取数组长度代码放在循环之外,使得循环执行更快。
减少 DOM 获取操作和 DOM 大小
保持 HTML DOM 里面的元素数量少而精,可以提高页面加载、渲染速度。
比起其他 JS 语句,获取 HTML DOM 速度慢,如果需要多次获取一个 DOM 元素,最好获取一次,然后作为局部变量来使用。
obj = document.getElementById("demo");
obj.innerHTML = "Hello";
减少不必要的变量
如果你不打算使用变量来保存数值,不要创建新的变量。
推迟 JS 加载
把 JS 文件放在页面底部,让浏览器先加载页面。因为下载脚本时,浏览器不会开始其他的下载了,所有的解析、渲染可能被 blocked。
如果可能,可以在页面加载完之后,通过代码把脚本加进来。
<script>
window.onload = downScripts;
function downScripts() {
var element = document.createElement("script");
element.src = "myScript.js";
document.body.appendChild(element);
}
</script>
也可以在 script 标签里添加 defer="true"
,该特性 specifies that the script should be executed after the page has finished parsing, but it 只作用于外链脚本.
- 不 block the page
- 当DOM is ready时执行(但是 before
DOMContentLoaded
事件)
哈佛大学CS50
- 参数名称与变量名称保持一致,是一种惯例,for visual convienence 便于阅读。
- copy + paste 有时走捷径看似节省了时间,但当项目文件中出现了相同的代码。任何东西的重复,都是不好的设计。
- Client-side validation is not robust(仅通过 input attributes 使用浏览器验证,不是健壮的防御)。fu wu服务器经常被黑客攻击的一个原因就是没有做服务端验证。因此,永远不要信任用户的输入,比如:SQL injection attack。