es6在开发中的技巧应用

1. 对于多个条件,使用 Array.includes

假设我们想要在函数中检查任务类型taskType是nrm 还是 pm。那么代码可能是这样的:

const checkTaskType = (taskType) => {
    if(taskType === 'nrm' || taskType === 'pm') { 
        console.log('tasktype checked')
    }
}

checkTaskType('nrm'); // 输出 'tasktype checked'

考虑到我们只有两个模型,这么做似乎也还能接受,但如果我们还想要检查另一个或者是几个模型呢?如果我们增加更多 '||'语句,那么代码将变得难以维护,且不够整洁。为了让它更加简洁,我们可以像这样重写函数:

const checkOmcType = (omcType) => {
    if(['nrm', 'pm'].includes(omcType)) { 
        console.log('omcType checked')
    }
}

checkOmcType('pm'); // 输出 'omcType checked'

上面的代码看起来已经很漂亮了。为了更进一步改善它,我们可以创建一个变量来存放所有的任务类型:

const checkOmcType = (omcType) => {
    const omcTypes = ['nrm', 'pm', 'alarm']

    if(omcTypes.includes(omcType)) { 
        console.log('omcType checked')
    } else console.log('omcType checked fail')
}

checkOmcType('alarm'); // 输出 'omcType checked'
checkOmcType('test'); // 不输出 'omcType checked fail'

现在,如果我们想要检查更多的任务类型,只需要添加一个新的元素即可。此外,如果它很重要的话,我们还可以将 omcTypes变量定义在函数作用域外,并在需要的地方重用。这种方式可以让我们集中管理,并使维护变得轻而易举,因为我们只需在代码中更改一个位置。

2. 匹配所有条件,使用 Array.every 或者 Array.find

在本例中,我们想要检查传入的任务状态是否是已有的状态类型。为了以更加命令式的方式实现,我们也许会这么做:

const omcTaskStatus = [
  {name: '待采集', value: 'INITIALING'},
  {name: '采集中', value: 'RUNNING'},
  {name: '停止', value: 'STOPPED'},
  {name: '失败', value: 'ERROR'}
]
const checkEveryTaskStatus = (taskStatusValue) => {
  let isValid = false
  for (let omcTask of omcTaskStatus) {
    if (isValid) {
      break
    }
    isValid = omcTask.value === taskStatusValue
  }
  return isValid
}
console.log(checkEveryTaskStatus('test')) // 输出 false
console.log(checkEveryTaskStatus('RUNNING')) // 输出 true

如果你不关心其背后发生了什么,那么你可以重写上面的函数并使用Array.some来达到相同的结果。
const checkEveryTaskStatus = (taskStatusValue) => {
return omcTaskStatus.some(omcTask => omcTask.value === ta
}
console.log(checkEveryTaskStatus(‘test’)) // 输出 false
console.log(checkEveryTaskStatus(‘RUNNING’)) // 输出 true

3. 使用索引或者映射,而不是 switch 语句

假设我们想通过传入omc类型,获取omc中包含的任务类型

// 获取资源、性能、告警中包含的任务类型                                           
const getTaskTypeByOmc3 = (state) => {                                               
  switch (state) {                                                                   
    case 'nrm':                                                                      
      return ['ftp', 'gsmFile']                                                      
    case 'pm':                                                                       
      return ['ftp', 'database', 'gsmDatabase']                                      
    case 'alarm':                                                                    
      return ['socket', 'corba', 'gsmAlarm']                                         
    default:                                                                         
      return []                                                                      
  }                                                                                  
}                                                                                    

上诉代码可以重构,完全去除 switch 语句。

const taskType = new Map()                                               
  .set('nrm', ['ftp', 'gsmFile'])                                        
  .set('pm', ['ftp', 'database', 'gsmDatabase'])                         
  .set('alarm', ['socket', 'corba', 'gsmAlarm'])                         
                                                                         
const taskType1 = {                                                      
  nrm: ['ftp', 'gsmFile'],                                               
  pm: ['ftp', 'database', 'gsmDatabase'],                                
  alarm: ['socket', 'corba', 'gsmAlarm'],                                
}                                                                        
                                                                         
const getTaskTypeByOmc = (omcType) => {                                  
  return taskType.get(omcType) || []                                     
}                                                                        
                                                                         
console.log(getTaskTypeByOmc()); // 输出 []                                
console.log(getTaskTypeByOmc('nrm')); // 输出 ['ftp', 'gsmFile']           
console.log(getTaskTypeByOmc('')); // 输出 []                              

4. 平铺多维数组

使用 Spread(展开),可以很容易去平铺嵌套多维数组:


const arr = [11, [22, 33], [44, 55], 66];
const flatArr = [].concat(...arr); //=> [11, 22, 33, 44, 55, 66]

可惜,上面的方法仅仅适用于二维数组。不过,通过递归,我们可以平铺任意维度的嵌套数组。

function flattenArray(arr) {
  const flattened = [].concat(...arr);
  return flattened.some(item => Array.isArray(item)) ? 
    flattenArray(flattened) : flattened;
}
 
const arr = [11, [22, 33], [44, [55, 66, [77, [88]], 99]]];
const flatArr = flattenArray(arr); 
//=> [11, 22, 33, 44, 55, 66, 77, 88, 99]

5. 函数默认值

doSomething({ foo: 'Hello', bar: 'Hey!', baz: 42 });

// bad
function doSomething(config) {
  const foo = config.foo !== undefined ? config.foo : 'Hi';
  const bar = config.bar !== undefined ? config.bar : 'Yo!';
  const baz = config.baz !== undefined ? config.baz : 13;
}

// good
function doSomething({ foo = 'Hi', bar = 'Yo!', baz = 13 }) {
  ...
}

// better
function doSomething({ foo = 'Hi', bar = 'Yo!', baz = 13 } = {}) {
  ...
}

6. arguments 转数组

// bad
function sortNumbers() {
  return Array.prototype.slice.call(arguments).sort();
}

// good
const sortNumbers = (...numbers) => numbers.sort();

7. 构建对象

剔除部分属性,将剩下的属性构建一个新的对象

// bad
function pick(data) {
  const { id, name, age} = data
  const res = { guid: id }
  if (name) {
    res.name = name
  }
  else if (age) {
    res.age = age
  }
  return res
}

// good
function pick({id, name, age}) {
  return {
    guid: id,
    ...(name && {name}),
    ...(age && {age})
  }
}

8. 对象的基本解构

// bad
handleEvent = () => {
  this.setState({
    data: this.state.data.set("key", "value")
  })
};

// good
handleEvent = () => {
  this.setState(({data}) => ({
    data: data.set("key", "value")
  }))
};

9. 对象深度解构

// bad
function test(fruit) {
  if (fruit && fruit.name)  {
    console.log (fruit.name);
  } else {
    console.log('unknown');
  }
}

// good
function test({name} = {}) {
  console.log (name || 'unknown');
}

10. 数组解构

// bad
const splitLocale = locale.split("-");
const language = splitLocale[0];
const country = splitLocale[1];

// good
const [language, country] = locale.split('-');

11. optional-chaining

const obj = {
  foo: {
    bar: {
      baz: 42,
    },
  },
};

const baz = obj?.foo?.bar?.baz; // 42

同样支持函数:

function test() {
  return 42;
}
test?.(); // 42

exists?.(); // undefined

需要添加 @babel/plugin-proposal-optional-chaining 插件支持

12. 对象解构

12.1 删除不需要的属性
有时候你不希望保留某些对象属性,你可能会枚举整个对象然后删除它们,但实际上只需要简单的将这些无用属性赋值给变量,然后把想要保留的有用部分作为剩余参数就可以了。

下面的代码里,我们希望删除id,provinceName和name参数,只保留network相关的信息。

let {id, name, provinceName,...networkObject} = {
    id: 396,
    name: "collenciton-test16",
    provinceName: "上海",
    networkElement: "MME",
    networkType: "4G",
    networkVersion: "V1",
    networkName: "核心网"};

console.log(networkObject); // {networkElement: "MME",networkType: "4G",networkVersion: "V1",networkName: "核心网"}

13. 必须传值的解构参数

function setCookie(name, value, {
    secure,
    path,
    domain,
    expires
}) {
    //  设置cookie的代码
}
setCookie('type', 'js') // 报错

在此函数内,name与value参数是必须的,而secure、path、domain与expires则不是。默认情况下调用函数时未给参数解构传值会抛出错误。像上例中如果setCookie不传第三个参数,就会报错。
若解构参数是可选的,可以给解构的参数提供默认值来处理这种错误。

function setCookie(name, value, {
    secure,
    path,
    domain,
    expires
} = {}) {
    //  设置cookie的代码
}
setCookie('type', 'js') // 不会报错

14. 在函数参数中解构嵌套对象

使用类似于对象字面量的语法,可以深入到嵌套的对象结构中去提取你想要的数据。
在下面的代码中,rows是对象scanLog中嵌套的一个对象。如果我们对rows的createTime属性感兴趣,使用解构赋值可以很轻松地得到它。

var scanLog = {
  id: '000012138',
  rows: {
    clazz: 'com.chinamobile.cmss.oss4.ftpscanner.entrance.FtpScannerTask',
    turbo: true,
    createTime: 1562893502465
  },
  tags: ['tag']
}
const idAndCreateTime = ({id, rows: {createTime}}) => {
  console.log(`id: ${id} createTime: ${createTime}`);
}
idAndCreateTime(scanLog); // => id: 000012138  createTime: 1562893502465

15. 合并对象

ES6带来了扩展运算符(…)。它一般被用来解构数组,但你也可以用它处理对象。

可以使用扩展运算符来展开一个新的对象,第二个对象中的属性值会改写第一个对象的属性值。比如object2的b和c就会改写object1的同名属性。

let array1 = [{name: '服务器北向IP地址', value: 'host'},
        {name: '端口号', value: 'port'}]
let array2 = [{name: '文件接口协议', value: 'omcProtocol'},
        {name: '文件目录', value: 'dir'}]
let mergedArray = […object1, …object2]
console.log(merged) 
// [{name: '服务器北向IP地址', value: 'host'},{name: '端口号', value: 'port'},{name: '文件接口协议', value: 'omcProtocol'}, {name: '文件目录', value: 'dir'}]

16. Sets

使用Set实现数组去重
在ES6中,因为Set只存储唯一值,所以你可以使用Set删除重复项。

let arr = [1, 1, 2, 2, 3, 3];
let deduped = [...new Set(arr)] // [1, 2, 3]

17. 验证函数的简化示例

function validate(values) {
  if(!values.first)
    return false;
  if(!values.last)
    return false;
  return true;
}
console.log(validate({first:'Bruce',last:'Wayne'})); // true

上面的函数完美的完成验证工作。但是当有很多表单,则需要应用验证,此时会有不同的字段和规则。如果可以构建一个在运行时配置的通用验证函数,会是一个好选择。

// object validation rules
const schema = {
  first: {
    required:true
  },
  last: {
    required:true
  }
}

// universal validation function
const validate = (schema, values) => {
  for(field in schema) {
    if(schema[field].required) {
      if(!values[field]) {
        return false;
      }
    }
  }
  return true;
}
console.log(validate(schema, {first:'Bruce'})); // false
console.log(validate(schema, {first:'Bruce',last:'Wayne'})); // true

现在有了这个验证函数,我们就可以在所有窗体中重用,而无需为每个窗体编写自定义验证函数。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值