资讯专栏INFORMATION COLUMN

高程3总结#第24章最佳实践

zhiwei / 640人阅读

摘要:也就是说避免属性查找或其他的操作。简化循环体循环体是执行最多的,所以要确保其被最大限度地优化。代码组织组织代码要考虑到可维护性并不一定是传送给浏览器的最好方式。

最佳实践 可维护性 什么是可维护性的代码

如果说代码是可维护的,它需要遵循以下特点

可理解性——其他人可以接手代码并理解它的意图和一般途径,而无需原开发人员的完整解释。

直观性——代码中的东西一看就能明白,不管其操作过程多么复杂。

可适应性——代码以一种数据上的变化不要求完全重写的方法撰写。

可扩展性——在代码架构上已考虑到在未来允许对核心功能进行扩展

可调试性——当有地方出错时,代码可以给予你足够的信息来尽可能直接地确定问题所在。

代码约定 可读性

可读性大部分内容和代码的缩进相关,当所有人使用一样的缩进方式时,整个项目的代码都会更加易于阅读

可读性的另一方面是注释,下面内容需要进行注释

函数和方法——每个函数或方法都应该包含一个注释,描述其目的和用于完成任务所可能使用的算法。陈述事先的假设也非常重要,如参数代表什么,函数是否有返回值(因为这不能从函数定义中推断出来)。

大段代码——用于完成单个任务的多行代码应该在前面放一个描述任务的注释。

复杂的算法——如果使用了一种独特的方式解决某个问题,则要在注释中解释你是如何做的。这不仅仅可以帮助其他浏览你代码的人,也能在下次你自己查阅代码的时候帮助理解。

Hack——因为存在浏览器差异,JavaScript 代码一般会包含一些 hack。不要假设其他人在看代码的时候能够理解 hack 所要应付的浏览器问题。如果因为某种浏览器无法使用普通的方法,所以你需要用一些不同的方法,那么请将这些信息放在注释中。这样可以减少出现这种情况的可能性:有人偶然看到你的 hack,然后“修正”了它,最后重新引入了你本来修正了的错误。

变量和函数命名

命名规则

变量名应为名词如 car 或 person 。

函数名应该以动词开始,如 getName() 。返回布尔类型值的函数一般以 is 开头,如isEnable() 。

变量和函数都应使用合乎逻辑的名字,不要担心长度。长度问题可以通过后处理和压缩来缓解

变量类型透明

三种表示变量数据类型的方式

初始化

//通过初始化指定变量类型
var found = false; //布尔型
var count = -1; //数字
var name = ""; //字符串
var person = null; //对象

使用匈牙利标记法

//用于指定数据类型的匈牙利标记法
var bFound; //布尔型
var iCount; //整数
var sName; //字符串
var oPerson; //对象

使用类型注释

//用于指定类型的类型注释
var found /*:Boolean*/ = false;
var count /*:int*/ = 10;
var name /*:String*/ = "Nicholas";
var person /*:Object*/ = null

松散耦合

几条规则

勿将 event 对象传给其他方法;只传来自 event 对象中所需的数据;

任何可以在应用层面的动作都应该可以在不执行任何事件处理程序的情况下进行;

任何事件处理程序都应该处理事件,然后将处理转交给应用逻辑

编程实践 尊重对象所有权

不要为实例或原型添加属性;

不要为实例或原型添加方法;

不要重定义已存在的方法。

创建包含所需功能的新对象,并用它与相关对象进行交互;

创建自定义类型,继承需要进行修改的类型。然后可以为自定义类型添加额外功能。

避免全局量
//两个全局量——避免!!
var name = "Nicholas";
function sayName(){
alert(name);
}
//一个全局量——推荐
var MyApplication = {
name: "Nicholas",
sayName: function(){
  alert(this.name);
}
}
避免与null进行比较
function sortArray(values){
if (values != null){ //避免!
  values.sort(comparator);
}
}
function sortArray(values){
if (values instanceof Array){ // 推荐
  values.sort(comparator);
}
}

如果看到了与null比较的代码,尝试使用以下技术替换

如果值应为一个引用类型,使用 instanceof 操作符检查其构造函数;

如果值应为一个基本类型,使用 typeof 检查其类型;

如果是希望对象包含某个特定的方法名,则使用 typeof 操作符确保指定名字的方法存在于对象上。

使用常量
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;
}
}
性能 注意作用域 避免全局查找
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.";
}
避免with语句
function updateBody(){
with(document.body){
  alert(tagName);
  innerHTML = "Hello world!";
}
}
//改进
function updateBody(){
var body = document.body
alert(body.tagName);
body.innerHTML = "Hello world!";
}
选择正确方法 避免不必要的属性查找

优化循环

减值迭代——大多数循环使用一个从 0 开始、增加到某个特定值的迭代器。在很多情况下,从最大值开始,在循环中不断减值的迭代器更加高效。

简化终止条件——由于每次循环过程都会计算终止条件,所以必须保证它尽可能快。也就是说避免属性查找或其他 O(n)的操作。

简化循环体——循环体是执行最多的,所以要确保其被最大限度地优化。确保没有某些可以被很容易移出循环的密集计算。

使用后测试循环——最常用 for 循环和 while 循环都是前测试循环。而如 do-while 这种后测试循环,可以避免最初终止条件的计算,因此运行更快

展开循环
//credit: Speed Up Your Site (New Riders, 2003)
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);
避免双重解释
//某些代码求值——避免!!
eval("alert("Hello world!")");
//创建新函数——避免!!
var sayHi = new Function("alert("Hello world!")");
//设置超时——避免!!
setTimeout("alert("Hello world!")", 500);
//已修正
alert("Hello world!");
//创建新函数——已修正
var sayHi = function(){
alert("Hello world!");
};
//设置一个超时——已修正
setTimeout(function(){
alert("Hello world!");
}, 500);
其他

原生方法较快——只要有可能,使用原生方法而不是自己用 JavaScript 重写一个。原生方法是用诸如 C/C++之类的编译型语言写出来的,所以要比 JavaScript 的快很多很多。JavaScript 中最容易被忘记的就是可以在 Math 对象中找到的复杂的数学运算;这些方法要比任何用 JavaScript 写的同样方法如正弦、余弦快的多。

Switch 语句较快 —— 如果有一系列复杂的 if-else 语句,可以转换成单个 switch 语句则可以得到更快的代码。还可以通过将 case 语句按照最可能的到最不可能的顺序进行组织,来进一步优化 switch 语句。

位运算符较快 —— 当进行数学运算的时候,位运算操作要比任何布尔运算或者算数运算快。选择性地用位运算替换算数运算可以极大提升复杂计算的性能。诸如取模,逻辑与和逻辑或都可以考虑用位运算来替换

最小化语句数 多个变量声明
//4 个语句 —— 很浪费
var count = 5;
var color = "blue";
var values = [1,2,3];
var now = new Date()
//改进
//一个语句
var count = 5,
  color = "blue",
  values = [1,2,3],
  now = new Date()
插入迭代值
var name = values[i];
i++;
//改进
var name = values[i++];
使用数组和对象字面量
//用 4 个语句创建和初始化数组——浪费
var values = new Array();
values[0] = 123;
values[1] = 456;
values[2] = 789;
//用 4 个语句创建和初始化对象——浪费
var person = new Object();
person.name = "Nicholas";
person.age = 29;
person.sayName = function(){
alert(this.name);
};
//改进
//只用一条语句创建和初始化数组
var values = [123, 456, 789];
//只用一条语句创建和初始化对象
var person = {
name : "Nicholas",
age : 29,
sayName : function(){
  alert(this.name);
}
};
优化DOM交互 最小化现场更新
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);
使用innerHTML
var list = document.getElementById("myList"),
  html = "",
  i;
for (i=0; i < 10; i++) {
html += "
  • Item " + i + "
  • "; } list.innerHTML = html;
    使用事件代理 HTMLCollection
    var images = document.getElementsByTagName("img"),
      image,
      i, len;
    for (i=0, len=images.length; i < len; i++){
    image = images[i];
    //处理
    }
    部署 构建过程

    写的代码不应该原封不动地放入浏览器中

    知识产权问题 —— 如果把带有完整注释的代码放到线上,那别人就更容易知道你的意图,对它再利用,并且可能找到安全漏洞。

    文件大小 —— 书写代码要保证容易阅读,才能更好地维护,但是这对于性能是不利的。浏览器并不能从额外的空白字符或者是冗长的函数名和变量名中获得什么好处。

    代码组织 —— 组织代码要考虑到可维护性并不一定是传送给浏览器的最好方式。

    验证

    JSLint可以查找JavaScript代码中语法错误以及常见的编码错误,可以发掘潜在问题

    eval() 的使用;

    未声明变量的使用;

    遗漏的分号;

    不恰当的换行;

    错误的逗号使用;

    语句周围遗漏的括号;

    switch 分支语句中遗漏的 break ;

    重复声明的变量;

    with 的使用;

    错误使用的等号(替代了双等号或三等号);

    无法到达的代码。

    压缩 文件压缩

    删除额外的空白(包括换行);

    删除所有注释;

    缩短变量名。

    HTTP压缩

    对于 Apache Web服务器,有两个模块可以进行 HTTP压缩: mod_gzip (Apache1.3.x)和 mod_deflate(Apache 2.0.x)。对于 mod_gzip ,可以给 httpd.conf 文件或者是 .htacces s文件添加以下代码启用对JavaScript的自动压缩:

    告诉 mod_zip 要包含任何以.js 结尾的文件
    mod_gzip_item_include file .js$

    文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

    转载请注明本文地址:https://www.ucloud.cn/yun/98226.html

    相关文章

    • 高程3总结#4变量、作用域和内存问题

      摘要:当代码在一个环境中执行时,会创建变量对象的一个作用域链。作用域链的用途,是保证对执行环境有权访问的所有变量和函数的有序访问。这样,一直延续到全局执行环境全局执行环境的变量对象始终都是作用域链中的最后一个对象。 变量、作用域和内存问题 基本类型和引用类型的值 基本类型值指的是简单的数据段,而引用类型值值那些可能由多个值构成的对象。 定义基本类型值的引用和引用类型值的方法是类似的,创建...

      xumenger 评论0 收藏0
    • JS学习笔记(24)(最佳实践

      摘要:大多数情况下,可以是同局部变量完成相同的事情而不引入新的作用域。选择正确的方法避免不必要的属性查找一旦多次用到属性对象,应该将其存储在局部变量中。尽可能多的使用局部变量将属性查找替换为值查找。 1、可维护性 1.1 可维护代码特征 1. 可理解性 2. 直观性 3. 可适应性 4. 可扩展性 5. 可调试性 1.2 代码约定 1、可读性(代码缩进和代码注释) 2、变量和函数命名 变量...

      cnTomato 评论0 收藏0
    • 高程3总结#8BOM

      摘要:对象的核心对象是,它表示浏览器的一个实例。而和则表示该容器中页面视图区的大小。在中,与返回相同的值,即视口大小而非浏览器窗口大小。第三个参数是一个逗号分隔的设置字符串,表示在新窗口中都显示哪些特性。这应该是用户打开窗口后的第一个页面 BOM window对象 BOM的核心对象是window,它表示浏览器的一个实例。在浏览器中,window对象有双重角色,它既是通过JavaScript访...

      MASAILA 评论0 收藏0
    • 高程3总结#7函数表达式

      摘要:匿名函数可以用来模仿块级作用域来避免这个问题这里是块级作用域代码定义并立即调用了一个匿名函数,将函数声明包含在一对圆括号中,表示它实际上是一个函数表达式,而紧随其后的另一对圆括号会立即调用这个函数。 函数表达式 递归 递归函数是在一个函数通过名字调用自身的情况下构成的 function factrial(num){ if(num

      sevi_stuo 评论0 收藏0
    • 高程3总结#1JavaScript简介

      摘要:简介简史诞生于年,当时主要负责表单的输入验证。实现一个完整的由三部分组成核心文档对象模型浏览器对象模型就是对实现该标准规定的各个方面内容的语言的描述。把整个页面映射为一个多层节点结构。由万维网联盟规划。主要目标是映射文档的结构。 JavaScript简介 JavaScript简史 JavaScript诞生于1995年,当时主要负责表单的输入验证。 如果没有表单验证的功能,填入信息之...

      betacat 评论0 收藏0

    发表评论

    0条评论

    zhiwei

    |高级讲师

    TA的文章

    阅读更多
    最新活动
    阅读需要支付1元查看
    <