JS学习22(最佳实践)

可维护性

JS从完成小的网页特效和验证到现在要处理各种复杂的逻辑,页面中代码的数量也是成倍的增长。这就让编写可维护的代码变得越来越重要了。

可维护代码的特点

可理解性
直观性
可适应性
可拓展性
可调试性

代码约定

注释和缩进。
变量命名以名词开始,函数名命名以动词开始,返回布尔值的函数以is开头。

松散耦合

不同语言间的紧耦合
CSS,JS,HTML他们天生就需要交互。有时我们不得不在一个里面修改另一个,这就造成了紧耦合,出了错调试起来非常麻烦。尽量做到分开。

  • HTML里不要有JS这个比较好做到。
  • JS中有时需要动态添加HTML, 这个尽量交给JSP,PHP等页面来做,最后用JS加进去就好。
  • 尽量不要在HTML中写CSS
  • JS中修改样式最好使用类的方式,这样所有样式问题都可以追溯到CSS文件中。

事件处理和应用逻辑间的紧耦合
如果将应用逻辑直接写在事件处理函数中,不管是调试还是重用都会很不方便,将应用逻辑提出来,在事件处理中调用会是一个比较好的方法。有这么几个原则:

  • 不要将event对象传给其他方法,只传来自event对象中所需的数据
  • 任何应用逻辑层面的操作都应该可以在不执行任何事件处理程序的情况下执行
  • 任何事件处理程序都应该处理事件,然后将时间转交给应用逻辑

编程实践

尊重对象所有权
在其他语言中,在没有源码的时候,类和对象一般是不可变的,就算可以也是添加属性和方法,不可能覆盖已有的。但是在JS中,一切都可以修改,覆盖,重写,想干啥干啥。这有时就会造成很严重的问题。
尊重对象的所有权就是说不是属于你的对象不要随便修改,即便你觉得这样会很方便。拥有对象的意思是,这些对象由你创建,由你维护。像Array,document这些对象显然不是你的,就不要尝试修改他们。
避免全局变量

var name = "Nicholas";
function sayName(){
    alert(name);
}

在这里创建了两个全局变量name和sayName。
这样看起来没什么,但是是有问题的,比如变量name覆盖了window的name属性,其他需要这个属性的功能就会因此获得错误的信息。

var MyApplication = {     
    name: "Nicholas",     
    sayName: function(){         
        alert(this.name);     
    } 
}; 
MyApplication.sayName();

这样大家都使用一个全局变量把自己封装起来,使用和共存和调试都很方便:

var Exia = {};
Exia.ProJS = {};
Exia.ProJS.EventUtil = {};
Exia.ProJS.CookieUtil = {};

避免与null进行比较
比如:

function sortArray(values){
    if (values != null){
        values.sort(comparator);
    }
}

function sortArray(values){  
    if (values instanceof Array){       
        values.sort(comparator); 
    } 
} 

这时明显是应该使用下面这种判断更加合理。大多数情况也应该这样判断。如果是引用类型就使用instanceof,基本类型就使用typeof。
使用常量
比如URL,设置的量之类的,放到一个常量里,以后要修改就只需要改一次就好。

var Constants = {
    INVALID_VALUE_MSG: "Invalid value!",     
    INVALID_VALUE_URL: "/errors/invalid.php"
};

重复值
用户界面字符串
URLs
任意可能会更改的值
以上这些值提出来会比较方便

性能

曾经JS是一种解释型语言,执行速度比编译型语言慢的多,Chrome率先实现了将JS编为本地机器码执行的浏览器。后来主流的浏览器都这么做了。即便是这样,我们还是要避免写出低效率的代码。

注意作用域

随着作用域链中作用域的增加,访问当前作用域以外的变量所花的时间也越多,越远越耗时。
避免全局查找
当访问全局变量时就是最慢的,如果在一个局部环境中要多次访问全局的变量,先用一个局部变量把它保存起来比较好。

function updateUI(){     
    var doc = document;     
    var imgs = doc.getElementsByTagName("img");     
    for (var i=0, len=imgs.length; i < len; i++){      
        imgs[i].title = doc.title + " image " + i;  
    }
    var msg = doc.getElementById("mydiv");    
    msg.innerHTML = "Update complete.";
}

避免with语句
with起初的目的是为了让开发人员少写点字

function updateBody(){
    alert(document.body.tagName);
    document.body.innerHTML = "Hello world!";
}
function updateBody(){
    with(document.body){
        alert(tagName);
        innerHTML = "Hello world!";
    }
}
function updateBody(){    
    var body = document.body;   
    alert(body.tagName);   
    body.innerHTML = "Hello world!";
}

虽然确实方便了,不过这样会增加作用域链的长度,会更慢,使用新添加局部变量的办法一般可以达到目的。

选择正确方法

和其他语言一样,性能问题的一部分是和用于解决问题的算法或方法有关的。
避免不必要的属性查找
对于变量和数组中元素的访问都是O(1)级别的操作,但是要访问对象属性的操作则是O(n)级别的。
一旦要多次用到同一个对象的同一个属性就建议把它保存起来,这样第一次是O(n),以后的就是O(1)了。
优化循环
减值迭代,从最大值开始减到0,这样的循环条件一般都会比增值迭代要高效。因为每次循环和终止条件对比时减值对比都是和常量0进行对比,而增量都是和一个变量甚至是一个对象的属性做对比,这样每次循环累计起来就会有一定的差距了。
简化终止条件,每次循环都会和终止条件对比,如果你的终止条件直接是一个对象的一个属性,那每次都要进行O(n)的查找。
简化循环体,这个不用说啥了。
展开循环
当循环次数确定时,使用多次函数调用而不是循环会更快。
不过一般循环的次数都是不确定的呢,
在处理大数据集时,可以使用一个叫Duff装置的技术。这个技术将循环拆成每8次一组。在处理大量数据时提升效果显著。毕竟每8次才有一次处理循环的开销。当然数据量小的时候就并不划算了。

var iterations = Math.floor(values.length / 8);
var leftover = values.length % 8;
var i = 0;
if (leftover > 0){
    do {
        process(values[i++]);
    } while (--leftover > 0);
}
do {   
    process(values[i++]);
    process(values[i++]);  
    process(values[i++]);   
    process(values[i++]);   
    process(values[i++]);    
    process(values[i++]);  
    process(values[i++]);   
    process(values[i++]); 
} while (--iterations > 0);

其他提升性能的方法
原生方法较快
Switch语句较快
位运算符较快

最小化语句数

简单来讲,就是完成多个操作的单个语句要比完成单个操作的多个语句快。
多个变量声明

var count = 5,      
    color = "blue",    
    values = [1,2,3],  
    now = new Date(); 

使用数组和对象字面量

优化DOM交互

最小化现场更新
一旦你需要访问的DOM部分是已经显示页面的一部分,那么你就是在进行一次现场更新。每次现场更新都有一个很大的性能惩罚,浏览器要重新计算各种尺寸和属性。所以更新次数要尽可能少,动作要尽可能的小。
比如你要给一个ul添加多个li,那把所有li准备好一起塞到ul里就比一个一个塞要好。
使用innerHTML
用innerHTML来创建DOM节点,不仅写起来舒服,执行起来也快。这个同样,把字符串拼好了再一次性加到页面里,这样才高效。
使用事件代理
就是在整个文档上添加事件,文档中各个事件冒泡到文档上统一处理。
注意HTMLCollection
任何时候访问这种类型的变量都是在文档上进行了一次查询,这是个很昂贵的操作。尤其是在循环中。。。

var images = document.getElementsByTagName("img"),    
    image,  
    i,
    len;
for (i=0, len=images.length; i < len; i++){  
    image = images[i];     
    //其他操作
} 

这里既在循环终止条件中避免了对HTMLCollection的多次访问,又在循环体里使用image储存了当前要使用的元素,从而避免了多次访问HTMLCollection

部署

构建过程

我们开发Web应用时JS文件是按照可维护性优先的原则组织的,但是这样会存在一些问题:

  • 把带有自己注释的代码放上去,别人就更容易知道你的意图,有可能被人找到漏洞
  • 书写代码时我们保证代码简单易读,但是对于性能是不利的。浏览器并不能从空格和各式各样的变量中获得什么有用的信息

所以使用构建工具将多个JS合并压缩就很必要了。这样的工具有很多,挑顺手的用。

验证

JSLint可以在线验证JS代码中的潜在语法错误。
在开发周期中添加这个环节可以作为发现代码潜在问题的办法。
把验证添加到构建过程中是很常用且推荐的做法。

压缩

文件压缩
如果每次都把带有各种空格和注视的JS通过网络传送到浏览器,显然有太多不必要的开销。
在部署前使用压缩工具压缩JS文件也是必要的。
HTTP压缩
对于服务器向浏览器传送文件这个过程,也是可以优化的,服务器和浏览器现在都有压缩和解压缩功能。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,294评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,780评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,001评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,593评论 1 289
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,687评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,679评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,667评论 3 415
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,426评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,872评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,180评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,346评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,019评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,658评论 3 323
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,268评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,495评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,275评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,207评论 2 352

推荐阅读更多精彩内容

  • 国家电网公司企业标准(Q/GDW)- 面向对象的用电信息数据交换协议 - 报批稿:20170802 前言: 排版 ...
    庭说阅读 10,946评论 6 13
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 172,026评论 25 707
  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,617评论 18 399
  • 九月的上海依然有些闷热,我坐在地铁车厢发着呆。 每天我们都与形形色色的人擦身而过,也许有过眼神交流,也许有过一面之...
    恋粉破晓阅读 268评论 2 3
  • 生活总是在不经意间感动你,有时再微小的事物也能戳中自己的泪点…… 感谢生命中的每一天,和出现在生命里的每个人及其每...
    井溢阅读 147评论 0 0