前端进阶-个人笔记-如何写出更好风格的JS代码(JS 代码优化建议)
1. 按强类型风格写代码
JS 是弱类型的,但是写代码的时候不能太随意,写得太随意也体现了编码风格不好。下面分点说明:
(1)定义变量的时候要指明类型,告诉 JS 解释器这个变量是什么数据类型的,而不要让解释器去猜,例如不好的写法:
var num,str,obj;
声明了三个变量,但其实没什么用,因为解释器不知道它们是什么类型的,好的写法应该是这样的:
var num = 0,str = '',obj = null;
定义变量的时候就给他一个默认值,这样不仅方便了解释器,也方便了阅读代码的人,他会在心里有数——知道这些变量可能会当作什么用。
(2)不要随意地改变变量的类型,例如下面代码:
var num = 5;
num = "-" + num;
第 1 行它是一个整型,第 2 行它变成了一个字符串。因为 JS 最终都会被解释成汇编的语言,汇编语言变量的类型肯定是要确定的,你把一个整型的改成了字符串,那解释器就得做一些额外的处理。并且这种编码风格是不提倡的,有一个变量第 1 行是一个整型,第 10 行变成了一个字符串,第 20 行又变成了一个 object,这样就让阅读代码的人比较困惑,上面明明是一个整数,怎么突然又变成一个字符串了。好的写法应该是再定义一个字符串的变量:
var num = 5;
var sign = "-" + num;
(3)函数的返回类型应该是要确定的,例如下面不确定的写法:
function getPrice(count){if(count < 0) return"";elsereturn count * 100;
}
getPrice 这个函数有可能返回一个整数,也有可能返回一个空的字符串。这样写也不太好,虽然它是符合 JS 语法的,但这种编码风格是不好的。使用你这个函数的人会有点无所适从,不敢直接进行加减乘除,因为如果返回字符串进行运算的话值就是 NaN 了。函数的返回类型应该是要确定的,如下面是返回整型:
function getPrice(count){if(count < 0) return-1;elsereturn count * 100;
}
然后告诉使用者,如果返回-1 就表示不合法。如果类型确定,解释器也不用去做一些额外的工作,可以加快运行速度。
2. 减少作用域查找
(1)不要让代码暴露在全局作用域(运行在整个script标签里)下
例如以下运行在全局作用域的代码:
<script>var map = document.querySelector("#my-map");map.style.height = "600px";
</script>
有时候你需要在页面直接写一个 script,要注意在一个 script 标签里面,代码的上下文都是全局作用域的,由于全局作用域比较复杂,查找比较慢。例如上面的 map 变量,第二行在使用的时候,需要在全局作用域查找一下这个变量,假设 map 是在一个循环里面使用,那可能就会有效率问题了。所以应该要把它搞成一个局部的作用域:
<script>
!function(){var map = document.querySelector("#my-map");map.style.height = "600px";
}()
</script>
上面用了一个 function 制造一个局部作用域,也可以用 ES6 的块级作用域。由于 map 这个变量直接在当前的局部作用域命中了,所以就不用再往上一级的作用域(这里是全局作用域)查找了,而局部作用域的查找是很快的。同时直接在全局作用域定义变量,会污染 window 对象。
(2)不要滥用闭包
闭包的作用在于可以让子级作用域使用它父级作用域的变量,同时这些变量在不同的闭包是不可见的。这样就导致了在查找某个变量的时候,如果当前作用域找不到,就得往它的父级作用域查找,一级一级地往上直到找到了,或者到了全局作用域还没找到。因此如果闭包嵌套得越深,那么变量查找的时间就越长。如下:
function getResult(count){count++;function process(){var factor = 2;return count * factor - 5;}return process();
}
上面的代码定义了一个 process 函数,在这个函数里面 count 变量的查找时间要高于局部的 factor 变量。其实这里不太适合用闭包,可以直接把 count 传给 process:
function getResult(count){count++;function process(count){var factor = 2;return count * factor - 5;}return process(count);
}
这样 count 的查找时间就和 factor 一样,都是在当前作用域直接命中。这个就启示我们如果某个全局变量需要频繁地被使用的时候,可以用一个局部变量缓存一下,如下:
var url = "";
if(window.location.protocal === "https:"){url = "wss://xxx.com" + window.location.pathname + window.location.search;
}
频繁地使用了 window.location 对象,所以可以先把它缓存一下:
var url = "";
var location = window.location;
if(location.protocal === "https:"){url = "wss://xxx.com" + location.pathname + location.search;
}
搞成了一个局变变量,这样查找就会明显快于全局的查找,代码也可以写少一点。
3. 避免==的使用
这里你可能会有疑问了,有些人喜欢用==,有些人喜欢用===,大家的风格不一样,你为什么要强制别人用=呢?习惯用的人,不能仅仅是因为比=少敲了一次键盘。为什么不提倡用==呢?
(1)如果你确定了变量的类型,那么就没必要使用==了,如下:
if(typeof num != "undefined"){}
var num = parseInt(value);
if(num == 10){}
上面的两个例子都是确定类型的,一个是字符串,一个是整数。就没必要使用了,直接用=就可以了。
(2)如果类型不确定,那么应该手动做一下类型转换,而不是让别人或者以后的你去猜这里面有类型转换,如下:
var totalPage = "5";
if(parseInt(totalPage) === 1){}
(3)使用==在 JSLint 检查的时候是不通过的:
if(a == b){}
如下 JSLint 的输出:
Expected ‘=’ and instead saw ‘’.
if(a == b){
(4)并且使用==可能会出现一些奇怪的现象,这些奇怪的现象可能会给代码埋入隐患:
null == undefined//true
'' == '0'//false
0 == ''//true
0 == '0'//true
' ' == 0//true
newString("abc") == "abc"//true
newBoolean(true) == true//true
true == 1//true
上面的比较在用===的时候都是 false,这样才是比较合理的。例如第一点 null 居然会等于 undefined,就特别地奇怪,因为 null 和 undefined 是两个毫无关系的值,null 应该是作为初始化空值使用,而 undefined 是用于检验某个变量是否未定义。这和第 1 点介绍强类型的思想是相通的。
4. 合并表达式
如果用 1 句代码就可以实现 5 句代码的功能,那往往 1 句代码的执行效率会比较高,并且可读性可能会更好
(1)用三目运算符取代简单的 if-else
如上面的 getPrice 函数:
function getPrice(count){if(count < 0) return-1;elsereturn count * 100;
}
可以改成:
function getPrice(count){return count < 0 ? return-1 : count * 100;
}
这个比写一个 if-else 看起来清爽多了。当然,如果你写了 if-else,压缩工具也会帮你把它改三目运算符的形式:
function getPrice(e){return0>e?-1:100*e}
(2)连等
连等是利用赋值运算表达式会返回所赋的值,并且执行顺序是从右到左的,如下:
overtime = favhouse = listingDetail = {...}
有时候你会看到有人这样写:
var age = 0;
if((age = +form.age.value) >= 18){console.log("你是成年人");
} else {consoe.log("小朋友,你还有" + (18 - age) + "就成年了");
}
也是利用了赋值表达式会返回一个值,在 if 里面赋值的同时用它的返回值做判断,然后 else 里面就已经有值了。上面的+号把字符串转成了整数。
(3)自增
利用自增也可以简化代码。如下,每发出一条消息,localMsgId 就自增 1:
chatService.sendMessage(localMsgId++, msgContent);
5. 减少魔数
例如,在某个文件的第 800 行,冒出来了一句:
dialogHandler.showQuestionNaire("seller", "sell", 5, true);
就会让人很困惑了,上面的四个常量分别代表什么呢,如果我不去查一个那个函数的变量说明就不能够很快地意会到这些常量分别有什么用。这些意义不明的常量就叫“魔数”。所以最好还是给这些常量取一个名字,特别是在一些比较关键的地方。例如上面的代码可改成:
var naireType = "seller",dialogType = "sell",questionsCount = 5,reloadWindow = true;naireHandler.showNaire(naireType, dialogType, questionsCount, reloadWindow);
这样意义就很明显了。
6. 使用 ES6 简化代码
ES6 已经发展很多年了,兼容性也已经很好了。恰当地使用,可以让代码更加地简洁优雅。
(1)使用箭头函数取代小函数
有很多使用小函数的场景,如果写个 function,代码起码得写 3 行,但是用箭头函数一行就搞定了,例如实现数组从大到小排序:
var nums = [4, 8, 1, 9, 0];
nums.sort(function(a, b){return b - a;
});
//输出[9, 8, 4, 1, 0]
如果用箭头函数,排序只要一行就搞定了:
var nums = [4, 8, 1, 9, 0];``nums.sort(a, b => b - a);
代码看起来简洁多了,还有 setTimeout 里面经常会遇到只要执行一行代码就好了,写个 function 总感觉有点麻烦,用字符串的方式又不太好,所以这种情况用箭头函数也很方便:
setTimeout(() =>console.log("hi"), 3000)
箭头函数在 C++/Java 等其它语言里面叫做 Lambda 表达式,Ruby 比较早就有这种语法形式了,后来 C++/Java 也实现了这种语法。当然箭头函数或者 Lambda 表达式不仅适用于这种一行的,多行代码也可以,不过在一行的时候它的优点才比较明显。
(2)使用 ES6 的 class
虽然 ES6 的 class 和使用 function 的 prototype 本质上是一样的,都是用的原型。但是用 class 可以减少代码量,同时让代码看起来更加地高大上,使用 function 要写这么多:
function Person(name, age){this.name = name;this.age = age;
}Person.prototype.addAge = function(){this.age++;
};Person.prototype.setName = function(name){this.name = name;
};
使用 class 代码看加地简洁易懂:
class Person{constructor(name, age){this.name = name;this.age = age;}addAge(){this.age++;}setName(name){this.name = name;}
}
并且 class 还可以很方便地实现继承、静态的成员函数,就不需要自己再去通过一些技巧去实现了。
(3)字符串拼接
以前要用+号拼接:
var tpl ='<div>' +' <span>1</span>' +'</div>';
现在只要用两个反引号“`”就可以了:
var tpl =
` <div><span>1</span></div>
`;
另外反引号还支持占位替换,原本你需要:
var page = 5,type = encodeURIComponet("#js");
var url = "/list?page=" + page + "&type=" + type;
现在只需要:
var url = `/list?page=${page}&type=${type}`;
就不用使用+号把字符串拆散了。
(4)块级作用域变量
块级作用域变量也是 ES6 的一个特色,下面的代码是一个任务队列的模型抽象:
var tasks = [];
for(var i = 0; i < 4; i++){tasks.push(function(){console.log("i is " + i);});
}
for(var j = 0; j < tasks.length; j++){tasks[j]();
}
但是上面代码的执行输出是 4,4,4,4,并且不是想要输出:0,1,2,3,所以每个 task 就不能取到它的 index 了,这是因为闭包都是用的同一个 i 变量,i 已经变成 4 了,所以执行闭包的时候就都是 4 了。那怎么办呢?可以这样解决:
var tasks = [];
for(var i = 0; i < 4; i++){!function(k){tasks.push(function(){console.log("i is " + k);});}(i);
}
for(var j = 0; j < tasks.length; j++){tasks[j]();
}
把 i 赋值给了 k,由于 k 它是一个 function 的一个参数,每次执行函数的时候,肯定会实例化新的 k,所以每次的 k 都是不同的变量,这样就输出就正常了。但是代码看起来有点别扭,如果用 ES6,只要把 var 改成 let 就可以了:
var tasks = [];
for(let i = 0; i <= 4; i++){tasks.push(function(){console.log("i is " + i);});
}
for(var j = 0; j < tasks.length; j++){tasks[j]();
}
只改动了 3 个字符就达到了目的。因为 for 循环里面有个大括号,大括号就是一个独立的作用域,let 定义的变量在独立的作用域里面它的值也是独立的。当然即使没写大括号 for 循环执行也是独立的。除了以上几点,ES6 还有其它一些比较好用的功能,如 Object 的 assign,Promise 等,也是可以帮助写出简洁高效的代码。以上列了我自己在实际写代码过程中遇到的一些问题和一些个人认为比较重要的方面,其它的还有变量命名、缩进、注释等,这里就不提及了。写代码的风格也体现了编程的素养,有些人的代码看起来非常地干净利落,而有些人的代码看起来让人比较痛苦。这种编程素质的提升需要有意识地去做一些改进,有些人虽然代码写得很烂,但是他自己并不觉得有什么问题。这就需要多去学下别人的代码,甚至学一下其它语言的书写,两者一比较就能发现差异,或者看下这方面的书,像什么代码大全之类的。
前端进阶-个人笔记-如何写出更好风格的JS代码(JS 代码优化建议)相关推荐
- 如何写出同事看不懂的Java代码?
壹.瞒天过海 我打赌你肯定想不到,有人居然会在注释里下了毒.看看下面的代码,简单到main方法中只有一行注释. public static void main(String[] args) {// \ ...
- 大佬教你如何写出更好的CSS,分享web前端资料
让我们开门见山:编写优秀的 CSS 代码是件十分痛苦的事情.很多开发人员都不想做 CSS 开发.你让我干什么都行,但是 CSS 还是算了吧. 在我创建应用的时候,从来都无法从 CSS 中享受到乐趣.但 ...
- [读书笔记]5个小技巧让你写出更好的JavaScript[图]
在使用JavaScript时,我们常常要写不少的条件语句.这里有五个小技巧,可以让你写出更干净.漂亮的条件语句. 使用Array.includes来处理多重条件 举个栗子: //条件语句 functi ...
- 你应该知道的7个写出更好的 Java 代码的技巧
来源:SpringForAll社区 查看这些技巧和窍门可以帮助你写出更好的 Java 代码. 是的,你可以按照以下7个技巧和窍门编写出简短.整洁的 Java 代码.他们中的一些可能会让你感到惊讶,但是 ...
- python写出的程序如何给别人使用-涨姿势!这些小技巧让小白也可以写出更优雅的Python代码!...
原标题:涨姿势!这些小技巧让小白也可以写出更优雅的Python代码! 一.前言 我前两天回答了两个Python相关的问题,收到了很多赞,从答案被收藏的情况来看,确实对不少人都很有帮助,所以我也很开心. ...
- 9个JavaScript小技巧:写出更简洁,高效代码
JavaScript一直在变化进步着,这儿列举了一些小技巧帮你在2019年写出更简洁,高效的可拓展的代码.下面共列举了9个讲究使用的小技巧来帮助你成为更好的开发者. 1. async / await ...
- 如何写出更好的代码(文末有福利)
女主宣言 我们在过去的几期推送里已经给大家介绍了笔者根据多年研发经验总结出来的编码规范和 git 等实用工具的运用场景,今天咱们就来继续聊聊项目开发过程的诸多方法论.本文最先发布于 7rule,转载已 ...
- 5个小技巧让你写出更好的 JavaScript 条件语句
在使用 JavaScript 时,我们常常要写不少的条件语句.这里有五个小技巧,可以让你写出更干净.漂亮的条件语句. 1.使用 Array.includes 来处理多重条件 举个栗子 : // 条件语 ...
- 5个小技巧让你写出更好的JavaScript 条件语句
在使用 JavaScript 时,我们常常要写不少的条件语句.这里有五个小技巧,可以让你写出更干净.漂亮的条件语句. 使用 Array.includes 来处理多重条件 举个栗子 : // 条件语句 ...
最新文章
- 直播 | Python Web开发者的破局之道
- 讲mysql执行流程书籍_MySQL 基础架构 1. 一条SQL查询语句的执行过程(个人学习笔记)...
- vue导入excel进度条_Vue 前端开发——导入Excel/Csv
- 二分查找算法及其变种
- 史上最有趣的Readme
- 给超链接A添加按钮样式
- macbook历代_苹果MacBook Pro为什么越来越贵?历代回顾与新MBP简评
- 12 种主流编程语言输出“ Hello World ”,你真的都会了吗?
- php sorcket_深入浅出讲解:php的socket通信
- CLR寄宿(上) MSCOREE.DLL
- axios 同时多个请求_Axios是什么?用在什么场景?如何使用?
- java 对象转换成map_Java中对象(Object)转换成Map
- 极光推送java demo_极光推送JAVA代码示例
- html 实现动态在线预览word、excel、pdf等文件(方便快捷)
- Android OTG U盘相关
- Arduino ESP32 通过定时器(Timer)功能唤醒深度睡眠
- CTF_Web:从0学习Flask模板注入(SSTI)
- 实例讨论数据可视化的配色思路
- h264基本编码参数
- Java读取Hdfs的文件数据出现乱码的解决方案和办法
热门文章
- Sublime Text 常用热键
- Vijos P1026毒药?解药?
- 谷歌最新开源前端框架了解一下?前端小白都能看懂的8本书
- mysql内部服务器错误_解决discuz论坛500内部服务器错误
- Shell中的<,<<,>,>>介绍
- 招聘软件测试笔试题及答案,软件测试笔试题及答案 招聘笔试题(一般能力测试50道及答案).doc...
- 智能AI计算芯片对比
- Linux下dup函数、dup2函数
- 中兴交换机配置vlan地址
- python tkinter怎么安装_Python的Tkinter库的安装