logo

常见 ES6 语法的简单用法

Sat Apr 02 2022 Posted 2 years ago

本文总结于 2021年12月17日,用法比较偏基础,并没有什么实际的干货,唯一的价值可能就是让我的博客数量 +1~

一、解构赋值 #

<1> 对象和数组

const obj = {
  a: 1,
  b: 2,
  c: 3
}
const { a, b, c } = obj // 等价于 const a = 1; const b = 2; const c = 3;
/********************************/
const arr = [1, 2, 3]
const [a, b, c] = arr // 等价于 const a = 1; const b = 2; const c = 3;

<2> 深度解构

const obj = {
  a: 0,
  b: {
    c: 1
  }
}
const { b: { c } } = obj // 等价于 const c = 1    tip: b is not defined

<3> 解构时使用别名

const obj = {
  a: 1,
  b: 2,
  c: 3
}
const { a: count } = obj // 等价于 const count = 1

<5> 变量互换

const a = 1
const b = 2
  [b, a] = [a, b]

<5> 解构的对象不能为 undefinednull

const {a, b, c} = obj || {}

二、...(拓展运算符) #

const arr1 = [1, 2, 3]
const arr2 = [3, 4, 5, 6]
// const mixArr = [...newSet(arr1.concat(arr2))]
const mixArr = [...new Set([...a, ...b])]
/********************************/
const obj1 = { a: 1 }
const obj2 = { b: 1 }
// const mixObj = Object.assign({}, obj1, obj2)
const mixObj = { ...obj1, ...obj2 }

结合拓展运算符有条件的添加对象的属性:

// 此处可以将 isEmpty 封装为函数
/*
    const isEmpty = (field) => this[field] === ''
*/
const isEmpty = this.keyword === ''
const searchCondition = {
  ...(isEmpty && { keyword: this.keyword }),
}

三、Object.hasOwn #

用于判断对象上是否存在某个属性(需要注意兼容性,最好配合 polyfill 使用)

const person = {
  name: 'sehci',
  age: 21
}
Object.hasOwn(person, 'name') // true
Object.hasOwn(person, 'gender') // false
// Object.hasOwn 本质上是语法糖,等价于以下代码
Object.prototype.hasOwnProperty.call(person, 'name') // true

四、includes #

includes 是数组上的一个方法,用于判断一个数组是否包含一个指定的值,返回值为 boolean

// bad
if (a === 1 || a === 2 || a === 3 || a === 4) {
  // ...
}
// good
if ([1, 2, 3, 4].includes(a)) {
  // ...
}

includes 可以接收两个参数: <1> valueToFind 需要查找的元素值 <2> fromIndex 从某个索引开始遍历查找

需要注意的地方是 fromIndex 可以为负数

// arr's length is 3
// fromIndex is -100
// computed index is 3 + (-100) = -97
const arr = [1, 2, 3]

arr.includes('a', -100) // true
arr.includes('a', -2) // false

五、?. (可选链操作符) #

可选链操作符( ?. )允许读取位于对象链深处的属性的值,而不必明确验证链中的每个引用是否有效。

const person = {
  name: 'sechi',
  age: 21,
  cat: {
    name: 'kiki'
  }
}
// bad
const dogName = person.dog && person.dog.name
// good
const dogName = person.dog?.name
console.log(dogName) // undefined

可选链操作符不仅能用于对象,还可以用于函数的调用

const someInterface = {
  someMethod: () => 'call successfully!'
}
const result1 = someInterface.anotherMethod?.() // undefined

const result2 = someInterface.anotherMethod() // someInterface.anotherMethod is not a function

六、??(空值合并运算符) #

空值合并操作符(??)是一个逻辑操作符,当左侧的操作数为 null 或者 undefined 时,返回其右侧操作数,否则返回左侧操作数。注意:它和逻辑或操作符(||)不同,逻辑或操作符会在左侧操作数为假值(如false, 0, '', NaN)时返回右侧操作数。

const nullValue = null
const emptyString = '' // 空字符串,是一个假值,Boolean("") === false
const num = 42

const valA = nullValue ?? 'valA 的默认值'
const valB = emptyString ?? 'valB 的默认值'
const valC = num ?? 0

console.log(valA) // "valA 的默认值"
console.log(valB) // ""(空字符串虽然是假值,但不是 null 或者 undefined)
console.log(valC) // 42

实际开发中可以用它来简化输入框的非空判断:

// bad
if (value !== null && value !== undefined && value !== '') {
  // ...
}
// good
if ((value ?? '') !== '') {
  // ...
}

Tip: ?? 不可以直接与 &&|| 组合使用,原因是空值合并操作符和其他逻辑操作符之间的运算优先级/运算顺序是未定义的。组合使用时需要使用括号来显式地表明优先级

null || undefined ?? 'foo' // 抛出 SyntaxError
(null || undefined) ?? 'foo' // 返回 "foo"

七、Object.entries / Object.keys / Object.values / Object.fromEntries #

Object.entries / Object.keys / Object.values 这三个方法都可以将对象转换为数组,并且只会遍历自身的属性而不会遍历原型链中的属性。

<1> Object.entries()方法返回一个给定对象自身可枚举属性的键值对数组。

// 简单示例
const obj = { 0: 'a', 1: 'b', 2: 'c' }
console.log(Object.entries(obj)) // [ ['0', 'a'], ['1', 'b'], ['2', 'c'] ]

// 如果 key 可以被排序,那么遍历的顺序会由 key 决定
const anObj = { 100: 'a', 2: 'b', 7: 'c' }
console.log(Object.entries(anObj)) // [ ['2', 'b'], ['7', 'c'], ['100', 'a'] ]

// getFoo 并不是 myObj 的可枚举的属性,所以不会被遍历
const myObj = Object.create({}, { getFoo: { value() { return this.foo } } })
myObj.foo = 'bar'
console.log(Object.entries(myObj)) // [ ['foo', 'bar'] ]

// 如果传入的参数类型不是对象,则会被强制转换为对象类型
console.log(Object.entries('foo')) // [ ['0', 'f'], ['1', 'o'], ['2', 'o'] ]

// 如何优雅地迭代键值对~
const obj = { a: 5, b: 7, c: 9 }
for (const [key, value] of Object.entries(obj))
  console.log(`${key} ${value}`) // "a 5", "b 7", "c 9"

// 梅开二度
Object.entries(obj).forEach(([key, value]) => {
  console.log(`${key} ${value}`) // "a 5", "b 7", "c 9"
})

<2> Object.keys() 方法会返回一个由一个给定对象的自身可枚举属性组成的数组。

// 如果参数为数组,那么会返回由索引组成的数组
const arr = ['a', 'b', 'c']
console.log(Object.keys(arr)) // console: ['0', '1', '2']

// 简单示例
const obj = { 0: 'a', 1: 'b', 2: 'c' }
console.log(Object.keys(obj)) // console: ['0', '1', '2']

// 如果 key 可以被排序,那么遍历的顺序会由 key 决定
const anObj = { 100: 'a', 2: 'b', 7: 'c' }
console.log(Object.keys(anObj)) // console: ['2', '7', '100']

// getFoo 并不是 myObj 的可枚举的属性,所以不会被遍历
const myObj = Object.create({}, {
  getFoo: {
    value() { return this.foo }
  }
})
myObj.foo = 1
console.log(Object.keys(myObj)) // console: ['foo']

<3> Object.values()方法返回一个给定对象自身的所有可枚举属性值的数组。

// 简单示例
const obj = { foo: 'bar', baz: 42 }
console.log(Object.values(obj)) // ['bar', 42]

// 如果 key 可以被排序,那么遍历的顺序会由 key 决定
const an_obj = { 100: 'a', 2: 'b', 7: 'c' }
console.log(Object.values(an_obj)) // ['b', 'c', 'a']

// getFoo 并不是 myObj 的可枚举的属性,所以不会被遍历
const my_obj = Object.create({}, { getFoo: { value() { return this.foo } } })
my_obj.foo = 'bar'
console.log(Object.values(my_obj)) // ['bar']

// 如果传入的参数类型不是对象,则会被强制转换为对象类型
console.log(Object.values('foo')) // ['f', 'o', 'o']

<4> Object.fromEntries() 方法把键值对列表转换为一个对象。执行的操作与 Object.fromEntries 相反

// Map 转化为 Object
const map = new Map([['foo', 'bar'], ['baz', 42]])
const obj = Object.fromEntries(map)
console.log(obj) // { foo: "bar", baz: 42 }

// Array 转化为 Object
const arr = [['0', 'a'], ['1', 'b'], ['2', 'c']]
const obj = Object.fromEntries(arr)
console.log(obj) // { 0: "a", 1: "b", 2: "c" }

// 优雅地用数组方法处理对象~
const object1 = { a: 1, b: 2, c: 3 }
const object2 = Object.fromEntries(
  Object.entries(object1)
    .map(([key, val]) => [key, val * 2])
)
console.log(object2) // { a: 2, b: 4, c: 6 }