如何让你的代码变得更优雅?这些代码规范和技巧必须知道(进阶必备,建议收藏)下

简介: 笔记

5. 函数优化


5.1 提炼函数


在javascript开发中,大部分时间都在与函数打交道,所以希望这些函数有着良好的命名,函数体内包含的逻辑清晰明了。

如果一个函数过长,不得不加上若干注释才能让这个函数显得易读一些,那这些函数就很有必要进行重构

如果在函数中有一段代码可以被独立出来,那最好把这些代码放进另外一个独立的函数中,这是一种很常见的优化工作。

项目越大,必须拆分得越细,好维护(函数也是如此)

千万不要一个函数从奶奶家写到外婆家去了

这样做的好处主要有以下几点:


避免出现超大函数

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

独立出来的函数更容易被覆写

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

比如在一个负责取得用户信息的函数里面,还需要打印跟用户信息有关的信息,那么打印的语句就可以被封装在一个独立的函数里:

let getUserInfo = function(){
    ajax( 'http:// xxx.com/userInfo', function( data ){
        console.log( 'userId: ' + data.userId );
        console.log( 'userName: ' + data.userName );
        console.log( 'nickName: ' + data.nickName );
    });
};
//改成:
let getUserInfo = function(){
    ajax( 'http:// xxx.com/userInfo', function( data ){
        printDetails( data );
    });
};
let printDetails = function( data ){
    console.log( 'userId: ' + data.userId );
    console.log( 'userName: ' + data.userName );
    console.log( 'nickName: ' + data.nickName );
};

5.2 尽量减少参数


调用一个函数时需要传入多个参数,那这个函数是让人望而生畏的(甚至调用起来还会骂娘~)

必须搞清楚这些参数代表的含义,必须小心翼翼地把它们按照顺序传入该函数。

在实际开发中,向函数传递参数不可避免,但应该尽量减少函数接收的参数数量

比如我们需要封装一个CSS操作库:


第一版的代码

function cssTransform(ele, attr, val){
    // ele 要操作的元素
    // attr 运动属性 缩放,旋转
    // val 具体值
    if(!ele.transform){
        ele.transform = {};
    }
    if(typeof val === "undefined"){
        // 取值阶段
        // 取不到 设置默认值
        if(typeof ele.transform[attr] === "undefined"){
            switch(attr){
                case "scale":
                case "scaleX":    
                case "scaleY":    
                case "scaleZ":
                    // attr是scale 默认值是1 其它都是0
                    ele.transform[attr] = 1;
                    break;   
                default:
                    ele.transform[attr] = 0;     
            }
        }
        // 取值完毕 返回该值
        return ele.transform[attr];
    }else{
        // 赋值阶段
        ele.transform[attr] = val;      // 设置属性 方便取值
        let transformVal = "";
        for(var s in ele.transform){
            switch(s){
                case "scale":
                case "scaleX":    
                case "scaleY":    
                case "scaleZ":
                    transformVal += " " + s + "("+(ele.transform[s])+")";
                    break;
                case "rotate":
                case "rotateX":    
                case "rotateY": 
                case "rotateZ": 
                case "skewX":
                case "skewY":    
                    transformVal += " " + s + "("+(ele.transform[s])+"deg)";
                    break;
                default:
                    transformVal +=  " " + s + "("+(ele.transform[s])+"px)";    
            }
            ele.style.WebkitTransform = ele.style.transform = transformVal;
        }
    }
}
  • 我们需要传入三个参数,这就导致了传参的复杂性
  • 可以将它绑定到HTML元素上,减少传参
HTMLElement.prototype.cssTransform = function (prop, value){
    var transform,
        transformValue = "";
        if(this.transform === undefined) {
            this.transform = transform = Object.create(null);
        }
        if(value !== undefined){
            // 赋值阶段
            this.transform[prop] = value;
            transform = this.transform;
            for(var name in transform){
                switch(name){
                    case "scale":
                    case "scaleX":    
                    case "scaleY":    
                    case "scaleZ":
                        transformValue += " " + name + "("+ transform[name]+")";
                        break;
                    case "rotate":
                    case "rotateX":    
                    case "rotateY": 
                    case "rotateZ": 
                    case "skewX":
                    case "skewY":    
                        transformValue += " " + name + "("+ transform[name] + "deg)";
                        break;
                    default:
                        transformValue +=  " " + name + "("+ transform[name] + "px)";    
                }
                this.style.WebkitTransform = this.style.transform = transformValue;
            }
        }else{
            // 取值
            return this.transform[prop];
        }
}
  • 现在就只需要两个参数了
  • 核心代码没变,事件直接绑定在元素上,每一个html都拥有这个原型方法
  • 调用更加方便,传参更加简单60.png


6.条件优化


6.1 合并条件判断


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

假如有一个分页函数paging(),该函数接收一个参数currPage,currPage表示即将跳转的页码。

在跳转之前,为防止currPage传入过小或者过大的数字,要手动对它的值进行修正,详见如下代码

let paging = function( currPage ){
    if ( currPage == 0 ){
        currPage = 0;
        jump( currPage ); // 跳转
    }else if ( currPage == totalPage ){
        currPage = totalPage;
        jump( currPage ); // 跳转
    }else{
        jump( currPage ); // 跳转
    }
};
  • 可以看到,负责跳转的代码jump(currPage)在每个条件分支内都出现了,所以完全可以把这句代码独立出来
let paging = function( currPage ){
    if ( currPage == 0 ){
        currPage = 0;
    }else if ( currPage == totalPage ){
        currPage = totalPage;
    }
    jump( currPage ); // 把jump 函数独立出来
};

6.2 条件语句过多,提炼成函数

  • 在程序设计中,复杂的条件分支语句是导致程序难以阅读和理解的重要原因,而且容易导致一个庞大的函数
  • 假设现在有一个需求是编写一个计算商品价格的 getPrice(),商品的计算只有一个规则:如果当前正处于夏季,那么所有冬装将以5折出售
let getPrice = function( price ){
    let date = new Date();
    if ( date.getMonth() > 6 &&  date.getMonth() < 10 ){ // 冬天
        return price * 0.5;
    }
    return price;
};
  • 判断是否处于夏季
if ( date.getMonth() > 6 &&  date.getMonth() < 10 )

这句代码要表达的意思很简单,就是判断当前是否正处于夏天(7 - 9月)。

尽管这句代码很短小,但代码表达的意图和代码自身还存在一些距离,阅读代码的人必须要多花一些精力才能明白它传达的意图。

其实可以把这句代码提炼成一个单独的函数,既能更准确地表达代码的意思,函数名本身又能起到注释的作用

let isSummer = function(){
    let date = new Date();
    return date.getMonth() > 6 && date.getMonth() < 10;
};
let getPrice = function( price ){
    if ( isSummer() ){ // 夏天
        return price * 0.5;
    }
    return price;
};

90.png

7. 循环优化



7.1 高效循环

  • 在函数体内,如果有些代码实际上负责的是一些重复性的工作
  • 合理利用循环不仅可以完成同样的功能,还可以使代码量更少
  • 以for循环为例,最常规写法
for (let i = 0; i < arr.length; i++) {
    // do something...
}
  • 大多数人都是这种写法,这种写法的缺点在于,每次循环都要去读取一次数组的长度,性能上并不友好
  • 变量情况的优化写法
for (let i = 0, j = arr.length; i < j; i++) {
    // do something...
}
  • 将长度进行存储,之后循环无需再去读取长度
  • 这只是上面写法的一种变体,另一种写法而已,谈不上优化。因为无块级作用域,所以和上面的效果是一样的
  • 优化版
for (let i = arr.length - 1; i >= 0; i--) {
    // do something...
}

推荐的写法,它在第上面的基础上节约了一个变量100.png

8. 如何提升js性能


8.1 性能至关重要


性能是创建网页或应用程序时最重要的一个方面,特别是加载性能,如果让用户等久了,别人干脆不等了,会造成用户流失

用户对于应用的体验普遍要求提高了(现在来说,2s 内打不开网页的都是不合格的网站)

应用的性能瓶颈,依然是在js上

8.2 优化方向


1. 删除未使用的js代码


未使用的功能性代码以及与之相关的代码(它一样的会编译,运行)

多余的依赖(不需要的及时删除)

2. 数组与对象避免使用构造函数


构造函数是啥?

new Array(), new Object()等

demoObj = () => {
    let obj = new Object()
    obj.name = '朱小明'
    obj.age = 10
    obj.sex = '男'
    return obj
}
  • 推荐写法
demoObj = () => {
    let obj = {
        name: '朱小明',
        age: 10,
        sex: '男'
    }
    return obj
}

3. 避免全局变量


js 的垃圾回收机制是不会销毁全局变量的

所以它会常驻内存

4. 合理使用闭包


闭包可以提供面向对象编程的便利,有私有属性和方法

由于闭包会携带包含它的函数的作用域,因此会比其他函数占用更多的内存

过度使用闭包可能会导致内存占用过多的问题。

所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露

5. 减少循环中的活动


循环本来就耗性能(特别是数据量大的)

方法尽量不要放在循环中执行(执行多次,特别是逻辑复杂的方法,后果可想而知)



目录
相关文章
|
3天前
|
算法 测试技术 持续交付
Python面试:代码审查与重构相关问题
【4月更文挑战第19天】本文讨论了Python面试中常被问到的代码审查和重构主题。代码审查涉及理解审查目的、使用工具(如GitHub PR)和遵循PEP 8规范。要避免仅关注表面错误,忽视可读性,同时提供具体反馈。重构时,要理解其原则,熟悉各种手法,并借助单元测试和持续集成保证质量。遵循小步快跑原则,评估技术债务,记录重构步骤。文中通过示例展示了如何将原始代码重构为更清晰的抽象类结构,以提高代码组织性。掌握这些技能对于面试成功至关重要。
10 0
|
1月前
|
Java
Java开发规范(简洁明了)
Java开发规范(简洁明了)
|
5月前
|
算法 编译器 程序员
代码规范:其它编程经验
【建议 11-3-4】当心数据类型转换发生错误。尽量使用显式的数据类型转换(让人们知道发生了什么事),避免让编译器轻悄悄地进行隐式的数据类型转换。
34 0
|
5月前
|
安全 编译器 C语言
代码规范:C++函数的高级特性
一个好的编译器将会根据函数的定义体,自动地取消不值得的内联(这进一步说明了 inline 不应该出现在函数的声明中)。
39 0
|
9月前
|
缓存 算法 安全
程序员写代码为什么要阅读源码?
阅读一篇技术文章,畅聊一个技术话题。本期文章推荐的是《Node 中的 AsyncLocalStorage 的前世今生和未来》,一起来聊聊开发者阅读源码的这件事。阅读源码的过程实质上是对软件构建技术和架构深度的一种持续学习和理解。阅读源码可以揭示代码的内在逻辑,可以对技术深度的理解,也能提高对技术的理解程度。然而,仅仅阅读源码并不能代替实践操作,因为通过实践,可以更加全面的理解代码的深度和进展。
101 1
|
11月前
|
移动开发 前端开发 JavaScript
前端编码规范
前端编码规范
456 0
|
IDE 编译器 程序员
C++ 最佳实践 | 2. 代码风格
C++ 最佳实践 | 2. 代码风格
139 0
|
JavaScript 前端开发 算法
BetterScroll源码阅读顺便学习TypeScript
BetterScroll源码阅读顺便学习TypeScript
135 0
BetterScroll源码阅读顺便学习TypeScript
|
移动开发 前端开发 JavaScript