JavaScript基础笔记(十四)最佳实践
最佳实践
一)松散耦合
1.解耦HTML/JavaScript:
1)避免html种使用js
2)避免js种创建html
2.解耦CSS/JS
操作类
3.解耦应用逻辑和事件处理
以下是要牢记的应用和业务逻辑之间松散耦合的几条原则:
勿将 event 对象传给其他方法;只传来自 event 对象中所需的数据;
任何可以在应用层面的动作都应该可以在不执行任何事件处理程序的情况下进行;
任何事件处理程序都应该处理事件,然后将处理转交给应用逻辑。
牢记这几条可以在任何代码中都获得极大的可维护性的改进,并且为进一步的测试和开发制造了很
多可能 。
二)尊重对象所有权
1.尽量不修改不属于你的对象
2.避免全局变量(以单一的全局变量作为一个容器,在其中定义其他对象)
3.避免与null进行比较(能直接进行类型或值检查的请检查)
如果看到了与 null 比较的代码,尝试使用以下技术替换:
如果值应为一个引用类型,使用 instanceof 操作符检查其构造函数;
如果值应为一个基本类型,使用 typeof 检查其类型;
如果是希望对象包含某个特定的方法名,则使用 typeof 操作符确保指定名字的方法存在于对
象上。
4.常量的使用
var Constants = {
INVALID_VALUE_MSG: "Invalid value!",
INVALID_VALUE_URL: "/errors/invalid.php"
};
function validate(value){
if (!value){
alert(Constants.INVALID_VALUE_MSG);
location.href = Constants.INVALID_VALUE_URL;
}
}
三)性能问题
1.避免全局查找
使用全局变量和函数肯定要比局部的开销更大 。
function updateUI(){
var imgs = document.getElementsByTagName("img");
for (var i=0, len=imgs.length; i < len; i++){
imgs[i].title = document.title + " image " + i;
}
var msg = document.getElementById("msg");
msg.innerHTML = "Update complete.";
}
更改后:
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("msg");
msg.innerHTML = "Update complete.";
}
2.避免with语句
3.避免不必要的属性查找
在计算机科学中,算法的复杂度是使用 O 符号来表示的。最简单、最快捷的算法是常数值即 O(1)。
之后,算法变得越来越复杂并花更长时间执行
标 记 名 称 描 述
O(1) 常数 不管有多少值,执行的时间都是恒定的。一般表示简单值和存储在变量中的值
O(log n) 对数 总的执行时间和值的数量相关,但是要完成算法并不一定要获取每个值。例如:二分查找
O(n) 线性 总执行时间和值的数量直接相关。例如:遍历某个数组中的所有元素
O(n2) 平方 总执行时间和值的数量有关,每个值至少要获取n次。例如:插入排序
对象上的任何属性查找都要比访问变量或者数组花费更长时间,
因为必须在原型链中对拥有该名称的属性进行一次搜索
问题代码:
var query = window.location.href.substring(window.location.href.indexOf("?"));
改进后
var url = window.location.href;
var query = url.substring(url.indexOf("?"));
4.优化循环
(1) 减值迭代——大多数循环使用一个从 0 开始、增加到某个特定值的迭代器。在很多情况下,从
最大值开始,在循环中不断减值的迭代器更加高效。
(2) 简化终止条件——由于每次循环过程都会计算终止条件,所以必须保证它尽可能快。也就是说
避免属性查找或其他 O(n)的操作。
(3) 简化循环体——循环体是执行最多的,所以要确保其被最大限度地优化。确保没有某些可以被
很容易移出循环的密集计算。
(4) 使用后测试循环——最常用 for 循环和 while 循环都是前测试循环。而如 do-while 这种后测
试循环,可以避免最初终止条件的计算,因此运行更快。
待优化:
for (var i=0; i < values.length; i++){
process(values[i]);
}
优化1:
for (var i=values.length -1; i >= 0; i--){
process(values[i]);
}
进一步优化:
var i=values.length -1;
if (i > -1){
do {
process(values[i]);
}while(--i >= 0);
}
5.避免双重解释
当 JavaScript 代码想解析 JavaScript 的时候就会存在双重解释惩罚。当使用 eval()函数或者是
Function 构造函数以及使用 setTimeout()传一个字符串参数时都会发生这种情况
//某些代码求值——避免!!
eval("alert('Hello world!')");
//创建新函数——避免!!
var sayHi = new Function("alert('Hello world!')");
//设置超时——避免!!
setTimeout("alert('Hello world!')", 500);
在以上这些例子中,都要解析包含了 JavaScript 代码的字符串。这个操作是不能在初始的解析过程
中完成的,因为代码是包含在字符串中的,也就是说在 JavaScript 代码运行的同时必须新启动一个解
析器来解析新的代码。
6.其他:
原生方法较快——只要有可能,使用原生方法而不是自己用 JavaScript 重写一个。原生方法是用
诸如 C/C++之类的编译型语言写出来的,所以要比 JavaScript 的快很多很多。 JavaScript 中最容
易被忘记的就是可以在 Math 对象中找到的复杂的数学运算;这些方法要比任何用 JavaScript 写
的同样方法如正弦、余弦快的多。
Switch 语句较快 —— 如果有一系列复杂的 if-else 语句,可以转换成单个 switch 语句则可
以得到更快的代码。还可以通过将 case 语句按照最可能的到最不可能的顺序进行组织,来进一
步优化 switch 语句。
位运算符较快 —— 当进行数学运算的时候,位运算操作要比任何布尔运算或者算数运算快。选
择性地用位运算替换算数运算可以极大提升复杂计算的性能。诸如取模,逻辑与和逻辑或都可
以考虑用位运算来替换。
7.最小化语句数
JavaScript 代码中的语句数量也影响所执行的操作的速度。完成多个操作的单个语句要比完成单个
操作的多个语句快 。
8.优化DOM操作
1)减少现场更新
一旦你需要访问的 DOM 部分是已经显示的页面的一部分,那么你就是在进行一个现场更新。之所
以叫现场更新,是因为需要立即(现场)对页面对用户的显示进行更新。每一个更改,不管是插入单个
字符,还是移除整个片段,都有一个性能惩罚,因为浏览器要重新计算无数尺寸以进行更新。现场更新
进行得越多,代码完成执行所花的时间就越长;完成一个操作所需的现场更新越少,代码就越快。
//10次现场更新
var list = document.getElementById("myList"),
item,
i;
for (i=0; i < 10; i++) {
item = document.createElement("li");
list.appendChild(item);
item.appendChild(document.createTextNode("Item " + i));
}
改进后
//一次现场更新:
var list = document.getElementById("myList"),
fragment = document.createDocumentFragment(),
item,
i;
for (i=0; i < 10; i++) {
item = document.createElement("li");
fragment.appendChild(item);
item.appendChild(document.createTextNode("Item " + i));
}
list.appendChild(fragment);
2)使用innerHTML
有两种在页面上创建 DOM 节点的方法:使用诸如 createElement()和 appendChild()之类的
DOM 方法,以及使用 innerHTML。对于小的 DOM 更改而言,两种方法效率都差不多。然而,对于大
的 DOM 更改,使用 innerHTML 要比使用标准 DOM 方法创建同样的 DOM 结构快得多。
使用 innerHTML 的关键在于(和其他 DOM 操作一样)最小化调用它的次数。例如,下面的代码
在这个操作中用到 innerHTML 的次数太多了:
var list = document.getElementById("myList"),
i;
for (i=0; i < 10; i++) {
list.innerHTML += "<li>Item " + i + "</li>"; //避免!!!
}
3)使用事件代理
大多数 Web 应用在用户交互上大量用到事件处理程序。页面上的事件处理程序的数量和页面响应
用户交互的速度之间有个负相关。为了减轻这种惩罚,最好使用事件代理。
事件代理,用到了事件冒泡。任何可以冒泡的事件都不仅仅可以在事
件目标上进行处理,目标的任何祖先节点上也能处理。使用这个知识,就可以将事件处理程序附加到更
高层的地方负责多个目标的事件处理。如果可能,在文档级别附加事件处理程序,这样可以处理整个页
面的事件。
4)注意HTMLCollection
任何时候要访问 HTMLCollection,不管它是一个属性还是一个方法,都是在文档上进
行一个查询,这个查询开销很昂贵。最小化访问 HTMLCollection 的次数可以极大地改进脚本的性能。
也许优化 HTMLCollection 访问最重要的地方就是循环了。前面提到过将长度计算移入 for 循环
的初始化部分。现在看一下这个例子:
var images = document.getElementsByTagName("img"),
i, len;
for (i=0, len=images.length; i < len; i++){
//处理
}
这里的关键在于长度 length 存入了 len 变量,而不是每次都去访问 HTMLCollection 的 length
属性。当在循环中使用 HTMLCollection 的时候,下一步应该是获取要使用的项目的引用,如下所示,
以便避免在循环体内多次调用 HTMLCollection。
var images = document.getElementsByTagName("img"),
image,
i, len;
for (i=0, len=images.length; i < len; i++){
image = images[i];
//处理
}
进行了对 getElementsByTagName() 的调用;
获取了元素的 childNodes 属性;
获取了元素的 attributes 属性;
访问了特殊的集合,如 document.forms、 document.images 等
JavaScript基础笔记(十四)最佳实践的更多相关文章
- JavaScript基础笔记(四) JS式面向对象
JS式面向对象 一.理解对象 一)属性类型 ECMA-262 第 5 版在定义只有内部才用的特性(attribute)时,描述了属性(property)的各种特征. ECMA-262 定义这些特性是为 ...
- JavaScript基础笔记二
一.函数返回值1.什么是函数返回值 函数的执行结果2. 可以没有return // 没有return或者return后面为空则会返回undefined3.一个函数应该只返回一种类型的值 二.可变 ...
- JavaScript基础笔记一
一.真假判断 真的:true.非零数字.非空字符串.非空对象 假的:false.数字零.空字符串.空对象.undefined 例: if(0){ alert(1) }else{ alert(2) } ...
- 转载----给JavaScript初学者的24条最佳实践
给JavaScript初学者的24条最佳实践 1.使用 === 代替 == JavaScript 使用2种不同的等值运算符:===|!== 和 ==|!=,在比较操作中使用前者是最佳实践. “如果 ...
- Bootstrap<基础二十四> 缩略图
Bootstrap 缩略图.大多数站点都需要在网格中布局图像.视频.文本等.Bootstrap 通过缩略图为此提供了一种简便的方式.使用 Bootstrap 创建缩略图的步骤如下: 在图像周围添加带有 ...
- python3.4学习笔记(十四) 网络爬虫实例代码,抓取新浪爱彩双色球开奖数据实例
python3.4学习笔记(十四) 网络爬虫实例代码,抓取新浪爱彩双色球开奖数据实例 新浪爱彩双色球开奖数据URL:http://zst.aicai.com/ssq/openInfo/ 最终输出结果格 ...
- 《C++游戏开发》笔记十四 平滑过渡的战争迷雾(二) 实现:真正的迷雾来了
本系列文章由七十一雾央编写,转载请注明出处. http://blog.csdn.net/u011371356/article/details/9712321 作者:七十一雾央 新浪微博:http:/ ...
- Java15-java语法基础(十四)抽象类
Java15-java语法基础(十四)抽象类 一.抽象类的作用 三个类都有"执行任务"的方法,分别在这三个类中进行定义,因此需要重复编写代码,降低了程序开发效率,且增加了程序出现错 ...
- JavaScript基础笔记集合(转)
JavaScript基础笔记集合 JavaScript基础笔记集合 js简介 js是脚本语言.浏览器是逐行的读取代码,而传统编程会在执行前进行编译 js存放的位置 html脚本必须放在&l ...
- 软件设计师【软件工程:软件开发模型、XP极限编程十二最佳实践】
一.软件开发模型 二.XP极限编程十二最佳实践
随机推荐
- springboot linux启动方式
手动启动 java -Xms128m -Xmx256m -Xdebug -Xrunjdwp:server=y,transport=dt_socket,address=8081,suspend=n -j ...
- exec函数族
进程程序替换 进程程序替换原理 fork创建子进程执行的是和父进程相同的程序(也有可能是某个分支),通常fork出的子进程是为了完成父进程所分配的任务,所以子进程通常会调用一种exec函数(六种中的任 ...
- Encountered IOException running import job: org.apache.hadoop.mapred.FileAlreadyExistsException: Output directory hdfs://slaver1:9000/user/hadoop/tb_user already exists
1.当时初学Sqoop的时候,mysql导入到hdfs导入命令执行以后,在hdfs上面没有找到对应的数据,今天根据这个bug,顺便解决这个问题吧,之前写的http://www.cnblogs.com/ ...
- Java集合源码学习(四)HashMap
一.数组.链表和哈希表结构 数据结构中有数组和链表来实现对数据的存储,这两者有不同的应用场景,数组的特点是:寻址容易,插入和删除困难:链表的特点是:寻址困难,插入和删除容易:哈希表的实现结合了这两点, ...
- Java基础知识➣集合整理(三)
概述 集合框架是一个用来代表和操纵集合的统一架构.所有的集合框架都包含如下内容: 接口:是代表集合的抽象数据类型.接口允许集合独立操纵其代表的细节.在面向对象的语言,接口通常形成一个层次. 实现(类) ...
- ajax一次获取整个表单的数据
$.ajax({ cache: true, type: "POST", url:ajaxCallUrl, data:$('#yourformid').serialize(),// ...
- mysql数据类型(三)
MySQL 数据类型 MySQL中定义数据字段的类型对你数据库的优化是非常重要的. MySQL支持多种类型,大致可以分为三类:数值.日期/时间和字符串(字符)类型. 数值类型 MySQL支持所有标准S ...
- net core体系-API-1Ocelot-(2)继续深入
简单的说Ocelot是一个用.NET Core实现并且开源的API网关技术.可能你又要问了,什么是API网关技术呢?Ocelot又有什么特别呢?我们又该如何集成到我们的asp.net core程序中呢 ...
- Linux拷贝U盘文件(命令行)
Linux系统有的有界面,有的没有只要命令窗口,因此导入外部文件就变得困难,没有可视化的方便. 这里通过挂载u盘进行文件拷贝. 首先挂载u盘:这里以centos为例 1.进入命令行模式下,输入命令 s ...
- Python学习(六) —— 函数
一.函数的定义和调用 为什么要用函数:例如,计算一个数据的长度,可以用一段代码实现,每次需要计算数据的长度都可以用这段代码,如果是一段代码,可读性差,重复代码多: 但是如果把这段代码封装成一个函数,用 ...