/*
* 前言
* 这个文档摘自Nicbolas C Zakas(担任过雅虎首席前端工程师) 著作 《编写可维护的 JavaScript》,下面是一些摘要
* 这个文档讲了一些很基本的编写JavaScript 代码的规范,很基础,但是很重要
* 良好的代码格式可以让代码结构和逻辑看起来更清晰,更美观,也更利于维护,尤其是维护问题。除非
* 写完一段代码你以后都不用再看它了(但这基本是不可能的),请一定让自己养成一个良好的
* 编写代码的习惯,否则这就是在给自己和后来的人挖坑。
*/
一、基本的编写规范
1、缩进和空格,正确的缩进能够明确代码结构,规范的缩进示例
// 最基本的结构缩进
if(true){
alert();
}
// 换行缩进,换行后应该有两个制表符的缩进
function(name, age, gender, class,
school){
alert();
}
// 运算符的边都应该有空格
var name = "";
if(true && true){
}
2、语句结尾,JavaScript可以用分号结尾,也可以不写分号,但是良好的习惯建议不要省略
3、行的长度,建议是不超过80个字符,原则是不要让编码窗口出现横向滚动条
4、换行原则,一般是在运算符后面换行,换行后应该有两个缩进,规范的示例
fif(name == "" && age == "" && gender == "" &&
school != ""){ // 这一行应该有两个制表符,下面的内容依旧根据结构缩进
alert();
}
// 但是有个例外:赋值运算,换行后应该与等号右边对齐
var sqlString = "select * from where id = '' and " +
"name = order by id desc";
// 函数赋值给变量时不需要遵循上面的规则
var getName = function(){
return name;
};
5、命名,基本的大小驼峰命名法,变量以名词开头,小驼峰法,方法动词开头,小驼峰法,看示例
规范的命名是为了更好的阅读维护,优秀的命名是具有自我说明性的,见其名知其意
如果不知道该如何命名,你就想想你这段代码的目的。另外,请一定用英文命名
// 变量命名
var name = "Tom";
var count = 10;
var mySchoolName = "Big School";
// 方法
function getName(){
return name;
}
// 常量,全大写字母,单词之间以下划线分割
var MAX_SIZE = 10;
6、JavaScript 的构造函数,大驼峰命名法,因为 JavaScript 的构造函数都是需要 new 的
// 构造函数
function Person(name){
this.name = name;
}
Person.prototype.sayName(){
alert(this.name);
}
var me = new Person("Tom");
// 这样很容易就跟方法区分开了,规范之后很容易就发现第一行代码少了 new 关键字
var me = Person("Tom");
var you = getName("Tim");
7、字符串,JavaScript 中字符串可以单引号或者双引号包裹,书中建议是双引号,因为有时需要
与Java 代码转换,但是个人认为如果只是纯粹的拼接HTML 代码的话,单引号更直接一些,因为不需要
考虑“的转意
8、数字,JavaScript 中只有整数和浮点数类型,使用浮点数时不能缩略小数位和整数位,不要使用八进制
// 错误示范
var price = 10.;
var price = .1;
var num = 010;
9、null,null 是个特殊的值,常常跟undefined 搞混,因为alert(null == undefined) 输出true
以下场景中当使用null
// 初始化变量,如
var Person = null;
// 与一个已经初始化的变量比较
var Person = null;
if(Person == null)
// 当参数期望是一个对象时,函数返回值期望是一个对象时
function getStudentName(stu){
if(stu){
return stu.name;
}else{
null;
}
}
var stuName = getStudentName(null);
// 不好的用法,与未初始化的变量比较
if(name == null)
//以及检测是否传入了参数
function(name){
if(name != null);
}
10、undefined,当一个变量未被初始化或者不存在的时候的默认值就是undefined。一般情况下应该禁止
使用它,来保证代码中只有一种情况返回undefined ,就是变量未声明的时候
// 简单的例子说明何时返回undefined
var Person;
console.log(typeof Person); // "undefined"
console.log(typeof str); // "undefined"
// 养成良好的习惯,声明变量的时候即初始化,以保证只有未声明变量时才出现undefined
var Person = null;
11、对象直接量,用最简洁的方式创建对象
// 一般的做法,已经不推荐使用
var stu = new Object();
stu.name = "Tom";
stu.gender = "男";
// 简洁的做法
var stu = {
name: "Tom",
gender: "男"
}
// 数组也是类似的情况
var nums = ["abc", "def", "ghi"];
二、注释规范
1、单行注释,
// 基本的单行注释,内容与符号间有一个空格
if(true){
// 单行注释前应该有换行,缩进与解释的代码一致
return null; // 同行注释前应该有一个制表符
}
2、多行注释,可以参考Java 的注释风格
/*
* 前面加* 号,并且添加一个空格
*/
3、文档注释,跟Java 类似
/**
* 多行注释
* @param 参数说明
*/
4、使用注释的时机
⑴ 难以理解的代码
⑵ 可能被认为是错误的代码
⑶ 浏览器特性代码(看起来似乎很烂很低效,实际上是为了兼容性而写的代码)
⑷ 函数、类的说明要用文档注释,注释应该写明白参数的意义
三、语句和表达式
1、if 语句
// 正确的写法,无论之后有几条语句,都应该用括号包起来,并且有合适的缩进和换行
if(true){
alert("正确的写法");
}
// 错误的写法
if(true)
alert();
if(true) alert();
if(true){ alert(); }
2、花括号对齐方式,有两种,一般以Java 为主流
// Java 推崇的对齐方式,左边跟在第一句语句结尾,示例如下
if(true){
alert();
}
// C#推崇的对齐方式
if(true)
{
alert();
}
3、switch 语句块,两种风格,看个人喜好
// Java 类似的编译器风格
switch(num){
case "1":
break;
case "2":
break;
default: // 选项很明确时可以不要默认选项
}
// 第二种风格
switch(num){
case "1":
break;
case "2":
break;
default: // 选项很明确时可以不要默认选项
}
4、for 和 for-in
// 有些规范中禁止for 里面使用continue ,建议用if代替,因为这样结构不明确
// for-in 看起来和for,很像,但是用途有些不一样,for-in用来遍历对象属性
var prop;
for(prop in object){
console.log("property name is " + prop);
console.log("property value is" + object[prop]);
}
// 需要特别注意的是for-in 不但遍历本身的属性,还会遍历从原型继承的属性,
// 这就导致在遍历自定义对象时容易因为意外而终止,可以使用一个方法过滤掉
var prop;
for(prop in object){
if(object.hasOwnProperty(prop)){ //过滤掉原型的属性
console.log("property name is " + prop);
console.log("property value is" + object[prop]);
}
}
5、函数和变量的声明,在Java 和 JavaScript 中是允许调用在声明之前的,但是在c语言
中是不允许的,虽然调用在声明之前并不会出现编译错误或者不能正常运行,但是某
些时候有可能会出现一些小的问题,为了规范代码,最好是先声明后调用。
6、立即调用的函数,立即执行的匿名函数,一般是需要通过复杂的计算以获得一个值
// 不好的写法
var value = function(){
return null;
}(); // 这里调用意图很不明显,虽然它确实是符合语法的调用执行
// 正确的写法
var value = (function(){
return null;
}());
7、判断比较运算,JavaScript 具有强制类型转换机制,即在做普通的比较的时候,如果
两个变量或者值类型不同时会首先进行强制类型转换,然后进行比较。
// 比较字符串"5" 与数值 5,会先将字符串转换为数值
console.log(5 == "5"); // true
// 数值与16进制的比较
console.log(25 == "0x19"); // true
// 如果比较的其中一个变量为对象时,则会先调用对象的valueOf 得到原始类型值再
比较,没有定义valueOf 则调用toString 比较
var object = {
toString: function(){
return "0x19";
}
};
console.log(25 == object); // true
// 因为强制类型转换的缘故,null 与 undefined 被认为是相等的
console.log(null == undefined); // true
console.log(0 == false); // true
// 为了避免这些情况,所以比较的时候推荐使用 === 和 !==
console.log(5 == "5");
console.log(5 === "5"); // false
8、eavl() ,这个函数可以将字符串转换为JavaScript 代码执行,可以做到这一点的方法
还有 Function() 构造函数和 setTimeOut()、setInterval(),但是强烈不推荐使用,
除非别无他法,必须使用。
// 将字符串转换为JavaScript 代码执行
eval("alert('hello')");
eval("1+1");
// 通过 Function 构造函数以及setTimeOut 和 setInterval也可以实现
var myFunc = new Function("alert('hello')");
setTimeOut("alert('hello')");
setInterval("alert('hello')");
// 各种js规范中都非常不推荐使用eval(),setTimeOut() 和 setInterval()
应该传入函数
setTimeOut(function(){
},1000);
9、原始包装类型,原始类型包括String,Boolean,Number,原始包装类型主要是为了
让原始值具有对象般的行为
// 最典型的就是字符串的原始类型
var name = "Tom"; // name 只是一个普通的字符串,但是下面的语句可以执行
console.log(name.toUpperCase); //是因为JavaScript 引擎在需要的时候创建了实例
// 但是这个实例马上就会被销毁掉,用完就丢了
var name = "Tom";
name.author = "mySelf"; // 这行执行完毕String 实例就会被销毁
console.log(name.author); // undefined
// 虽然JavaScript 中可以这么使用,但是我们应该人为的避免使用这些原始类型
var name = new String("Tom");