编写可维护的js代码

在工作中,制定一套统一的编码风格,可以提高开发效率,维护起来的也要容易很多,也能避免一些不必要的错误出现。

项目中常用的检查编码风格的工具JSLintJSHintJSCSESLint,,在这呢,我就不介绍这些工具的使用,大家可以自行去看看官方文档就好,我就给大家介绍平时写时候的要点就好

基本的格式化

缩进层级

使用制表符进行缩进(tab键:一个制表符的长度相当于4个字符)

编辑器可以设置是一个缩进是2个空格还是4个空格还是8个空格,建议是使用4个空格,折中处理,很多编辑器默认也是4个空格.制表符和空格是两个概念,不要混淆

语句结尾

语句结尾用分号结尾,如果省略了分号的话,JSLint和JSHint默认都会有警告 注意点:(javascript Standard标准里面是可以不使用分号,加与不加就看你使用哪种标准)

// 合法的代码
function sayHello(){
  console.log('hello world')
}

// 合法的代码
function sayHello(){
  console.log('hello world');
}
 

行的长度

一行代码不应该超过80个字符,超过80的话,就折行或隐藏

换行

当一行的长度达到了单行最大字符数限制是,就需要手动将一行拆成两行,通常我们会在运算符后换行,下一行会增加两个层级的缩进(两个tab缩进)

callFunction(document,element,windiw,"some string value",true,123,
         navigation);

注意点:主体部分的话,还是保留一个层级的缩进(一个tab,4个字符) 例外:当个变量赋值时,第二行的位置应当和赋值运算符的位置保持对齐

var result=something + anotherthing + yetAnohterthing + somethingElse + 
           anotherthingElse

空行

添加空行是为了提高代码的可读性,以下情况可以添加空行

  • 在方法之间
  • 在方法中的局部变量和第一条语句之间
    if(flag){
        for(let i=0;i<10;i++){
            let p =i;
            
            if(p=8){
                console.log(p);
            }
        }
    }
  • 在多行或则单行注释之前
  • 在方法内的逻辑片段之间
未完待续....

下面场景中应当使用null

  • 用来初始化一个变量,该变量可能为一个对象
  • 用来和一个已经初始化的变量比较该变量可以使也可以不是一个对象
  • 当函数的返回值期望是对象时,用作返回值传出

下面场景不要用null

  • 不要使用null来检测是否传入了某个参数
  • 不要使用null来检测一个未初始化的变量

代码实例:

// 好的用法
var person=null;
// 好的用法
function getPerson(){
    if(condition){
        return new Person("Nicholas");
    }
    else{
        return null
    }
}

// 好的用法
function getPerson(){
    if(person!==null){
        getMag();
    }
    
}
// 不好的写法:用来和初始化的变量比较
var person;
if(person!==null){
    getMag();
}

// 不好写法:检测是否传入了参数
function getArr(arg,agr2,agr3,agr4){
    if(arg4!==null){
        getMag();
    }
}

undefined

undefined不全等于null

null==undefined  // true
null==undefined  // false
typeof undefined // "undefined"
typeof null // object

注释

单行注释

  • 独占一行的注释,用来解释下一行代码,折行注释之前总是有一行空行,切且缩进层级和下一行代码保持一致
  • 在代码的尾部的注释,代码结束到注释之间要有至少一个缩进,注释(包括之前的代码部分)不应当超过单行最大字符数限制,如果超过了,就讲这条注释放置于当前代码行额上方
  • 被注释掉的大段代码可以用单行注释,编辑器里面有自带
// 好的写法:留有空行,及正确的缩进
if(condition){
    
    // 代码执行到这里,则表明通过了所有的安全性检查
    allowed();
}
// 不好的写法:没有空行及错误的缩进
if(condition){
// 代码执行到这里,则表明通过了所有的安全性检查
    allowed();
}
// 好的写法
var result=something +sometimes; // 是的就是这么写

// 不好的写法: 代码和注释之间没有间隔
var result=something +sometimes;// 是的就是这么写

// 好的写法:代码段使用单行注释
// if(condition){
//    flag=true;
//    allowed();
// }

// 不好的写法:这里应该使用多行注释
// 集体那第五次
// 集体那第五次
// 集体那第五次
// 集体那第五次
// 集体那第五次

多行注释

建议的写法是:

/*
* 这是一段注释,风格是仿Java的
*/

  

  • 多行注释注释和单行注释一样,前面都要留一行空行,且缩进层级和其描述的代码保持一致
if(condition){
    
    /*
    * 代码执行到这里,则表明通过了所有的安全性检查
    */
    allowed();
}

 

文档注释

/**
这是一段说明文字
@method=merge
@param {object}
@return null
**/

  

第三章:语句和表达式

所有的语句块都应该使用花括号,包括:

  • if
  • for
  • while
  • do...while
  • try..catch...finally

switch语句

缩进

switch (condition){
case "first":
    break;
case "second":
    break;
default:
    // 代码
}

 

在JSLint中,是期望switch和case的层级缩进是一致的,如果不一致的话,就会警告,但是如果包含额外的空行的话,就不会报警告了

case语句的连续执行

可行方案:当你的代码中出现了case的连续执行,JSLint就会给出警告,但是如果你加上了一句注释的话,就能避免给出警告

switch (condition){

// 这里的连续执行没注释,会给出警告
case "fisrt";
case "second":
    break;
    
// 这里不会给出警告
case "third":
    // 代码
    // fall through
default:
    // 代码
}

 

default

建议:当default中没有逻辑代码时,建议是可以省略default

for循环

尽量避免使用break,和continue语句

  • break:退出循环
  • continue:退出本次循环

for-in循环

for-in循环有个问题,就是它不仅遍历对象的实例属性,同样还遍历从原型继承来的属性,当遍历自定义对象的属性时,往往会因为意外的结果而终止,出于这个原因的考虑,最好使用hasOwnProperty()方法来为for-in循环过滤出实例属性

for (item in obj){
    if(obj.hasOwnProperty(item)){
        console.log("Property is "+item);
        console.log("Property value is "+obj[item]);
    }
}

 

对于循环没有使用hasOwnProperty()方法的for-in循环,JSlint会给出警告

变量函数运算符

相等:在判断相等的时候,为了规范,尽量用全等(=或则!)来判断,目的是为了防止强制转换

console.log(5==="5"); // true 把字符串转为了数字来进行比较

 

原始包装类型:

原始包装类型有:String,Boolean,Number 3钟类型,他们都具有对象的特征,但是在工作中不建议使用

var name="milk";
name.author="coat";
console.log(name.author); // undefined

  

注意点:原始值本身是不具有对象特征,比如1.toString();是报错的必须这样做:var a=1;a.toString();

UI层的松耦合

将css中JavaScript中抽离

在js里面不应该直接操作样式表,而应该是操作className

// 原生写法
element.className+="reveal";

// h5中的写法
element.ClassList.add("reveal");

 

将JavaScript从html中抽离

把JavaScript代码写到外部的js文件中,这样的到时候修改就只需要修改一个文件就可以了

将html从JavaScript中抽离

从服务器加载

将模板放置在远程服务器,使用XMLHttpRequest对象来获取,但是该方法很容易造成XSS漏洞, 需要服务器对模板文件做适当的转义处理


简单的客户端模板

// 这段中%s是占位符
	var li='<li><a href="%s"></a></li>'
	var href="yes"
	function sprintf(text){
		var i=1;args=arguments;
		return text.replace(/%s/g,function(){
			return (i<args.length)?args[i++]:""
		})
	}
	console.log(sprintf(li,"nihao"));

  

通常做法:将模板定义在html标签里面,并且注释掉模板文本,通过JavaScript的dom来提取

html部分:
<ul id="mylist">
        <!-- <li id="item%s"><a href="/item%s"></a></li> -->
        <li><a href="/item/2"></a></li>
        <li><a href="/item/3"></a></li>
        <li><a href="/item/4"></a></li>
    </ul>
javascript部分:
        var mylist=document.getElementById("mylist"),
        templeText=mylist.childNodes[0].nextSibling.data;
        function sprintf(text){
            let i=1,args=arguments;
            return text.replace(/%s/g,function(){
                return (i<args.length) ? args[i++]:'';
            })
        }
        function addItem(url,text){
            var mylist=document.getElementById("mylist"),
            templeText=mylist.childNodes[0].nextSibling.data || "";
            console.log(templeText);
            result=sprintf(templeText,url,text);
        }
        // 这段中%s是占位符
        var li='<li><a href="%s"></a></li>'
        // console.log(sprintf(li,"我也是","是啊是啊","我的"));
        addItem("/5","/five item");

 

检测

检测原始类型:

原始类型有:字符串,数字,布尔值,null,undefined


检测原始类型最好的方式是用typeof运算符
· 检测字符串 typeof 返回的是string
* 对于数字 返回的是 number
* 对于布尔值 返回的是布尔值
* 对于undefined 返回的是 undefined
* 对于null 返回的是 object
* NaN返回的是number

//
检测字符串 if(typeof name==="string"){ return true; } // 检测数字 if(typeof count==="number"){ return true; } // 检测布尔值 if(typeof flag==="boolean" &&flag){ return true; } // 检测undefined if(typeof myApp==="undefined"){ return true; }

 

检测引用类型

内置的引用类型有:Array,Object,Date和Error

检测最好是用instanceof来检测:语法

value instanceof construtor

 

检测的例子

// 检测日期
if(value instanceof Date){
    console.log(value)
}
// 检测正则
if(value instanceof RegExp){
    console.log(value)
}

 

instance还可以检测原型链

var now=new Date();
console.log(now instanceof Object); // true
console.log(now instanceof Date); // true

 

检测函数

函数检测最好用typeof

function Fuc(){}
console.log(typeof Fuc==="function"); // true

 

注意点:在IE8以及更早的版本中,typeof来检测dom节点,的函数,返回的都是object而不是function(93页中说明)

console.log(document.getElementById); //"object"
console.log(document.getElement); //"object"
console.log(document.getElementByTagName); //"object"

 

检测数组

检测数组的时候,用instanceof有时候并不一定准确,所以ES5中新增了一个isArray方法 说明:

var arr=[];
Array.isArray(arr); // true

function isArray(value){
    return Object.prototype.toString.call(value)==="[object Array]"
}

// 如果是json对象的话,返回的则是[object,JSON]

 

检测属性

  • in 运算符检测实例对象的某个属性是否存在
var obj={
        count:0,
        retlated:null
    }
    console.log("count" in obj);
  • hasOwnProperty()方法 检测实例对象的某个属性是否存在:所有继承自Object的javascript对象都有这个方法,如果实力中存在这个属性则返回true(如果这个属性只存在原型中,则返回false),需要注意的是,在IE8以及更早的IE版本中,dom并非继承自Object,因此也不包含这个方法,,也就是说你在调用dom对象的hasOwnProperty()方法之前,应当检测其是否存在
    
    
      •     //  对于所有非dom对象来说, 这是好的写法
                if (object.hasOwnProperty('related')){
                    // 执行这里的代码
                }
                // 如果你不确定是否为dom对象,则这样写
                if("hasOwnProperty" in Object&&object.hasOwnProperty('relative')){
                    // 执行这里的代码
                }

         

posted @ 2018-06-13 23:41  三叶酱  阅读(365)  评论(0编辑  收藏  举报