JavaScript高级程序设计(4)
第28章 最佳实践
### 28.1 可维护性 842 ##### 28.1.1 什么是可维护的代码 - > - 容易理解:无须求助原始开发者,任何人一看代码就知道它是干什么的,以及它是怎么实现的。 > - 符合常识:代码中的一切都显得顺理成章,无论操作有多么复杂。 > - 容易适配:即使数据发生变化也不用完全重写。 > - 容易扩展:代码架构经过认真设计,支持未来扩展核心功能。 > - 容易调试:出问题时,代码可以给出明确的信息,通过它能直接定位问题。 ##### 28.1.2 编码规范 - > - 可读性 > > - 函数和方法。每个函数和方法都应该有注释来描述其用途,以及完成任务所用的算法。 > - 大型代码块。多行代码但用于完成单一任务的,应该在前面给出注释,把要完成的任务写清楚。 > - 复杂的算法。如果使用了独特的方法解决问题,要通过注释解释明白。 > - 使用黑科技。由于浏览器之间的差异,JavaScript 代码中通常包含一些黑科技。不要假设其他人一看就能明白某个黑科技,如果某个浏览器不能使用正常方式达到目的,那要在注释里把黑科技的用途写出来。 > > - 变量和函数命名 > > - 变量名应该是名词,例如 car 或 person。 > - 函数名应该以动词开始,例如 getName()。返回布尔值的函数通常以 is 开头,比如 isEnabled()。 > - 对变量和函数都使用符合逻辑的名称,不用担心长度。长名字的问题可以通过后处理和压缩解决。 > - 变量、函数和方法应该以小写字母开头,使用驼峰大小写(camelCase)形式,常量值应该全部大写并以下划线相接,比如 REQUEST_TIMEOUT。 > - 名称要尽量用描述性和直观的词汇,但不要过于冗长。 > > - 变量类型透明化 > > ```javascript > //第一种标明变量类型的方式是通过初始化。 > let found = false; // 布尔值 > let count = -1; // 数值 > let name = ""; // 字符串 > let person = null; // 对象 > > //使用匈牙利表示法标明数据类型 > let bFound; // 布尔值 > let iCount; // 整数 > let sName; // 字符串 > let oPerson; // 对象 > > //使用类型注释表明数据类型 > let found /*:Boolean*/ = false; > let count /*:int*/ = 10; > let name /*:String*/ = "Nicholas"; > let person /*:Object*/ = null; > ``` ##### 28.1.3 松散耦合 - > 1. 解耦 HTML/JavaScript > > > 把 JavaScript 直接嵌入在 HTML 中,要么使用包含嵌入代码的<script>元素,要么使用 HTML 属性添加事件处理程序,这些都会造成紧密耦合。理想情况下,HTML 和 JavaScript 应该完全分开,通过外部文件引入 JavaScript,然后使用 > > > > DOM 添加行为。 > > > > 一般来说,应该避免在 JavaScript 中创建大量 HTML。HTML 渲染应该尽可能与 JavaScript 分开。 > > 2. 解耦 CSS/JavaScript > > 3. 解耦应用程序逻辑/事件处理程序 ##### 28.1.4 编码惯例 - > 1. 尊重对象所有权 > > 2. 不声明全局变量 > > 3. 不要比较 **null** > > 4. 使用常量 ### 28.2 性能 851 ##### 28.2.1 作用域意识 - > 1. 避免全局查找 > > ```javascript > //改进代码性能非常重要的一件事,可能就是要提防全局查询。全局变量和函数相比于局部值始终是最费时间的,因为需要经历作用域链查找。 > function updateUI() { > let imgs = document.getElementsByTagName("img"); > for (let i = 0, len = imgs.length; i < len; i++) { > imgs[i].title = '${document.title} image ${i}'; > } > let msg = document.getElementById("msg"); > msg.innerHTML = "Update complete."; > } > //这个函数三个地方引用了全局 document 对象。如果页面的图片非常多,那么 for 循环中就需要引用 document 几十甚至上百次,每次都要遍历一次作用域链。通过在局部作用域中保存 document 对象的引用,能够明显提升这个函数的性能,因为只需要作用域链查找。 > function updateUI() { > let doc = document; > let imgs = doc.getElementsByTagName("img"); > for (let i = 0, len = imgs.length; i < len; i++) { > imgs[i].title = '${doc.title} image ${i}'; > } > let msg = doc.getElementById("msg"); > msg.innerHTML = "Update complete."; > } > ``` > > 2. 用 **with** 语句 > > > 在性能很重要的代码中,应避免使用 with 语句。与函数类似,with 语句会创建自己的作用域,因此也会加长其中代码的作用域链。在 with 语句中执行的代码一定比在它外部执行的代码慢,因为作用域链查找时多一步。 ##### 28.2.2 选择正确的方法 - > 1. 避免不必要的属性查找 > > > 使用变量和数组复杂度是 *O*(1), 相比访问对象属性效率更高,访问对象属性的算法复杂度是 *O*(*n*)。 > > > > 通常,只要能够降低算法复杂度,就应该尽量通过在局部变量中保存值来替代属性查找。另外,如果实现某个需求既可以使用数组的数值索引,又可以使用命名属性(比如 NodeList 对象),那就都应该使用数值索引。 > > 2. 优化循环 > > > (1) 简化终止条件。因为每次循环都会计算终止条件,所以它应该尽可能地快。这意味着要避免属性查找或其他 *O*(*n*)操作。 > > > > (2) 简化循环体。循环体是最花时间的部分,因此要尽可能优化。要确保其中不包含可以轻松转移到循环外部的密集计算。 > > > > (3) 使用后测试循环。最常见的循环就是 for 和 while 循环,这两种循环都属于先测试循环。do-while就是后测试循环,避免了对终止条件初始评估 ,因此应该会更快。 > > 3. 展开循环 > > > 展开循环对于大型数据集可以节省很多时间,但对于小型数据集来说,则可能不值得。因为实现同样的任务需要多写很多代码,所以如果处理的数据量不大,那么显然没有必要。 > > 4. 避免重复解释 > > > ```javascript > > // 对代码求值:不要 > > eval("console.log('Hello world!')"); > > // 创建新函数:不要 > > let sayHi = new Function("console.log('Hello world!')"); > > // 设置超时函数:不要 > > setTimeout("console.log('Hello world!')", 500); > > > > // 直接写出来 > > console.log('Hello world!'); > > // 创建新函数:直接写出来 > > let sayHi = function() { > > console.log('Hello world!'); > > }; > > // 设置超时函数:直接写出来 > > setTimeout(function() { > > console.log('Hello world!'); > > }, 500); > > ``` > > 5. 其他性能优化注意事项 > > > 原生方法很快。 > > > > **switch** 语句很快。 > > > > 位操作很快。 ##### 28.2.3 语句最少化 - > 1. 多个变量声明, 一条语句更好 > > 2. 插入迭代性值 > 3. 使用数组和对象字面量 ##### 28.2.4 优化 DOM 交互 - > 1. 实时更新最小化 > 2. 使用 **innerHTML** > 3. 使用事件委托 > 4. 注意 **HTMLCollection** ### 28.3 部署 861 ##### 28.3.1 构建流程 - > 1. 文件结构 > 2. 任务运行器 > 3. 摇树优化 > 4. 模块打包器 ##### 28.3.2 验证 - > 有一些工具可以帮我们发现 JavaScript 代码中潜在的问题,最流行的是 Douglas Crockford 的 JSLint 和 ESLint。下面是它们会报告的一些问题: > > - 使用 eval(); > - 使用未声明的变量; > - 遗漏了分号; > - 不适当地换行; > - 不正确地使用逗号; > - 遗漏了包含语句的括号; > - 遗漏了 switch 分支中的 break; > - 重复声明变量; > - 使用了 with; > - 错误地使用等号(应该是两个或三个等号); > - 执行不到的代码。 ##### 28.3.3 压缩 - > 1. 代码压缩 > 2. JavaScript 编译 > 3. JavaScript 转译 > 4. HTTP 压缩
顶部
收展
底部
[TOC]
目录
第1章 JavaScript简介
第2章 在 HTML中使用JavaScript
第3章 语言基础(1)语法变量
第3章 语言基础(2)数据类型
第3章 语言基础(3)操作符
第3章 语言基础(4)语句
第4章 变量、作用域与内存
第5章 基本引用类型
第6章 集合引用类型
第7章 迭代器与生成器
第8 章对象、类与面向对象编程
第9章 代理与反射
第10章 函数
第11章 期约与异步函数
第12章 BOM
第13章 客户端检测
第14章 DOM
第15章 DOM 扩展
第16章 DOM2 和 DOM3
第17章 事件
第18章 动画与 Canvas 图形
第19章 表单脚本
第20章 JavaScript API
第21章 错误处理与调试
第22章 处理 XML
第23章 JSON
第24章 网络请求与远程资源
第25章 客户端存储
第26章 模块
第27章 工作者线程
第28章 最佳实践
相关推荐
WebSocket