概述
第1条:JS第一条,代码不“规范”,开发两行泪
这里的规范是指任何一个项目开始之前都要明确代码运行的环境即浏览器版本及其所支持JavaScript版本。如笔者日常都是面向移动端(iPhone、Android等)进行开发因此ES3特性及部分ES5特性都可较为方便的使用,而部分不幸同行还要为IE奔波劳累......
因此第一条也是最关键一条,开发者一定要明白清楚自己所要面向的代码运行环境,及其所能支持JS版本(即其所支持的ECMAScript标准)。
栗子1 const关键字,在ES6标准之前此关键字并没有纳入到ES标准中,因此它只在部分JavaScript引擎中支持,所以同一行代码在不同环境上运行结果会有差异:
const PI = 3.141592652589793;
PI = "modified!";
PI;
同样的代码在支持const环境里,运行结果PI为3.141592653589792,部分老版本浏览器中只是将const视为var的代名词,运行结果就会是"modified"。面对此类问题的解决方案就只能要求开发人员针对所要运行的环境采用最低ES版本特性进行开发,不考虑IE的情况下,大部分程序猿基于ES3标准规范进行开发基本能够满足大部分场景。当然对于采用nodejs进行后端开发的开发人员来说,基于ES6进行开发是比较幸福的群体。
题外话:虽然目前很多公司启用了nodejs+babel模式开发前端运行JS代码,并通过babel进行运行环境适配调优,但就个人以往项目经历来看这个也是不能保证万无一失的,开发不能把握好目标运行环境特性还是要做好随时打包回家的考虑。
第2条:巧用“严格模式”
前端JS开发一直存在一个问题,就是大多数业务场景下开发人员无法像控制JVM(或其他vm)版本那样控制客户端版本以控制自己代码的运行环境。这个很好理解,就好比Google搜索很好用但无法要求用户必须下载安装chrome才能搜索(少数2B前端开发会在这方面会幸福很多),但是或多或少又确实存在对于JS运行环境进行控制地需求(我个人很多时候抓狂地想让浏览器支持插件那样支持前端开发自定义的指定JS运行环境及版本,客观上来讲移动Hybrid APP一定程度上能够满足这样的需求)。经过几大厂(主要是google、微软、Firefox等)在W3C上博弈出的ES5标准中首次确定了严格模式(strict mode),通过它可以禁用一些JS语言中问题较多或易出错的特性(聊胜于无)。
严格模式说明 引入它相对过去传统模式(又称作马虎模式/稀松模式/懒散模式)会在以下带来如下几方面变化:
1. 更强的语法控制:一些静默错误会导致抛出错误(如果没有catch就会终止js进程);
2. (可能)更高的运行效率:此模式下修复了JS引擎难以执行优化的缺陷,因此有时候相同的代码会运行的更快相对传统模式。
3. 为未来预留:严格模式禁用了ECMAScript未来版本中可能会定义的一些语法,为未来提升预留准备。
开启严格模式方法:
A. 脚本文件级开启使用严格模式
// 整个脚本都开启严格模式的语法
"use strict";
var v = "Hi! I'm a strict mode script!";
此模式下整个JS脚本文件都会启用严格模式逻辑,但是注意这里是一个巨坑!特别对于采用JS压缩拼接辅助工具的前端项目来说,如果一个启用了严格模式的JS文件与另外一些未启用严格模式的JS文件合并生成压缩JS文件就可能会导致未知异常。因此个人不建议采用此模式开启严格模式,建议采用下面的模式。
B. 函数级开启使用严格模式
function strict(){
// 函数级别严格模式语法
'use strict';
function nested() { return "And so am I!"; }
return "Hi! I'm a strict mode function! " + nested();
}
function notStrict() { return "I'm not strict."; }
注意:就在范例中那样展示的,一个函数开启严格模式其内部定义的任意深度函数也会开启严格模式。
严格模式启用后差异:
1. 更强的语法语义控制:
1.1 不可创建意外地全局变量
//这样做会异常
(function(){
"use strict";
nothing = "123";
}();
1.2 传统模式下静默的错误失败赋值在严格模式会抛出Error
"use strict";
// 给不可写属性赋值
var obj1 = {};
Object.defineProperty(obj1, "x", { value: 42, writable: false });
obj1.x = 9; // 抛出TypeError错误
// 给只读属性赋值
var obj2 = { get x() { return 17; } };
obj2.x = 5; // 抛出TypeError错误
// 给不可扩展对象的新属性赋值
var fixed = {};
Object.preventExtensions(fixed);
fixed.newProp = "ohai"; // 抛出TypeError错误
1.3 删除不可删除属性会抛Error
"use strict";
delete Object.prototype; // 抛出TypeError错误
1.4 同一个对象内的属性名称必须唯一(这是个bug,ES6以后已修改删除此限制)
"use strict";
var o = { p: 1, p: 2 }; // !!! 语法错误
注意:理论上最新版本的浏览器都已经删除此限制(15年8月以后),但是一旦启用严格模式还是要考虑“黄金第1条”。另外说明一下,之所以认定它是一个bug并删除此限制理由有多方面,有兴趣可以参考“bug 1041128”了解更多细节,不过在个人实践过程中该规则存给我造成最大的困难在于进行JSON对象初始化(特别是那种有从数据库直接拿出两个表数据,利用属性同名覆盖机制进行数据前端关联的情况,别问我怎么知道的)时真心会出现重复属性名的情况。
1.5 函数参数名不能重复
function sum(a, a, c){ // !!! 语法错误
"use strict";
return a + a + c; // 代码运行到这里会出错
}
1.6 禁止八进制数字语法
ECMAScript并不包含八进制语法, 但基本所有的浏览器都支持这种以零(0)开头的八进制语法: 0644 === 420 还有 "