JavaScript 2019 新特性和使用技巧

JavaScript 作為最流行的編程語(yǔ)言,也是web開(kāi)發(fā)的主要內(nèi)容。每次迭代都會(huì)出現(xiàn)新穎、便捷的特性。下面介紹2019新特性及其在一些場(chǎng)景下更簡(jiǎn)便的使用技巧。

# Array.flat()

flat()將嵌套數(shù)組遞歸展平到指定的深度。默認(rèn)參數(shù)值為1,如果要進(jìn)行全深度,參數(shù)設(shè)成Infinity。此方法不修改原始數(shù)組,而是創(chuàng)建一個(gè)新數(shù)組。

const arr1 = [1, 2, [3, 4]]
arr1.flat() // [1, 2, 3, 4]

const arr2 = [1, 2, [3, 4, [5, 6]]]
arr2.flat() // [1, 2, 3, 4, [5, 6]]

const arr3 = [1, 2, [3, 4, [5, 6]]]
arr3.flat(2) // [1, 2, 3, 4, 5, 6]

const arr4 = [1, 2, [3, 4, [5, 6, [7, 8]]]]
arr4.flat(Infinity) // [1, 2, 3, 4, 5, 6, 7, 8]

如果原數(shù)組有空位,flat()方法會(huì)跳過(guò)空位。

const arr5 = [1, 2, , 4, 5]
arr5.flat() // [1, 2, 4, 5]

Usage

將下列數(shù)組中所有students中的項(xiàng)整合成一個(gè)扁平化一維數(shù)組

const courses = [
  {
    subject: "math",
    numberOfStudents: 3,
    waitlistStudents: 2,
    students: ['Janet', 'Martha', 'Bob', ['Phil', 'Candace']]
  },
  {
    subject: "english",
    numberOfStudents: 2,
    students: ['Wilson', 'Taylor']
  },
  {
    subject: "history",
    numberOfStudents: 4,
    students: ['Edith', 'Jacob', 'Peter', 'Betty']
  }
]
1. 以前的實(shí)現(xiàn)方式:
const courseStudents = courses.map(course => course.student)
// [
//   [ 'Janet', 'Martha', 'Bob', [ 'Phil', 'Candace' ] ],
//   [ 'Wilson', 'Taylor' ],
//   [ 'Edith', 'Jacob', 'Peter', 'Betty' ]
// ]
const tempArr = [].concat.apply([], courseStudents)

;[].concat(...tempArr)

以上方式僅僅是二維數(shù)組實(shí)現(xiàn)起來(lái)都已經(jīng)比較復(fù)雜了,對(duì)于多維數(shù)組通過(guò)遞歸的方式更復(fù)雜了。而通過(guò) flat() 一行代碼即可搞定。

2. 通過(guò) flat 實(shí)現(xiàn)
courses.map(course => course.student).flat(Infinity)
// [
//   'Janet',   'Martha',
//   'Bob',     'Phil',
//   'Candace', 'Wilson',
//   'Taylor',  'Edith',
//   'Jacob',   'Peter',
//   'Betty'
// ]

# Array.flatMap()

flatMap()方法對(duì)原數(shù)組的每個(gè)成員執(zhí)行一個(gè)函數(shù)(相當(dāng)于執(zhí)行map()),然后對(duì)返回值組成的數(shù)組執(zhí)行flat()方法。該方法返回一個(gè)新數(shù)組,不改變?cè)瓟?shù)組。

const arr1 = [1, 2, 3];

arr1.map(x => [x * 4]); // [[4], [8], [12]]
arr1.flatMap(x => [x * 4]); // [4, 8, 12]

flatMap()只能展開(kāi)一層數(shù)組。

[1, 2, 3, 4].flatMap(x => [[x * 2]]) 
// [[2], [4], [6], [8]]

flatMap()方法的參數(shù)是一個(gè)遍歷函數(shù),該函數(shù)可以接受三個(gè)參數(shù),分別是當(dāng)前數(shù)組成員、當(dāng)前數(shù)組成員的位置(從零開(kāi)始)、原數(shù)組。
flatMap()方法還可以有第二個(gè)參數(shù),用來(lái)綁定遍歷函數(shù)里面的this。

Usage

將下列數(shù)組中每一項(xiàng)加7,然后插入當(dāng)前元素之后。

const grades = [78, 62, 80, 64]
實(shí)現(xiàn)方式:
  1. map/concat
const curved = grades.map(grade => [grade, grade + 7])
// [ [ 78, 85 ], [ 62, 69 ], [ 80, 87 ], [ 64, 71 ] ]

;[].concat.apply([], curved)
// [ 78, 85, 62, 69, 80, 87, 64, 71 ]
  1. map/flat
grades.map(grade => [grade, grade + 7]).flat()
  1. flatMap (相當(dāng)于先map, 再flat(1))
grades.flatMap(grade => [grade, grade + 7])

如果將加7之后的結(jié)果放入數(shù)組,然后插入當(dāng)前項(xiàng)之后。

grades.flatMap(grade => [grade, [grade + 7]])
// [
//   78, [ 85 ],
//   62, [ 69 ],
//   80, [ 87 ],
//   64, [ 71 ]
// ]

# String.trimStart() 和 String.trimEnd()

trim() 是刪除字符串兩邊的空格,而 trimStart() 和 trimEnd() 刪除字符串開(kāi)頭和末尾由空格鍵、tab 鍵、換行符和不可見(jiàn)的空白符號(hào)產(chǎn)生的空格。

const test = " hello "

test.trim()       // "hello"
test.trimStart()  // "hello "
test.trimEnd()    // " hello"

# Object.fromEntries

Object.fromEntries()是Object.entries()的逆操作,用于將一個(gè)鍵值對(duì)數(shù)組轉(zhuǎn)為對(duì)象。

1. Object.entries()

const obj = { bar: 'bar', foo: 'foo' }
const array = Object.entries(obj);
// [["prop1", 2], ["prop2", 10], ["prop3", 15]]

2. Object.fromEntries()

Object.fromEntries([
  ['foo', 'bar'],
  ['baz', 42]
])
// { foo: "bar", baz: 42 }

該方法的主要目的,是將鍵值對(duì)的數(shù)據(jù)結(jié)構(gòu)還原為對(duì)象,因此特別適合將 Map 結(jié)構(gòu)轉(zhuǎn)為對(duì)象。

const entries = new Map([
  ['foo', 'bar'],
  ['baz', 42]
]);

Object.fromEntries(entries)
// { foo: "bar", baz: 42 }

Usage

將屬性值大于20的項(xiàng)組成一個(gè)新對(duì)象

let students = {
  amelia: 20,
  beatrice: 22,
  cece: 20,
  deirdre: 19,
  eloise: 21
}
1. 傳統(tǒng)方式
const overTwenty = Object.entries(students).filter(([name, age]) => age > 20) 
const DrinkingAgeStudents = {}

for (const [name, age] of overTwentyOne) {
  DrinkingAgeStudents[name] = age
}
2. Object.fromEntries()
Object.fromEntries(overTwenty)

# catch 參數(shù)可選

新特性允許忽略catch() 參數(shù),因?yàn)樵诤芏嗲闆r下并不會(huì)用到。

try {
  //...
} catch {
  //handle error without parameter
}

# Symbol.description

為了區(qū)分Symbol,通過(guò)給參數(shù)添加描述,讀取描述時(shí)需要講Symbol轉(zhuǎn)成字符串:

const symbol = Symbol('foo');

String(symbol) // "Symbol(foo)"
symbol.toString() // "Symbol(foo)"

ES2019 提供了一個(gè)實(shí)例屬性description,直接返回 Symbol 的描述。

const symbol = Symbol('foo');

symbol.description // "foo"

# Function.toString()

以前toString()方法會(huì)省略注釋和空格。

function /* foo comment */ foo () {}

foo.toString()
// function foo() {}

ES2019 返回一模一樣的原始代碼。

function /* foo comment */ foo () {}
foo.toString(); // "function /* foo comment */ foo () {}"

# JSON.parse() 改進(jìn)

行分隔符 (\u2028) 和段落分隔符 (\u2029),現(xiàn)在被正確解析,而不是報(bào)一個(gè)語(yǔ)法錯(cuò)誤。

const str = '{"name":"Bottle\u2028AnGe"}'
JSON.parse(str)
/* {name: "Bottle
AnGe"}
/*

# JavaScript optional chaining

我們?cè)陂_(kāi)發(fā)中經(jīng)常會(huì)得到缺少預(yù)期屬性的對(duì)象,甚至整個(gè)對(duì)象都是null。因此,如果我們的某個(gè)對(duì)象沒(méi)有所需的屬性,并且我們嘗試訪問(wèn)其屬性的屬性,則會(huì)報(bào)錯(cuò):

const user = {
  address: {
    // city: {
    //   name: "London",
    //   code: 20
    // }
  }
};

const cityCode = user.address.city.code;
// Uncaught TypeError: Cannot read property code of undefined
通常的解決方式:
  1. 檢查對(duì)象中某個(gè)屬性是否存在:
const cityCode1 = user.address && user.address.city && user.address.city.code;

const cityCode2 = (((user || {}).address || {}).city || {}).code;

try {
  const cityCode3 = user.address.city.code;
} catch (e) {}

或者使用類似于lodash的三方工具庫(kù):

import _ from "lodash";

_.get(cityCode, "user.address.city.code");
  1. 新增特性 可選鏈?zhǔn)竭\(yùn)算符 ?

使用可選的鏈接運(yùn)算符來(lái)檢測(cè)左側(cè)的屬性是否有值,如果值為null 或 undefined,則短路并返回undefined。這樣就可以安全放心的使用深層嵌套對(duì)象的屬性,即便它們可能不存在,我們將 ?鏈接到我們想要訪問(wèn)的屬性即可。

const user = {
  address: {
    city: {
      name: "London"
      //code: 20
    }
  },
  firstName: "Jane",
  lastName: "Doe",
  getFullName() {
    return `${this.firstName} ${this.lastName}`;
  }
};

user?.address?.city?.code; // undefined

使用括號(hào)表示,獲取動(dòng)態(tài)添加的屬性

let prop = "address";

user?.[prop]?.city?.name; // “London”

甚至可以調(diào)用可能不存在的函數(shù):

user?.getFullName?.(); // "Jane Doe"

還可訪問(wèn)數(shù)組中的元素

const arr = ["Jane", "Mark", "Joan"];
arr?.[1] // 'Mark'

或者刪除屬性

delete user?.address?.city?.code; 
  1. Babel插件

該功能長(zhǎng)期以來(lái)一直是C#,Groovy和Swift等許多語(yǔ)言的一部分,它最終在不久的將來(lái)會(huì)出現(xiàn)在JavaScript中。但是,如果您現(xiàn)在想要開(kāi)始使用它,那么Babel的人們會(huì)為您提供他們的插件。只需確保使用Babel7并安裝插件:

npm install --save-dev @babel/plugin-proposal-optional-chaining

然后將其添加到.babelrc配置中:

{
  "plugins": ["@babel/plugin-proposal-optional-chaining"]
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容