热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Javascript前端优化代码

这篇文章主要介绍了Javascript前端优化代码,对性能优化感兴趣的同学,可以参考下

if 判断的优化

Javascript条件语句在我们平时的开发中是不可避免要用到的,但是很多时候我们的代码写的并不好,一连串的if-else或者多重嵌套判断都会使得代码很臃肿,下面举例进行优化。

需求:现在有 4 个产品,分别是手机、电脑、电视机、游戏机,当然每个产品显示的价格不一样。

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(in)几种循环,事实上,这三种循环中for(in)的效率极差,因为他需要查询散列键,所以应该尽量少用。

for 循环是最传统的语句,它以变量 i 作为索引,以跟踪访问的位置,对数组进行操作。

var arr = ['a', 'b', 'c']
for (var i = 0; i 

以上的方法有一个问题:就是当数组的长度到达百万级时,arr.length就要计算一百万次,这是相当耗性能的。所以可以采用以下方法就行改良。

var arr = ['a', 'b', 'c']
for (var i = 0, length = arr.length; i 

此时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 

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('

' + i + '

') } 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单页面应用,声明的全局变量在切换页面的时候没有清空



解决方案: 在页面卸载的时候顺便处理掉该引用。

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:远程搜索时需要通过接口动态的获取数据,若是每次用户输入都接口请求,是浪费带宽和性能的。




上面代码中,标签分别有defer和async属性,浏览器识别到这 2 个属性时 js 就会异步加载。也就是说,浏览器不会等待这个脚本下载、执行完毕后再向后执行,而是直接继续向后执行

defer 与 async 区别:

  • defer:DOM 结构完全生成,以及其他脚本执行完成,才会执行(渲染完再执行)。有多个defer脚本时,会按照页面出现的顺序依次加载、执行。
  • async:一旦下载完成,渲染引擎就会中断渲染,执行这个脚本以后,再继续渲染(下载完就执行)。有多个async脚本时,不能保证按照页面出现顺序加载、执行

以上就是Javascript前端优化代码的详细内容,更多关于Javascript优化的资料请关注其它相关文章!


推荐阅读
  • CSS3选择器的使用方法详解,提高Web开发效率和精准度
    本文详细介绍了CSS3新增的选择器方法,包括属性选择器的使用。通过CSS3选择器,可以提高Web开发的效率和精准度,使得查找元素更加方便和快捷。同时,本文还对属性选择器的各种用法进行了详细解释,并给出了相应的代码示例。通过学习本文,读者可以更好地掌握CSS3选择器的使用方法,提升自己的Web开发能力。 ... [详细]
  • 阿里Treebased Deep Match(TDM) 学习笔记及技术发展回顾
    本文介绍了阿里Treebased Deep Match(TDM)的学习笔记,同时回顾了工业界技术发展的几代演进。从基于统计的启发式规则方法到基于内积模型的向量检索方法,再到引入复杂深度学习模型的下一代匹配技术。文章详细解释了基于统计的启发式规则方法和基于内积模型的向量检索方法的原理和应用,并介绍了TDM的背景和优势。最后,文章提到了向量距离和基于向量聚类的索引结构对于加速匹配效率的作用。本文对于理解TDM的学习过程和了解匹配技术的发展具有重要意义。 ... [详细]
  • 表单提交前的最后验证:通常在表单提交前,我们必须确认用户是否都把必须填选的做了,如果没有,就不能被提交到服务器,这里我们用到表单的formname.submit()看演示,其实这个对于我们修炼道 ... [详细]
  • Itwasworkingcorrectly,butyesterdayitstartedgiving401.IhavetriedwithGooglecontactsAPI ... [详细]
  • Iwouldliketobeabletohaveasidebarthatcanbetoggledinandoutonabuttonpress.However ... [详细]
  • 但有时候,需要当某事件触发时,我们先做一些操作,然后再跳转,这时,就要用JAVASCRIPT来实现这一跳转功能。下面是具体的做法:一:跳转到新页面,并且是在新窗口中打开时:复制代码代码如下:fu ... [详细]
  • JavaScript在常人看来都是门出不了厅堂的小语言,仅管它没有明星语言的闪耀,但至少网页的闪耀还是需要它的,同时它是一门很实用的语言,本人平时就喜欢拿它来写点实用工具或应用,本文演示用JavaSc ... [详细]
  • JavaScript概述1.JavaScript定义JavaScript是Netscape公司开发的一种基于对象和事件驱动的脚本语言。它是弱类型语言,只能由浏览器解释执行。其中:脚本语言:解释运行( ... [详细]
  • 如何实现织梦DedeCms全站伪静态
    本文介绍了如何通过修改织梦DedeCms源代码来实现全站伪静态,以提高管理和SEO效果。全站伪静态可以避免重复URL的问题,同时通过使用mod_rewrite伪静态模块和.htaccess正则表达式,可以更好地适应搜索引擎的需求。文章还提到了一些相关的技术和工具,如Ubuntu、qt编程、tomcat端口、爬虫、php request根目录等。 ... [详细]
  • Nginx使用AWStats日志分析的步骤及注意事项
    本文介绍了在Centos7操作系统上使用Nginx和AWStats进行日志分析的步骤和注意事项。通过AWStats可以统计网站的访问量、IP地址、操作系统、浏览器等信息,并提供精确到每月、每日、每小时的数据。在部署AWStats之前需要确认服务器上已经安装了Perl环境,并进行DNS解析。 ... [详细]
  • Monkey《大话移动——Android与iOS应用测试指南》的预购信息发布啦!
    Monkey《大话移动——Android与iOS应用测试指南》的预购信息已经发布,可以在京东和当当网进行预购。感谢几位大牛给出的书评,并呼吁大家的支持。明天京东的链接也将发布。 ... [详细]
  • 本文介绍了使用CentOS7.0 U盘刻录工具进行安装的详细步骤,包括使用USBWriter工具刻录ISO文件到USB驱动器、格式化USB磁盘、设置启动顺序等。通过本文的指导,用户可以轻松地使用U盘安装CentOS7.0操作系统。 ... [详细]
  • Lodop中特殊符号打印设计和预览样式不同的问题解析
    本文主要解析了在Lodop中使用特殊符号打印设计和预览样式不同的问题。由于调用的本机ie引擎版本可能不同,导致在不同浏览器下样式解析不同。同时,未指定文字字体和样式设置也会导致打印设计和预览的差异。文章提出了通过指定具体字体和样式来解决问题的方法,并强调了以打印预览和虚拟打印机测试为准。 ... [详细]
  • 本文介绍了lua语言中闭包的特性及其在模式匹配、日期处理、编译和模块化等方面的应用。lua中的闭包是严格遵循词法定界的第一类值,函数可以作为变量自由传递,也可以作为参数传递给其他函数。这些特性使得lua语言具有极大的灵活性,为程序开发带来了便利。 ... [详细]
  • Final关键字的含义及用法详解
    本文详细介绍了Java中final关键字的含义和用法。final关键字可以修饰非抽象类、非抽象类成员方法和变量。final类不能被继承,final类中的方法默认是final的。final方法不能被子类的方法覆盖,但可以被继承。final成员变量表示常量,只能被赋值一次,赋值后值不再改变。文章还讨论了final类和final方法的应用场景,以及使用final方法的两个原因:锁定方法防止修改和提高执行效率。 ... [详细]
author-avatar
心雨00937
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有