突破常规的前端技巧与方法(一)

简介: 突破常规的前端技巧与方法(一)

一、代码整洁推荐

1.1 三元(三目)运算符

如果只想在一行中编写if…else语句时,这是一个很好的节省代码的方式。

常规:

const x = 20
let answer
if(x > 10) {
    answer = '大于10'
}else {
    answer = '小于等于10'
}

简写:

const x = 20
const answer = x > 10? '大于10' : '小于等于10'

嵌套版三元运算

const x = 20
const answer = x > 10? '大于10' : x < 5? '小于5' : '在5和10之间'
// 第二层加上()增强可读性
const answer = x > 10? '大于10' : (x < 5? '小于5' : '在5和10之间')

注意:三元运算不要超过2层嵌套,否则可读性不强,如果是嵌套两层,要求第二层加上()帮助提升可读性。

1.2 短路判断简写

将变量值分配给另一个变量时,可能希望确保源变量不为null,undefined或为空。这时候可以编写带有多个条件的长 if 语句,也可以使用短路判断。

常规:

if(type !== null || type !== undefined || type !== '') {
    let wtType = type
} else {
    let wtType = '01'
}

简写:

let wtType = type || '01'

注意:如果type值为false或者数字0将取值为字符串’01’。

1.3 变量声明简写

在进行连续性的变量声明操作时,应尽可能的使用 一次声明语句来提升程序运行效率。

常规:

let x
let y
let z = 1

简写:

let x, y, z = 1

1.4 if真值判断简写

这可能是微不足道的,但值得一提。在执行“if 检查”时,有时可以省略全等运算符。

常规:

if(likeJavascript === true) {
    ...
}
if(likeNode !== true) {
    ...
}

简写:

if(likeJavascript) {
    ...
}
if(!likeNode) {
    ...
}

1.5 For循环简写

常规:

const arr = [1, 2, 3]
for(let i = 0; i < arr.length; i++) {
  console.log(i, arr[i])
  if(arr[i] > 1) {
    break
  }
}
// 0, 1
// 1, 2

如果不需要访问索引,请执行以下操作:

for(let item of arr) {
  console.log('item', item)
  if(item > 1) {
        break
    }
}
// 1
// 2

如果只想访问索引,请执行以下操作:

for(let index in arr) {
    console.log(index)
}
// 1
// 2
// 3

如果要访问对象中的键,请执行以下操作

const obj = {name: 'zhangsan', age: 18}
for(let key in obj) {
    console.log(key,obj[key])
}
// name
// age

注意:不能使用for…of 来遍历对象

1.6 对象属性简写

ES6提供了一种更简单的方法来为对象分配属性。如果变量名称与对象键相同,则可以使用简写表示法。

常规:

let signType = '1'
let params = {
    signType: signType
}

简写:

let signType = '1'
let params = {
    signType
}

1.7 箭头函数简写

经典函数以简单的形式易于读写,但是一旦你开始将它们嵌套在其他函数调用中,它们往往会变得有点冗长和混乱。

常规:

function sayHello(name) {
    console.log('Hello', name)
}
setTimeout(function() {
  console.log('Loaded')
}, 2000)
list.forEach(function(item) {
    console.log(item)
})

简写:

const sayHello = name => console.log('Hello', name)
setTimeout(() => console.log('Loaded'), 2000)
list.forEach(item => console.log(item))

1.8 隐式返回简写

Return 是我们经常使用的关键字,用于返回函数的最终结果。具有单个语句的箭头函数将隐式返回其执行结果(函数可以省略大括号{}用()省略return关键字,具体可参考下例)。

要返回多行语句(例如对象),必须使用 () 而不是 {} 来包装函数体。这可确保将代码执行为单个语句。

常规:

function sum(x, y) {
   return x + y
}
function makeInfo(name, age) {
    return {name, age}
}

简写:

const sum = (x, y) => x + y
const makeInfo = (name, age) => ({name, age})

1.9 模板字符串

您是否厌倦了使用 ‘+’ 将多个变量连接成一个字符串?有没有更简单的方法?如果你能够使用ES6,那么你很幸运。您需要做的就是使用反引号,并使用 ${} 来包含变量。

常规:

const name = 'zhangsan'
const age = 18
let des = name + '今年' + age + '岁'

简写:

const name = 'zhangsan'
const age = 18
let des = `${name}今年${age}岁`

1.10 默认参数值

您可以使用if语句定义函数参数的默认值。在ES6中,您可以在函数声明本身中定义默认值。

常规:

function volume(l, w, h) {
    if(w === undefined) {
        w = 3
    }
    if(h === undefined) {
        h = 4
    }
    return l * w * h
}

简写:

const volume = (l, w = 3, h = 4) => l * w * h
volume(2)
// 24

注意:只有w,h为undefined时默认值才会生效。

结构赋值中的默认值也是如此,如果值为null默认值不会生效,如:

const res = {
    list: null,
    code: undefined
}
const { list = [], code = 1 } = res
console.log(list) // null
console.log(code) // 1
let num = list.length // Uncaught TypeError: Cannot read properties of null (reading 'length')

注意:如果直接取list数组的长度或者利用[index]取里面的值在res.list为null或者不为数组的时候可能会发生报错,针对该问题,大家可以在解构的时候不赋默认值,在解构的下方利用null判断运算符来处理默认值,如:

const res = {
    list: null
}
let { list , code = 1 } = res
list = list ?? []
console.log(list) // []
let num = list.length // 0

1.11 解构赋值简写

对数组和变量进行解构可以减少变量滥用,提升程序的运行效率。

常规:

let params = {
  wtId: this.transferDetail.wtId,
  newPic: type === '01' ? this.selectPersonId : '', // type是方法入参
  oldPic: this.transferDetail.picOld,
  recordId: this.applyId, // 转派记录
  replacementPicStatus: '02', // 转派状态 01-转派中 02-转派结束
  replacementReason: this.replacementReason
}

简写:

const { selectPersonId, applyId, replacementReason, transferDetail } = this
let params = {
  wtId: transferDetail.wtId,
  newPic: type === '01' ? selectPersonId : '', // type是方法入参
  oldPic: transferDetail.picOld,
  recordId: applyId, // 转派记录
  replacementPicStatus: '02', // 转派状态 01-转派中 02-转派结束
  replacementReason
}

解构知识点链接地址:https://es6.ruanyifeng.com/#docs/destructuring

1.12 多条件判断简写

常规:

function typeHandle(type) {
    if (type === 'test1') {  
        test1(); 
     } else if (type === 'test2') {  
        test2(); 
     } else if (type === 'test3') {  
        test3(); 
     } else if (type === 'test4') {  
        test4(); 
     } else {  
        throw new Error('Invalid value ' + type); 
     }  
}
typeHandle('test3')

简写:

function typeHandle(type) { 
    const types = {  
         test1: test1,  
         test2: test2,  
         test3: test3,  
         test4: test4 
     }; 
    let func = types[type]; 
    (!func) && throw new Error('Invalid value ' + type);
    func(); 
}
typeHandle('test3')

1.13 多变量赋值简写

常规:

let test1, test2, test3; 
test1 = 1; 
test2 = 2; 
test3 = 3; 
let name, age, sex;
name = 'zhangsan';
age = '18';
sex = '男'

简写:(利用es6数组、对象的结构赋值,实现多变量赋值简写)

let [test1, test2, test3] = [1, 2, 3]; 
let {name, age, sex} = { name: 'zhangsan', age: '18', sex: '男'};

1.14 解构时重命名

常规:

const { ticketTypeName } = this.tciketDetail
let params = {
    wtName: ticketTypeName,
    ...
}

简写:

const { ticketTypeName: wtName } = this.tciketDetail
let params = {
    wtName,
    ...
}

对象解构赋值的简写形式:

let { foo: foo, bar: bar } = { foo: 'aaa', bar: 'bbb' };

也就是说,对象的解构赋值的内部机制,是先找到同名属性,然后再赋给对应的变量。真正被赋值的是后者,而不是前者。

let { foo: baz } = { foo: 'aaa', bar: 'bbb' };
baz // "aaa"
foo // error: foo is not defined

1.15 对象替代switch

常规:

// 获取工作票名称
workTicketName(type) {
    switch (type) {
        case '01':
            return '变一'
            break
        case '02':
            return '变二'
            break
        case '03':
            return '配一'
            break
        case '04':
            return '配二'
            break
        case '05':
            return '低压'
            break
        case '06':
            return '作业卡'
            break
        case '07':
            return '派工单'
            break
        default:
            break
    }
}
workTicketName('01') // 变一

简写:

// 获取工作票名称
workTicketName(type) {
    const typeObj = {
        '01': '变一',
        '02': '变二',
        '03': '配一',
        '04': '配二',
        '05': '低压',
        '06': '作业卡',
        '07': '派工单'
    }
    return typeObj[type]
}
workTicketName('01') // 变一

1.16 链判断运算符

编程实务中,如果读取对象内部的某个属性,往往需要判断一下,属性的上层对象是否存在。比如,读取message.body.user.firstName这个属性,安全的写法是写成下面这样。

// 错误的写法
const  firstName = message.body.user.firstName || 'default';
// 正确的写法
const firstName = (message
  && message.body
  && message.body.user
  && message.body.user.firstName) || 'default';
// 但是这种写法如果层级过长会显得冗长,可读性也不强,这是我们可以利用链判断运算符来解决
//链判断运算符写法
const firstName = message?.body?.user?.firstName || 'default';

链判断运算符?.有三种写法。

  • obj?.prop // 对象属性是否存在
  • obj?.[expr] // 同上 也可以理解为 arr?.[index]
  • func?.(...args) // 函数或对象方法是否存在

下面是?.运算符常见形式,以及不使用该运算符时的等价形式。

a?.b
// 等同于
a == null ? undefined : a.b
a?.[x]
// 等同于
a == null ? undefined : a[x]
a?.b()
// 等同于
a == null ? undefined : a.b()
a?.()
// 等同于
a == null ? undefined : a()

常规:

// 计划 id
let planId = this.ticketDetail && this.ticketDetail.planDetailVoList && this.ticketDetail.planDetailVoList[0] && this.ticketDetail.planDetailVoList[0].planId

简写:

// 计划 id
let planId = this.ticketDetail?.planDetailVoList?.[0]?.planId 
// 如果任意一个问号前面的值为null或者undefined都将直接返回undefined,不在向下取值

注意:链判断运算符只能在js代码块中使用,不能在template里面的标签上使用,否则会解析报错,如果想要在template里达到上述简写效果可以在计算属性中使用。

// 错误的写法
<template>  
    <div class="wrap">   
        <span>计划编号:</span>
        {{
              ticketDetail && ticketDetail.planDetailVoList && ticketDetail.planDetailVoList[0] && ticketDetail.planDetailVoList[0].planNo || ''
        }} 
  </div> 
</template>
<script> 
    export default {  
        data() {    
            return {
                ticketDetail: {
                    planDetailVoList: [
                        {
                            planNo: 'T202304200940' // 计划编号
                        }
                    ]
                } 
            }  
        }
    } 
</script>
//正确的写法
<template>  
    <div class="wrap">   
        <span>计划编号:</span>
        {{ planNo }} 
  </div> 
</template>
<script> 
    export default {  
        data() {    
            return {
                ticketDetail: {
                    planDetailVoList: [
                        {
                            planNo: 'T202304200940' // 计划编号
                        }
                    ]
                } 
            }  
        },
        // 计算属性
        computed: {
            // 计划编号
            planNo({ticketDetail}) {
               return ticketDetail?.planDetailVoList?.[0]?.planNo || ''
            }
        }
    } 
</script>

链判断运算符知识点链接:https://es6.ruanyifeng.com/#docs/operator

1.17 Null 判断运算符

读取对象属性的时候,如果某个属性的值是nullundefined,有时候需要为它们指定默认值。常见做法是通过||运算符指定默认值。

const headerText = response.settings.headerText || 'Hello, world!';
const animationDuration = response.settings.animationDuration || 300;
const showSplashScreen = response.settings.showSplashScreen || true;

上面的三行代码都通过||运算符指定默认值,但是这样写是错的。开发者的原意是,只要属性的值为nullundefined,默认值就会生效,但是属性的值如果为空字符串或false0,默认值也会生效。

为了避免这种情况,ES2020 引入了一个新的 Null 判断运算符??。它的行为类似||,但是只有运算符左侧的值为nullundefined时,才会返回右侧的值。

const headerText = response.settings.headerText ?? 'Hello, world!';
const animationDuration = response.settings.animationDuration ?? 300;
const showSplashScreen = response.settings.showSplashScreen ?? true;

上面代码中,默认值只有在左侧属性值为nullundefined时,才会生效。

目录
相关文章
|
25天前
|
存储 前端开发 JavaScript
前端的全栈之路Meteor篇(四):RPC方法注册及调用-更轻量的服务接口提供方式
RPC机制通过前后端的`callAsync`方法实现了高效的数据交互。后端通过`Meteor.methods()`注册方法,支持异步操作;前端使用`callAsync`调用后端方法,代码更简洁、易读。本文详细介绍了Methods注册机制、异步支持及最佳实践。
|
2月前
|
前端开发 JavaScript
前端基础(九)_this基本使用、this指向判断、改变this指向的方法
本文介绍了JavaScript中this的基本使用、this指向的判断以及改变this指向的方法。
44 1
前端基础(九)_this基本使用、this指向判断、改变this指向的方法
|
2月前
|
前端开发
前端基础(十四)_隐藏元素的方法
本文介绍了几种在前端开发中隐藏元素的方法,包括使用`display:none`、`visibility:hidden`、`opacity:0`等CSS属性,并提供了相应的示例代码。此外,还提到了其他隐藏元素的技巧,如通过设置元素位置、使用`overflow`属性和`filter`属性以及`rgba`颜色值来实现元素的隐藏。
66 1
前端基础(十四)_隐藏元素的方法
|
1月前
|
前端开发 JavaScript
掌握微前端架构:构建现代Web应用的新方法
本文介绍了微前端架构的概念及其在现代Web应用开发中的优势与实施方法。微前端架构通过将应用拆分成独立模块,提升了开发效率和灵活性。其核心优势包括技术栈灵活性、独立部署、团队协作及易于维护。文章详细阐述了定义边界、选择框架、管理状态和通信等关键步骤,并讨论了状态同步、样式隔离及安全性等挑战。微前端架构有望成为未来Web开发的重要趋势。
|
1月前
|
JavaScript 前端开发 应用服务中间件
vue前端开发中,通过vue.config.js配置和nginx配置,实现多个入口文件的实现方法
vue前端开发中,通过vue.config.js配置和nginx配置,实现多个入口文件的实现方法
140 0
|
1月前
|
存储 前端开发 API
前端开发中,Web Storage的存储数据的方法localstorage和sessionStorage的使用及区别
前端开发中,Web Storage的存储数据的方法localstorage和sessionStorage的使用及区别
92 0
|
2月前
|
前端开发
前端基础(十一)_Float浮动、清除浮动的几种方法
本文介绍了浮动的概念、属性、特性以及清除浮动的几种方法,并通过实例演示了如何使用CSS实现元素的浮动和处理浮动带来的问题。
78 3
|
1月前
|
前端开发
前端常用方法防抖(debounce)和节流(throttle)的示例演示及应用场景说明
前端常用方法防抖(debounce)和节流(throttle)的示例演示及应用场景说明
23 0
|
2月前
|
前端开发 JavaScript
前端ES5 | js —添加元素方法
前端ES5 | js —添加元素方法
|
3月前
|
JavaScript 前端开发 开发者
JS 继承之谜:究竟有哪些神秘方法?Web 前端开发者必知的关键技巧待你揭开谜底!
【8月更文挑战第23天】JavaScript (JS) 是 Web 前端开发的关键语言,其中继承是面向对象编程的重要概念。本文探讨了 JS 中几种继承机制:原型链继承、构造函数继承及组合继承。原型链继承利用原型对象实现属性和方法的共享;构造函数继承通过在子类构造器内调用父类构造器实现私有属性的复制;组合继承结合两者优点,既支持属性共享又避免了属性被意外覆盖的风险。理解这些模式有助于开发者更高效地组织代码结构,提升程序质量。
35 1