前端代码优化,以及日常使用技巧

2023-05-30 0 781

前端代码优化,以及日常使用技巧

简而言之无规矩清圣,后端天数在项目组 code-review 中辨认出,小贴士 所推荐我们能大体过两遍,逐步形成他们的标识符生活习惯

责任编辑主要就特别针对许多 JavaScript 展开强化,使之更为强壮,时效性大列佩季哈区,更以保护。

if 推论的强化

1、最简单的方式:if 推论

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

优点:标识符太短了,保护和写作都很不亲善

2、好一点儿的方式:Switch

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

3、更优的方式: 策略模式

策略模式利用组合、委托和多态等技术和思想,能有效地避免多重条件选择语句。它提供了对开放—封闭原则的完美支持,将算法封装在独立的 strategy 中,使得它们易于切换,易于理解,易于扩展。

const commodity = new Map([ [phone, 1999], [computer, 9999], [television, 2999], [gameBoy, 3999], ]) const price = (name) => { return commodity.get(name) } price(phone) // 1999

includes 的强化

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 你的身份不合法 } }

for 循环

在 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 的创建

创建多个 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, Im a global variable” } fn() function fn() { this.a = “Actually, Im 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 = “Im 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 等等,但有些时候我们并不希望在事件持续触发的过程中那么频繁地去执行函数。这时候就用到防抖与节流。

<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

默认情况下,浏览器是同步加载 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 区别:

defer:DOM 结构完全生成,和其他脚本执行完成,才会执行(渲染完再执行)。有多个 defer 脚本时,会按照页面出现的顺序依次加载、执行。

async:一旦下载完成,渲染引擎就会中断渲染,执行这个脚本以后,再继续渲染(下载完就执行)。有多个 async 脚本时,不能保证按照页面出现顺序加载、执行

前端代码优化,以及日常使用技巧

天宇文创意乐派”(ID:gh_cc865e4c536b)

nvm安装与采用
前端代码优化,以及日常使用技巧
Spring Boot + Vue 开发示例 音乐播放app
前端代码优化,以及日常使用技巧
20 个 JavaScript 单行标识符杀手锏
前端代码优化,以及日常使用技巧
全方位解读 package.json
前端代码优化,以及日常使用技巧
layui 官网将于 2021年10月13日 下线 曾经我们一起追过的东西
前端代码优化,以及日常使用技巧

责任编辑采用 文章同步助手 同步

相关文章

发表评论
暂无评论
官方客服团队

为您解决烦忧 - 24小时在线 专业服务