前端优化js篇

前言

分享即学习,欢迎转载,随意抄袭,学到了就是你的。

  • 文章共分成两个部分,分别为js部分与html+css部分。
  • 本文针对js优化部分,后续会跟进html+css部分。
  • 纯手码内容较长,建议分开食用,下面会先呈上目录。

正文

js优化建议

首先说明,本文仅供优化的方向和思路,会举例说明,并不代表所有的语法都要这么写,要结合应用场景与当前开发团队的平均水平,合理使用,而不是一味追求优化而去要求团队的代码风格,如果非要追求代码的统一性,也应该把业务处理或数据处理的方法变成共通方法,让开发人员调用。

在没有足够的时间和经验以及项目积累的情况下,时刻谨记,按时完成任务才是关键,完成任务是主优化代码其次。

js优化方向

提到优化,大多数想到的场景都是性能优化。
以前,由于浏览器以及网速的限制,代码性能优化就显得极为重要。
但在如今,谷歌浏览器独步天下已成必然,网速更是直线飞起,互联网产品的版本更新迭代更加频繁。
所以,应该适度考虑牺牲一点点性能,而去做代码层次的优化。
语义清晰、逻辑明了的代码既可以增强开发效率,同时也更利于增强代码的可读性、降低维护成本、版本迭代更新。
恰到好处的高级函数使用才是对于前端代码优化的最好方向,而不是一味地追求性能。

js优化建议

言归正传,优化的思路主要考虑以下4点:

  • 语义简单明了,逻辑清晰且合理
  • 合理使用高级函数
  • 方法尽早返回、尽早结束
  • 减少运算、 减少语句

满足以上四点,哪怕不做性能优化,也能保证代码的执行效率。

举例:
众所周知,就性能而言for > map
在网上可能都看过这样的测试

let test = 99999
let arr = new Array(33333333).fill(test)

console.time()

// 原生for
for (let i = 0; i < arr.length; i++) {}

// map
arr.map((item, index, arr) => {})

console.timeEnd()

电脑配置i7-9750H测试结果
for 18ms左右
map 420-480ms

乍一看相差确实很大,但是现实中使用的场景却不可能是这样的,肯定是带着运算和数据处理的,看下面的例子:

console.time()

let test = 9999999
let arr = new Array(9999999).fill(test)

let arrayList = []
// 原生for
for (let i = 0; i < arr.length; i++) {
   arrayList.push(arr[i])
}

// map
let arrayList = arr.map(item => item)

console.timeEnd()

电脑配置i7-9750H测试结果
for 705-720ms左右
map 680-700ms左右

结果map还比for快。单单论性能而言,肯定是for更快,但是写for方法的时候多了很多运算比如arr.length、push在每次循环时都执行。
所以,不论是考虑代码的性能还是、可读性,合理的使用高级函数才对代码的最好优化。


以判断语句为例,优化之时应考虑以下几点:

  • 更少的嵌套,尽早返回,错误语句应提前抛出,使用return或throw
  • 就性能而言:当数据量达到万级以上,if的执行速度反而会比switch更快;
  • 正常逻辑判断数量不会超过两位数,所以应选择合适的实现方式;
  • if在某些情景更适合表达逻辑,witch的控制表达式会依次与case后的值匹配,可以根据case标签的执行频率排列case标签的顺序进一步提高速度。
// bad
if (color) {
    if (color === 'black') {
        printBlackBackground();
    } else if (color === 'red') {
        printRedBackground();
    } else if (color === 'blue') {
        printBlueBackground();
    } else if (color === 'green') {
        printGreenBackground();
    } else {
        printYellowBackground();
    }
}

// good
var colorObj = {
    'black': printBlackBackground,
    'red': printRedBackground,
    'blue': printBlueBackground,
    'green': printGreenBackground,
    'yellow': printYellowBackground
}
if (color in colorObj) {
    colorObj[color]()
}
// bad
function condition(fruit) {
  if (fruit == 'apple' || fruit == 'banana') {
    console.log(fruit);
  }
}

// good
function condition(fruit){
    const allFruit = ['apple','banana'];
    if(allFruit.includes(fruit)){
        console.log(fruit)
    }
}

let与const使用

let取代var

let可以完全取代var且没有副作用;
下述例子如果把let替换成var则输出的是undefined,这违反了变量先声明后使用的原则

console.log(a)
let a = 'hello world'

const的使用

let与const之间,const定义的是常量,let定义的是变量;
建议优先使用const,尤其在全局环境中,大多数场景中我们应该在全局优先设置常量然后使用,变量大多数使用在方法体内。

字符串定义

字符串定义应该使用const
推荐eslint规则应限制使用单引号或反引号,且不使用分号,动态字符串应用反引号拼接而不是用加减号。
原因:

  1. JavaScript编译器会对const进行优化,所以多使用const有利于程序的运行效率;
  2. 单引号是为了减少不必要的转义;
  3. 分号,习惯而已个人认为没必要加,精简代码;
  4. 动态字符串拼接,不用加减号,减少不必要的运算;
// bad

var a = "hello world";
var b = "<div class=\"header\">" + a + "</div>";

// acceptable
const a = 'hello world'
const b = '<div class="header">' + a + '</div>'

// good
const a = 'hello world'
const b = `<div class="header">${a}</div>`

解构赋值

  • 减少运算和不必要的语句

深拷贝

单层

// bad
const a = { a: 'a', b: 'b'}
const b = JSON.parse(JSON.stringify(a))

// good
const a = { a: 'a', b: 'b'}
const b = { ...a }

解构赋值

数组赋值
const arr = [ 1, 2, 3, 4]

// bad
const first = arr[ 0 ]
const second = arr[ 1 ]
 
// good
const [ first, second ] = arr

Array

  • 数组拼接使用 unshiftsplicepush
  • Array.sort()数组排序
  • Array.filter()过滤
  • Array.flat(Infinity)数据扁平化
  • Array.Stringify()转字符串
  • Array.includes()检测数组包含指定值
  • Array.every()全部条件符合
  • Array.some()部分条件符合
  • Array.find()返回通过函数内判断的第一个元素的值
  • Array.findIndex()返回通过函数内判断的第一个元素的下标
  • Array.reduce()数组中的每个值作为累加,最终计算为一个值。

Object

  • delete obj0.age 删除
  • prototype 返回对象类型原型的引用
  • Object.keys(obj)对obj中的索引进行循环
  • Object.values(obj)对obj中的值进行循环
  • Object.entries(obj)循环obj中的某一项

对象的循环调用

let obj = {
    name:"张三",
    sex:"男",
    age:20,
    height:150
}
 
for ( let [key,val] of Object.entries(obj)){
    console.log(key,val)
}

// name 张三
// sex 男
// age 20
// height 150

对象尽量静态化

// bad
const obj = {}
obj.newData = 3

// conventional
const obj = {}
Object.assign(obj, { newData:'11' })

// good
const obj = { newData: null }
obj.newData = 3

对象属性名称动态

const varName = () => {
    return 'key'
}

// bad
const obj = {
    id: 5,
    name : 'XiaoMing'
}
obj[varName()] = 123

// good
const obj = {
    id: 5,
    name : 'XiaoMing',
    [varName()]: 123
}

对象属性动态

const obj_B = { a: 'a', b: 'b' }
const obj_C = { c: 'c' }

// bad
const obj_A = {}
obj_A.a = obj_B.a
obj_A.b = obj_B.b
obj_A.c = obj_C.c

// conventional
const obj_A = {
    a: obj_B.a,
    b: obj_B.b,
    c: obj_C.c
}

// good
const obj_A = {
    ...obj_B,
    ...obj_C
}

对象属性简写

const obj = {
    name: 'name',
    
    // bad
    funNameA: function (item) {
        console.log('item', item)
    },
    
    // good
    funNameB: item => console.log('item', item),
    
    // best:
    funNameC(item){
        console.log('item', item)
    }
}

函数

链式调用

返回对象使方法可以链式调用

function Person(name) {
    this.name = name
    this.sayName = function() {
        console.log("Hello my name is: ", this.name)
        return this
    }
    this.changeName = function(name) {
        this.name = name
        return this
    }
}
let person = new Person("John")
person.sayName().changeName("Timmy").sayName()

箭头函数

某些需要使用函数表达式的场合,尽量用箭头函数代替;
省去不必要的return,而且绑定了this,代码更整洁

let arrayA = [1, 2, 3, 4]
let arrayB = []

// bad
arrayA.map(function (x) {
    arrayB.push(x * x)
})

// good
arrayB = arrayA.map( x => {
    return x * x
})

// best
arrayB = arrayA.map( x => x * x)

函数的参数赋值

// bad
function requestAction( items ) {
    const paramA = items.paramA
    const paramB = items.paramB
}
 
// good
function requestAction( items ) {
    const { paramA , paramB } = items
}
 
// best
function requestAction( { paramA , paramB }) {
}

多个函数返回值

// bad
function requestAction() {
    return [ valA, valB, val3]
}
 
// good
function requestAction() {
    return { valA, valB, val3 }
}
 
// best
const { valA, valB, val3 } = requestAction()

函数参数默认值

函数的参数都要设置默认值,这样的的函数才能足够健壮

// bad
function( items ) {
    items = items || {}
}

// good
function( items = {} ) {
    // ...
}

性能优化

这里的性能优化并不是指是否使用高级函数,是指减少不必要的运算与语句的使用,下面举几个例子

循环优化

在for中定义array.length,每次循环都会重新计算array的长度,所以循环最大限制次数应该是个定值

// bad
for(let i = 0; i < array.length; i++) {
    // ...
}

// good
const length = array.length
for(let i = 0; i < length; i++) {
    // ...
}

减少运算

加号也算运算

// bad
let testData = '测试数据'
console.log('testData' + testData)

// good
console.log('testData', testData)

最小化语句数

// bad
let a = '1',
let b = '2',
let c = 3

// good
let a = '1',
    b = '2',
    c = 3

合并语句

// bad
let i = 0
let value = array[i]
i++

// good
let i = 0
let value = array[i++]

写在最后

以上是我针对于前端开发代码优化js部分的一些建议与心得。

希望大家明白,知道高级函数与合理的使用高级函数是两码事。

如何优雅的写出漂亮且高效的代码,严谨的规则、明了的语义和清晰的逻辑思路缺一不可,这样才能结合实际场景合理判断出适用的高阶函数加以使用,万万不可为了使用高级函数而去使用高级函数。

后续更新html+css部分。

分享即学习,欢迎转载,随意抄袭,学到了就是你的。

  • 3
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值