所谓无规矩不成方圆,前端时间在团队 code-review 中发现,小编 推荐大家可以大致过一遍,形成自己的编码习惯
本文主要针对一些 JavaScript 进行优化,使之更加健壮,可读性更强,更以维护。
let commodity = {
phone: '手机',
computer: '电脑',
television: '电视',
gameBoy: '游戏机',
}
function price(name) {
if (name === commodity.phone) {
console.log(1999)
} else if (name === commodity.computer) {
console.log(9999)
} else if (name === commodity.television) {
console.log(2999)
} else if (name === commodity.gameBoy) {
console.log(3999)
}
}
price('手机') // 9999
缺点:代码太长了,维护和阅读都很不友好
let commodity = {
phone: '手机',
computer: '电脑',
television: '电视',
gameBoy: '游戏机',
}
const price = (name) => {
switch (name) {
case commodity.phone:
console.log(1999)
break
case commodity.computer:
console.log(9999)
break
case commodity.television:
console.log(2999)
break
case commodity.gameBoy:
console.log(3999)
break
}
}
price('手机') // 9999
策略模式利用组合、委托和多态等技术和思想,可以有效地避免多重条件选择语句。它提供了对开放—封闭原则的完美支持,将算法封装在独立的 strategy 中,使得它们易于切换,易于理解,易于扩展。
const commodity = new Map([
['phone', 1999],
['computer', 9999],
['television', 2999],
['gameBoy', 3999],
])
const price = (name) => {
return commodity.get(name)
}
price('phone') // 1999
includes 是 ES7 新增的 api,与 indexOf 不同的是 includes 直接返回的是 Boolean 值,indexOf 则 返回的索引值, 数组和字符串都有 includes 方法。
需求:我们来实现一个身份认证方法,通过传入身份 Id 返回对应的验证结果
传统方法
function verifyIdentity(identityId) {
if (identityId == 1 || identityId == 2 || identityId == 3 || identityId == 4) {
return '你的身份合法,请通行!'
} else {
return '你的身份不合法'
}
}
includes 优化
function verifyIdentity(identityId) {
if ([1, 2, 3, 4].includes(identityId)) {
return '你的身份合法,请通行!'
} else {
return '你的身份不合法'
}
}
在 JavaScript 中,我们可以使用 for(), while(), for(in),for(of)几种循环,事实上,这三种循环中 for(in) 的效率极差,因为他需要查询散列键,所以应该尽量少用。
for 循环是最传统的语句,它以变量 i 作为索引,以跟踪访问的位置,对数组进行操作。
var arr = ['a', 'b', 'c']
for (var i = 0; i < arr.length; i++) {
console.log(arr[i]) //结果依次a,b,c
}
以上的方法有一个问题:就是当数组的长度到达百万级时,arr.length 就要计算一百万次,这是相当耗性能的。所以可以采用以下方法就行改良。
var arr = ['a', 'b', 'c']
for (var i = 0, length = arr.length; i < length; i++) {
console.log(arr[i]) //结果依次a,b,c
}
此时 arr.length 只需要计算一次,优化了性能。
for-in 一般用来来遍历对象的属性的,不过属性需要 enumerable(可枚举)才能被读取到。同时 for-in 也可以遍历数组,遍历数组的时候遍历的是数组的下标值。
var obj = { 0: 'a', 1: 'b', 2: 'c' }
for (var key in obj) {
console.log(key) //结果为依次为0,1,2
}
var arr = ['a', 'b', 'c']
for (var key in a) {
console.log(key) //结果为依次为0,1,2
}
for-of 语句看着有点像 for-in 语句,但是和 for-of 语句不同的是它不可以循环对象,只能循环数组。
var arr = ['a', 'b', 'c']
for (var value of arr) {
console.log(value) // 结果依次为a,b,c
}
for-of 比 for-in 循环遍历数组更好。for-of 只要具有 Iterator 接口的数据结构,都可以使用它迭代成员。它直接读取的是键值。for-in 需要穷举对象的所有属性,包括自定义的添加的属性也能遍历到。且 for-in 的 key 是 String 类型,有转换过程,开销比较大。
所以在开发过程中循环数组尽量避免使用 for-in。
数组去重是实际开发处理数据中经常遇到的,方法有很多,这里就不一一例举了。
1、最传统的方法:利用数组的 indexOf 下标属性来查询。
function unique4(arr) {
var newArr = []
for (var i = 0; i < arr.length; i++) {
if (newArr.indexOf(arr[i]) === -1) {
newArr.push(arr[i])
}
}
return newArr
}
console.log(unique4([1, 1, 2, 3, 5, 3, 1, 5, 6, 7, 4]))
// [1, 2, 3, 5, 6, 7, 4]
2、优化:利用 ES6 的 Set 方法。
Set 本身是一个构造函数,用来生成 Set 数据结构。Set 函数可以接受一个数组(或者具有 iterable 接口的其他数据结构)作为参数,用来初始化。Set 对象允许你存储任何类型的值,无论是原始值或者是对象引用。它类似于数组,但是成员的值都是唯一的,没有重复的值。
function unique4(arr) {
return Array.from(new Set(arr)) // 利用Array.from将Set结构转换成数组
}
console.log(unique4([1, 1, 2, 3, 5, 3, 1, 5, 6, 7, 4]))
// [1, 2, 3, 5, 6, 7, 4]
箭头函数表达式的语法比函数表达式更简洁。所以在开发中更推荐使用箭头函数。特别是在 vue 项目中,使用箭头函数不需要在更 this 重新赋一个变量。
// 使用functions
var arr = [5, 3, 2, 9, 1]
var arrFunc = arr.map(function (x) {
return x * x
})
console.log(arrFunc)
// 使用箭头函数
var arr = [5, 3, 2, 9, 1]
var arrFunc = arr.map((x) => x * x)
要注意的是,箭头函数不绑定 arguments,取而代之用 rest 参数…解决。
// 不能使用 arguments
let fun1 = (b) => {
console.log(arguments)
}
fun1(2, 92, 32, 32) // Uncaught ReferenceError: arguments is not defined
// 使用rest 参数
let fun2 = (...c) => {
console.log(c)
}
fun2(3, 82, 32, 11323) // [3, 82, 32, 11323]
创建多个 dom 元素时,先将元素 append 到 DocumentFragment 中,最后统一将 DocumentFragment 添加到页面。
常规方法;
for (var i = 0; i < 1000; i++) {
var el = document.createElement('p')
el.innerhtml = i
document.body.appendChild(el)
}
使用 DocumentFragment 优化多次 append
var frag = document.createDocumentFragment()
for (var i = 0; i < 1000; i++) {
var el = document.createElement('p')
el.innerHTML = i
frag.appendChild(el)
}
document.body.appendChild(frag)
更优的方法:使用一次 innerHTML 赋值代替构建 dom 元素
var html = []
for (var i = 0; i < 1000; i++) {
html.push('<p>' + i + '</p>')
}
document.body.innerHTML = html.join('')
系统进程不再用到的内存,没有及时释放,就叫做内存泄漏(memory leak)。当内存占用越来越高,轻则影响系统性能,重则导致进程崩溃。
引起内存泄漏的原因
1、未声明变量或者使用 this 创建的变量(this 的指向是 window)都会引起内存泄漏
function fn() {
a = "Actually, I'm a global variable"
}
fn()
function fn() {
this.a = "Actually, I'm a global variable"
}
fn()
解决方法:
避免创建全局变量
使用严格模式,在 JavaScript 文件头部或者函数的顶部加上 use strict。
2、在 vue 单页面应用,声明的全局变量在切换页面的时候没有清空
<div id="home">
这里是首页
</div>
export default {
mounted() {
window.test = {
// 此处在全局window对象中引用了本页面的dom对象
name: 'home',
node: document.getElementById('home')
}
}
}
解决方案: 在页面卸载的时候顺便处理掉该引用。
destroyed () {
window.test = null // 页面卸载的时候解除引用
}
闭包引起的内存泄漏原因:闭包可以维持函数内局部变量,使其得不到释放。
function fn() {
var a = "I'm a"
return function () {
console.log(a)
}
}
解决:将事件处理函数定义在外部,解除闭包,或者在定义事件处理函数的外部函数中,删除对 dom 的引用。
由于项目中有些页面难免会碰到需要定时器或者事件监听。但是在离开当前页面的时候,定时器如果不及时合理地清除,会造成业务逻辑混乱甚至应用卡死的情况,这个时就需要清除定时器事件监听,即在页面卸载(关闭)的生命周期函数里,清除定时器。
methods:{
resizeFun () {
this.tableHeight = window.innerHeight - document.getElementById('table').offsetTop - 128
},
setTimer() {
this.timer = setInterval(() => { })
},
clearTimer() {//清除定时器
clearInterval(this.timer)
this.timer = null
}
},
mounted() {
this.setTimer()
window.addEventListener('resize', this.resizeFun)
},
beforeDestroy() {
window.removeEventListener('resize', this.resizeFun)
this.clearTimer()
}
在前端开发的过程中,我们经常会需要绑定一些持续触发的事件,如 resize、scroll、mousemove 等等,但有些时候我们并不希望在事件持续触发的过程中那么频繁地去执行函数。这时候就用到防抖与节流。
案例 1:远程搜索时需要通过接口动态的获取数据,若是每次用户输入都接口请求,是浪费带宽和性能的。
<Select :remote-method="remoteMethod">
<Option v-for="item in temoteList" :value="item.value" :key="item.id">{{item.label}}</Option>
</Select>
<script>
function debounce(fn, wait) {
let timeout = null
return function () {
if (timeout !== null) clearTimeout(timeout)
timeout = setTimeout(fn, wait)
}
}
export default {
methods:{
remoteMethod:debounce(function (query) {
// to do ...
}, 200),
}
}
<script>
案例 2:持续触发 scroll 事件时,并不立即执行 handle 函数,当 1000 毫秒内没有触发 scroll 事件时,才会延时触发一次 handle 函数。
function debounce(fn, wait) {
let timeout = null
return function () {
if (timeout !== null) clearTimeout(timeout)
timeout = setTimeout(fn, wait)
}
}
function handle() {
console.log(Math.random())
}
window.addEventListener('scroll', debounce(handle, 1000))
默认情况下,浏览器是同步加载 js 脚本,解析 html 过程中,遇到 <script> 标签就会停下来,等脚本下载、解析、执行完后,再继续向下解析渲染。
如果 js 文件体积比较大,下载时间就会很长,容易造成浏览器堵塞,浏览器页面会呈现出“白屏”效果,用户会感觉浏览器“卡死了”,没有响应。此时,我们可以让 js 脚本异步加载、执行。
<script src="path/to/home.js" defer></script>
<script src="path/to/home.js" async></script>
上面代码中,<script> 标签分别有 defer 和 async 属性,浏览器识别到这 2 个属性时 js 就会异步加载。也就是说,浏览器不会等待这个脚本下载、执行完毕后再向后执行,而是直接继续向后执行。
defer 与 async 区别:
来源: 前端开发社区
在程序开发中,经常会使用到for循环的,但是很多人写的for循环效率都是比较低的,下面就举例说明,并总结优化for循环的方法,来提高我们程序的执行效率。
网站的加载速度不仅影响着用户体验,也会影响搜索引擎的排名,在百度推出“闪电算法”以来,将网站首屏打开速度被列入优化排名行列,作为前端开发的我们需要如果来优化网站的打开速度呢?下面就整理挖掘出很多细节上可以提升性能的东西分享给大家
DocumentFragments是DOM节点。它们不是主DOM树的一部分。通常的用例是创建文档片段,将元素附加到文档片段,然后将文档片段附加到DOM树。在DOM树中,文档片段被其所有的子元素所代替。因为文档片段存在于内存中,并不在DOM树中
对于代码裡面的 if else,我们可以使用逻辑判断式,或更好的三元判断式来优化代码。除了可以降低维护项目的成本之外,还可以提升代码可读性。就让我们从最简单的 if else 例子开始吧。
小程序从发布到现在也已经有将近两年的时间,越来越来多的公司开始重视小程序生态带来的流量,今年也由于小程序平台对外能力的越来越多的开放以及小程序平台的自身优化,越来越多的开发者也自主的投入到小程序的开发当中
无论你正在将 GIF 动图转换为 MP4 视频,还是手头已经有一大堆 MP4 视频,你都可以优化文件结构,以使得这些视频更快地加载和播放。通过重组 atoms 将 moov 放到文件开头,浏览器可以避免发送额外的 HTTP range request 请求来搜寻和定位 moovatom
要优化 Web 服务器的性能,我们先来看看 Web 服务器在 web 页面处理上的步骤:Web 浏览器向一个特定的服务器发出 Web 页面请求; Web 服务器接收到 web 页面请求后,寻找所请求的 web 页面,并将所请求的 Web 页面传送给 Web 浏览器; 显示出来
浏览器下载完页面所有的资源后,就要开始构建DOM树,于此同时还会构建渲染树(Render Tree)。(其实在构建渲染树之前,和DOM树同期会构建Style Tree。DOM树与Style Tree合并为渲染树)
写篇文章的目的,是以开放小程序代码的层面的优化。包括:条件判断将wx:if换成了hidden 、页面跳转请销毁之前使用的资源、列表的局部更新、小程序中多张图片懒加载方案、Input状态下隐藏input,应预留出键盘收起的时间
生活在信息爆炸的今天,我们每天不得不面对和过滤海量的信息--无疑是焦躁和浮动的,这就意味着用户对你站点投入的时间可能是及其吝啬的(当然有一些刚需站点除外)。如何给用户提供迅速的响应就显得十分重要了
内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!