资讯专栏INFORMATION COLUMN

代码书写优化(javaScript设计模式与开发实践--读书笔记)

geekidentity / 1571人阅读

摘要:独立出来的函数更加容易被改写,减少维护成本。例如一个分页函数,函数接受一个表示挑战页码,在跳转前需要判断是否在有效的取值范围。面向对象设计鼓励将行为分布在合理数量的更小对象之中。

这是《 javaScript设计模式与开发实践 》一书的最后一章"代码重构"。

以下的一些方法不是必须严格遵守的标准,选择实践哪些,以及如何实现这都需根据情况而定(是不是有充足时间)

提炼函数

如果在函数中有一段代码可以独立出来,那么最好把这些代码放进另外一个独立的函数当中去。好处有:

避免出现超大型函数。

独立出来的函数有助于代码复用。

独立出来的函数更加容易被改写,减少维护成本。

独立出来的函数如果有一个良好的命名,本身就起到了注释的作用。

例如一个获取用户信息的函数,我们还需要打印用户信息,这种情况下就可以独立出打印信息的代码。

</>复制代码

  1. var getUserInfo = function() {
  2. ajax("http://xxx/userInfo", function(data) {
  3. console.log("userId: " + data.userId);
  4. console.log("userName: " + data.userName);
  5. console.log("nickName: " + data.nickName);
  6. });
  7. };

改写:

</>复制代码

  1. var getUserInfo = function() {
  2. ajax("http://xxx/userInfo", function(data) {
  3. printUserInfo(data);
  4. });
  5. };
  6. var printUserInfo = function(data) {
  7. console.log("userId: " + data.userId);
  8. console.log("userName: " + data.userName);
  9. console.log("nickName: " + data.nickName);
  10. };
合并重复代码片段

如果一个函数内有一些条件语句,而条件语句内散布了一些重复代码,就有必要进行合并去重工作。

例如一个分页函数paging,函数接受一个currpage表示挑战页码,在跳转前需要判断currpage是否在有效的取值范围。

</>复制代码

  1. var paging = function(currpage) {
  2. if (currpage <= 0) {
  3. currpage = 0;
  4. jump(currpage); // 跳转
  5. } else if (currpage >= totalPage) { // 总页数totalPage
  6. currpage = totalPage;
  7. jump(currpage); // 跳转
  8. } else {
  9. jump(currpage); // 跳转
  10. }
  11. }

负责跳转的jump(currpage)在每个条件分支都出现了,所以完全把这句代码独立出来:

</>复制代码

  1. var paging = function(currpage) {
  2. if (currpage <= 0) {
  3. currpage = 0;
  4. } else if (currpage >= totalPage) { // 总页数totalPage
  5. currpage = totalPage;
  6. }
  7. jump(currpage); // 跳转
  8. }
把条件语句提炼成函数

在程序设计中,复杂的条件语句是导致程序难以阅读和理解的重要原因,而且容易增大函数代码量。例如以一个计算商品价格的getPrice函数,商品计算有个规则,夏天商品以8折出售。

</>复制代码

  1. var getPrice = function(price) {
  2. var date = new Date;
  3. if (date.getMonth() >= 6 && date.getMonth() <= 9 ) { // 处于夏天
  4. return price * 0.8
  5. }
  6. return price;
  7. }

其中的条件语句if (date.getMonth() >= 6 && date.getMonth() <= 9 )
如果改写提炼成一个独立的函数,既能更准确的表达代码的意思,函数名又能起到注释作用。

</>复制代码

  1. var isSummer = function() {
  2. var dateMonth = (new Date).getMonth();
  3. return dateMonth >= 6 && dateMonth <= 9 ;
  4. };
  5. var getPrice = function(price) {
  6. var date = new Date;
  7. if ( isSummer() ) { // 处于夏天
  8. return price * 0.8
  9. }
  10. return price;
  11. };
合理使用循环

在函数体内,如果有些代码是负责一些重复性的工作,那么合理使用循环不仅可以完成同样的功能,还可以使代码量更少,有一段创建XHR对象的代码,为了简化代码,只检测IE9已下的浏览器。

</>复制代码

  1. var creatXHR = function() {
  2. var xhr;
  3. try{
  4. xhr = new ActiveXObject("MSXML2.XMLHTTP.6.0");
  5. } catch(e) {
  6. try{
  7. xhr = new ActiveXObject("MSXML2.XMLHTTP.3.0");
  8. } catch(e) {
  9. xhr = new ActiveXObject("MSXML2.XMLHTTP");
  10. }
  11. }
  12. return xhr;
  13. };
  14. var xhr = creatXHR();

下面灵活的使用循环,可以得到上面代码一样的效果:

</>复制代码

  1. var creatXHR = function() {
  2. var versions = ["MSXML2.XMLHTTP.6.0", "MSXML2.XMLHTTP.3.0", "MSXML2.XMLHTTP"];
  3. for (var i = 0;i < versions.length; i++) {
  4. try{
  5. return new ActiveObject( version[i] );
  6. }catch(e) {
  7. }
  8. }
  9. };
  10. var xhr = creatXHR();
提前让函数退出嵌套条件分支

初学者可能有这样一个观念:”每个函数只能有一个入口和一个出口。”现代编程语言都会限制函数有一个入口。但是关于”函数只有一个出口”,往往有不一样的看法。
下面是一个遵守“函数只有一个出口”的代码。

</>复制代码

  1. var del = fucntion(obj) {
  2. var ret;
  3. if (!obj.isReadOnly) { // 不为只读才能删除
  4. if (obj.isFolder) { // 判断文件夹
  5. ret = deletFolder(obj);
  6. } else if (obj.isFile) { // 判断文件
  7. ret = deletFile(obj);
  8. }
  9. }
  10. return ret;
  11. }

嵌套的条件分支语句是代码维护者的噩梦,如果对函数的剩余部分不感兴趣,那就应该立即退出。
我们可以挑选一些条件分支,在进入这些条件分支后,就立即让函数退出。有一个常见的技巧。在面对一个嵌套的if分支时,我们可以把外层if表达式进行反转。例如:

</>复制代码

  1. var del = function(obj) {
  2. if (obj.isReadOnly) { // 反转表达式
  3. return;
  4. }
  5. if (obj.isFolder) {
  6. return deletFolder(obj);
  7. }
  8. if (obj.isFile) {
  9. return deletFile(obj);
  10. }
  11. }
传递对象参数代替过长的参数列表

函数可能接受多个参数,参数越多函数就越难理解和使用。

</>复制代码

  1. setUserInfo(1111, "sven", "hangzhou", "male", "137*****")
  2. // 可改写成
  3. setUserInfo({
  4. id: 1111,
  5. name: "sven",
  6. address: "hangzhou",
  7. sex: "male",
  8. mobile: "137*****"
  9. })

改写后可以不再关心参数的数量和顺序,一般参数控制在4个以内,超过4个就需要转化成对象形式。

合理使用链式调用

链式调用在调试的时候非常不方便,如果一条调用链中有错误出现,必须要把这条调用链拆开才能定位错误出现的地方。

如果该链条的结构稳定,后期不易发生修改,使用链式调用无可厚非,但是如果该链条容易发生变化,导致调试和维护困难,那么普通调用形式为佳。

分解大型类

如果一个类的方法足够复杂和庞大,那么它完全有必要作为一个多带带的类存在。面向对象设计鼓励将行为分布在合理数量的更小对象之中。

用return退出多重循环

在函数有两重循环语句时,我们往往需要在内层循环中判断,当达到临界条件时退出外层循环,有以下实现方式。

设置flag。

</>复制代码

  1. var func = function() {
  2. var flage = false;
  3. for (var i = 0; i < 10; i++) {
  4. for (var j = 0; j < 10; j++) {
  5. if (i * j > 30) {
  6. flag = true;
  7. break;
  8. }
  9. }
  10. if (flag === true) {
  11. break;
  12. }
  13. }
  14. }

设置循环标记

</>复制代码

  1. var func = function() {
  2. outerloop:
  3. for(var i = 0; i < 10; i++) {
  4. innerloop:
  5. for(var j = 0; j < 10; j++) {
  6. if (i * j >30) {
  7. break outerloop;
  8. }
  9. }
  10. }
  11. }

这两种做法都让人头晕目眩,更简单的做法是直接终止整个方法:

</>复制代码

  1. var func = function() {
  2. for (var i = 0; i < 10; i++) {
  3. for (var j = 0; j < 10; j++) {
  4. if (i * j > 30) {
  5. return;
  6. }
  7. }
  8. }
  9. }

return直接退出有一个问题,在循环之后如果还有代码就无法执行:

</>复制代码

  1. var func = function() {
  2. for (var i = 0; i < 10; i++) {
  3. for (var j = 0; j < 10; j++) {
  4. if (i * j > 30) {
  5. return;
  6. }
  7. }
  8. }
  9. console.log(i); // 无法执行
  10. }

我们可以把循环后需要的代码放到return后面,如果代码较多,可以提炼成一个多带带的函数。

</>复制代码

  1. var print = function(i) {
  2. console.log(i);
  3. };
  4. var func = function() {
  5. for (var i = 0; i < 10; i++) {
  6. for (var j = 0; j < 10; j++) {
  7. if (i * j > 30) {
  8. return print(i);
  9. }
  10. }
  11. }
  12. };

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

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

相关文章

  • 读书笔记-你不知道的JavaScript(上)

    摘要:比如程序会被分解为解析语法分析将词法单元流转换成一个由元素逐级嵌套所组成的代表了程序语法接口的书,又称抽象语法树。代码生成将抽象语法树转换为机器能够识别的指令。 showImg(https://segmentfault.com/img/remote/1460000009682106?w=640&h=280); 本文首发在我的个人博客:http://muyunyun.cn/ 《你不知道的...

    jzzlee 评论0 收藏0
  • 前端知识点整理

    摘要:难怪超过三分之一的开发人员工作需要一些知识。但是随着行业的饱和,初中级前端就业形势不容乐观。整个系列的文章大概有篇左右,从我是如何成为一个前端工程师,到各种前端框架的知识。 为什么 call 比 apply 快? 这是一个非常有意思的问题。 作者会在参数为3个(包含3)以内时,优先使用 call 方法进行事件的处理。而当参数过多(多余3个)时,才考虑使用 apply 方法。 这个的原因...

    Lowky 评论0 收藏0
  • 前端知识点整理

    摘要:难怪超过三分之一的开发人员工作需要一些知识。但是随着行业的饱和,初中级前端就业形势不容乐观。整个系列的文章大概有篇左右,从我是如何成为一个前端工程师,到各种前端框架的知识。 为什么 call 比 apply 快? 这是一个非常有意思的问题。 作者会在参数为3个(包含3)以内时,优先使用 call 方法进行事件的处理。而当参数过多(多余3个)时,才考虑使用 apply 方法。 这个的原因...

    snowLu 评论0 收藏0
  • 《高性能JavaScript读书笔记

    摘要:除此以外,让元素脱离文档流也是一个很好的方法。因为元素一旦脱离文档流,它对其他元素的影响几乎为零,性能的损耗就能够有效局限于一个较小的范围。讲完重排与重绘,往元素上绑定事件也是引起性能问题的元凶。高性能这本书非常精致,内容也非常丰富。 showImg(https://segmentfault.com/img/bVJgbt?w=600&h=784); 入手《高性能JavaScript》一...

    W_BinaryTree 评论0 收藏0
  • JavaScript 设计模式开发实践读书笔记

    摘要:设计模式与开发实践读书笔记最近利用碎片时间在上面阅读设计模式与开发实践读书这本书,刚开始阅读前两章内容,和大家分享下我觉得可以在项目中用的上的一些笔记。事件绑定暂时这么多,以后会不定期更新一些关于我读这本书的笔记内容 JavaScript 设计模式与开发实践读书笔记 最近利用碎片时间在 Kindle 上面阅读《JavaScript 设计模式与开发实践读书》这本书,刚开始阅读前两章内容,...

    FingerLiu 评论0 收藏0

发表评论

0条评论

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