ES6 經常使用方法概覽

整理自阮一峯 ECMAScript 入門html

模板字符串

  1. 模板字符串(template string)是加強版的字符串,用反引號(`)標識。它能夠看成普通字符串使用,也能夠用來定義多行字符串,或者在字符串中嵌入變量。
  2. 模板字符串,都是用反引號表示。若是在模板字符串中須要使用反引號,則前面要用反斜槓轉義。
  3. 若是使用模板字符串表示多行字符串,全部的空格和縮進都會被保留在輸出之中。
  4. 全部模板字符串的空格和換行,都是被保留的,好比<ul>標籤前面會有一個換行。若是你不想要這個換行,可使用trim方法消除它。
$('#list').html(`
<ul>
  <li>first</li>
  <li>second</li>
</ul>
`.trim());
複製代碼

字符串新增方法

實例方法:includes(), startsWith(), endsWith()

  1. includes():返回布爾值,表示是否找到了參數字符串。
  2. startsWith():返回布爾值,表示參數字符串是否在原字符串的頭部。
  3. endsWith():返回布爾值,表示參數字符串是否在原字符串的尾部。 這三個方法都支持第二個參數,表示開始搜索的位置。
let s = 'Hello world!';

s.startsWith('world', 6) // true
s.endsWith('Hello', 5) // true
s.includes('Hello', 6) // false
複製代碼

上面代碼表示,使用第二個參數n時,endsWith的行爲與其餘兩個方法有所不一樣。它針對前n個字符,而其餘兩個方法針對從第n個位置直到字符串結束。node

實例方法:repeat()

repeat方法返回一個新字符串,表示將原字符串重複n次。es6

'x'.repeat(3) // "xxx"
'hello'.repeat(2) // "hellohello"
'na'.repeat(0) // ""
複製代碼

實例方法:padStart(),padEnd()

ES2017 引入了字符串補全長度的功能。若是某個字符串不夠指定長度,會在頭部或尾部補全。padStart()用於頭部補全,padEnd()用於尾部補全。 padStart()和padEnd()一共接受兩個參數,第一個參數是字符串補全生效的最大長度,第二個參數是用來補全的字符串。正則表達式

'x'.padStart(4, 'ab') // 'abax'
'x'.padEnd(5, 'ab') // 'xabab'
複製代碼

padStart()的常見用途是爲數值補全指定位數。下面代碼生成 10 位的數值字符串。算法

'1'.padStart(10, '0') // "0000000001"
'12'.padStart(10, '0') // "0000000012"
'123456'.padStart(10, '0') // "0000123456"
複製代碼

實例方法:trimStart(),trimEnd()

ES2019 對字符串實例新增了trimStart()和trimEnd()這兩個方法。它們的行爲與trim()一致,trimStart()消除字符串頭部的空格,trimEnd()消除尾部的空格。它們返回的都是新字符串,不會修改原始字符串。編程

const s = ' abc ';

s.trim() // "abc"
s.trimStart() // "abc "
s.trimEnd() // " abc"
複製代碼

實例方法:matchAll()

matchAll()方法返回一個正則表達式在當前字符串的全部匹配。 若是一個正則表達式在字符串裏面有多個匹配,如今通常使用g修飾符或y修飾符,在循環裏面逐一取出。ES6增長了String.prototype.matchAll()方法,能夠一次性取出全部匹配。不過,它返回的是一個遍歷器(Iterator),而不是數組。數組

const string = 'test1test2test3';

// g 修飾符加不加均可以
const regex = /t(e)(st(\d?))/g;

for (const match of string.matchAll(regex)) {
  console.log(match);
}
// ["test1", "e", "st1", "1", index: 0, input: "test1test2test3"]
// ["test2", "e", "st2", "2", index: 5, input: "test1test2test3"]
// ["test3", "e", "st3", "3", index: 10, input: "test1test2test3"]
複製代碼

遍歷器轉爲數組是很是簡單的,使用...運算符和Array.from()方法就能夠了。安全

// 轉爲數組方法一
[...string.matchAll(regex)]

// 轉爲數組方法二
Array.from(string.matchAll(regex))
複製代碼

數值的擴展

二進制和八進制表示法

ES6 提供了二進制和八進制數值的新的寫法,分別用前綴0b(或0B)和0o(或0O)表示。bash

0b111110111 === 503 // true
0o767 === 503 // true
複製代碼

若是要將0b和0o前綴的字符串數值轉爲十進制,要使用Number方法。markdown

Number('0b111')  // 7
Number('0o10')  // 8
複製代碼

擴展:Number 對象

Number對象能夠將任何數據類型轉換成數值,包括 布爾值,日期,二進制數,八進制數,數字字符串(parseInt,parseFloat只能夠轉化數字字符串)。

Number 對象的方法

  1. Number.isNaN() 肯定傳遞的值是不是 NaN。(ES6新增)
  2. Number.isFinite() 肯定傳遞的值類型及自己是不是有限數。(ES6新增)
  3. Number.isInteger() 肯定傳遞的值類型是「number」,且是整數。
  4. Number.isSafeInteger() 肯定傳遞的值是否爲安全整數 ( -(253 - 1) 至 253 - 1之間)。
  5. Number.toInteger() 計算傳遞的值並將其轉換爲整數 (或無窮大)。
  6. Number.parseFloat() 和全局對象 parseFloat() 同樣。
  7. Number.parseInt() 和全局對象 parseInt() 同樣。

擴展:Math 對象

  1. Math.trunc 方法用於去除一個數的小數部分,返回整數部分。(對於非數值,會先使用Number將其轉換爲數值。)
  2. Math.sign方法用來判斷一個數究竟是正數、負數、仍是零。共有五種返回值:+1,-1,+0,-0,NaN。(對於非數值,會先使用Number將其轉換爲數值。)
  3. Math.sinh(x) 返回x的雙曲正弦(hyperbolic sine)
  4. Math.cosh(x) 返回x的雙曲餘弦(hyperbolic cosine)
  5. Math.tanh(x) 返回x的雙曲正切(hyperbolic tangent)
  6. Math.asinh(x) 返回x的反雙曲正弦(inverse hyperbolic sine)
  7. Math.acosh(x) 返回x的反雙曲餘弦(inverse hyperbolic cosine)
  8. Math.atanh(x) 返回x的反雙曲正切(inverse hyperbolic tangent)

擴展:指數運算符

指數運算符(**) 這個運算符的一個特色是右結合,而不是常見的左結合。多個指數運算符連用時,是從最右邊開始計算的。 例如:

// 至關於 3 ** (3 ** 2)
3 ** 3 ** 2
// 19683
複製代碼

指數運算符能夠與等號結合,造成一個新的賦值運算符(**=)

let a = 1.5;
a **= 2;
// 等同於 a = a * a;

let b = 4;
b **= 3;
// 等同於 b = b * b * b;
複製代碼

函數擴展

指定函數參數的默認值

ES6 容許爲函數的參數設置默認值,即直接寫在參數定義的後面。

function log(x, y = 'World') {
  console.log(x, y);
}
複製代碼

tip:一般狀況下,定義了默認值的參數,應該是函數的尾參數。由於這樣比較容易看出來,到底省略了哪些參數。若是非尾部的參數設置默認值,實際上這個參數是無法省略的。

rest 參數

rest 參數與擴展運算符實際上是同一種東西,就是... 只不過使用場景不一樣,他們的名字也不同。

  • 當用在函數定義時的形參前面時,稱爲rest參數,當函數調用時,用於接收不肯定的參數。例如:function sumRest (...m) {
  • 當與解構賦值組合使用時,稱爲rest參數,用於接收剩餘的值。例如:{a,b,...m}
  • 當用在字符串或數組前面時稱爲擴展運算符,將數組或字符串進行拆解。例如:console.log(...array);

箭頭函數

var f = v => v; 若是箭頭函數的代碼塊部分多於一條語句,就要使用大括號將它們括起來,而且使用return語句返回。 因爲大括號被解釋爲代碼塊,因此若是箭頭函數直接返回一個對象,必須在對象外面加上括號,不然會報錯。

let getTempItem = id => ({ id: id, name: "Temp" });
複製代碼

注意點 箭頭函數體內的this對象,就是定義時所在的對象,這個this是固定的,注意它沒有本身的this。

function foo() {
  setTimeout(() => {
    console.log('id:', this.id);
  }, 100);
}

var id = 21;

foo.call({ id: 42 });
// id: 42
複製代碼

上面代碼中,setTimeout的參數是一個箭頭函數,這個箭頭函數的定義生效是在foo函數生成時,而它的真正執行要等到 100 毫秒後。若是是普通函數,執行時this應該指向全局對象window,這時應該輸出21。可是,箭頭函數致使this老是指向函數定義生效時所在的對象(本例是{id: 42}),因此輸出的是42。 箭頭函數轉成 ES5 的代碼以下:

// ES6
function foo() {
  setTimeout(() => {
    console.log('id:', this.id);
  }, 100);
}

// ES5
function foo() {
  var _this = this;

  setTimeout(function () {
    console.log('id:', _this.id);
  }, 100);
}
複製代碼

數組的擴展

擴展運算符的應用

(1)複製數組

const a1 = [1, 2];
// 寫法一
const a2 = [...a1];
// 寫法二
const [...a2] = a1;
複製代碼

(2)合併數組

const arr1 = ['a', 'b'];
const arr2 = ['c'];
const arr3 = ['d', 'e'];

// ES5 的合併數組
arr1.concat(arr2, arr3);
// [ 'a', 'b', 'c', 'd', 'e' ]

// ES6 的合併數組
[...arr1, ...arr2, ...arr3]
// [ 'a', 'b', 'c', 'd', 'e' ]

複製代碼

須要注意的是:這兩種方法都是淺拷貝,使用的時候須要注意。合併而成的新數組,它們的成員都是對原數組成員的引用,這就是淺拷貝。若是修改了引用指向的值,會同步反映到新數組。

(5)實現了 Iterator 接口的對象

任何定義了遍歷器(Iterator)接口的對象(參閱 Iterator 一章),均可以用擴展運算符轉爲真正的數組。

let nodeList = document.querySelectorAll('div');
let array = [...nodeList];
複製代碼

上面代碼中,querySelectorAll方法返回的是一個NodeList對象。它不是數組,而是一個相似數組的對象。這時,擴展運算符能夠將其轉爲真正的數組,緣由就在於NodeList對象實現了 Iterator 。

數組實例的 flat(),flatMap()

數組的成員有時仍是數組,Array.prototype.flat()用於將嵌套的數組「拉平」,變成一維的數組。該方法返回一個新數組,對原數據沒有影響。

[1, 2, [3, 4]].flat()
// [1, 2, 3, 4]
複製代碼

上面代碼中,原數組的成員裏面有一個數組,flat()方法將子數組的成員取出來,添加在原來的位置。

flat()默認只會「拉平」一層,若是想要「拉平」多層的嵌套數組,能夠將flat()方法的參數寫成一個整數,表示想要拉平的層數,默認爲1。 若是flat()的參數爲2,表示要「拉平」兩層的嵌套數組。 若是無論有多少層嵌套,都要轉成一維數組,能夠用Infinity關鍵字做爲參數。

[1, 2, [3, [4, 5]]].flat(2)
// [1, 2, 3, 4, 5]
[1, [2, [3]]].flat(Infinity)
// [1, 2, 3]
複製代碼

對象的擴展

鏈判斷運算符

編程實務中,若是讀取對象內部的某個屬性,每每須要判斷一下該對象是否存在。好比,要讀取message.body.user.firstName,安全的寫法是寫成下面這樣。

const firstName = (message
&& message.body
&& message.body.user
&& message.body.user.firstName) || 'default';
  
  或
  
const fooInput = myForm.querySelector('input[name=foo]')
const fooValue = fooInput ? fooInput.value : undefined
複製代碼

這樣的層層判斷很是麻煩,所以 ES2020 引入了「鏈判斷運算符」(optional chaining operator)?.,簡化上面的寫法。

const firstName = message?.body?.user?.firstName || 'default';
const fooValue = myForm.querySelector('input[name=foo]')?.value
複製代碼

上面代碼使用了?.運算符,直接在鏈式調用的時候判斷,左側的對象是否爲null或undefined。若是是的,就再也不往下運算,而是返回undefined。

三種用法

鏈判斷運算符有三種用法。

obj?.prop // 對象屬性
obj?.[expr] // 同上
func?.(...args) // 函數或對象方法的調用
複製代碼

下面是判斷對象方法是否存在,若是存在就當即執行的例子。

iterator.return?.()
複製代碼

上面代碼中,iterator.return若是有定義,就會調用該方法,不然直接返回undefined。

對於那些可能沒有實現的方法,這個運算符尤爲有用。

if (myForm.checkValidity?.() === false) {
  // 表單校驗失敗
  return;
}
複製代碼

注意點

(1). 短路機制

a?.[++x]
// 等同於
a == null ? undefined : a[++x]
複製代碼

上面代碼中,若是a是undefined或null,那麼x不會進行遞增運算。也就是說,鏈判斷運算符一旦爲真,右側的表達式就再也不求值。 (2). delete 運算符

delete a?.b
// 等同於
a == null ? undefined : delete a.b
複製代碼

(3). 括號的影響

若是屬性鏈有圓括號,鏈判斷運算符對圓括號外部沒有影響,只對圓括號內部有影響。

(a?.b).c // 等價於 (a == null ? undefined : a.b).c 上面代碼中,?.對圓括號外部沒有影響,無論a對象是否存在,圓括號後面的.c老是會執行。

通常來講,使用?.運算符的場合,不該該使用圓括號。

(4).報錯場合

如下寫法是禁止的,會報錯。

// 構造函數
new a?.()
new a?.b()

// 鏈判斷運算符的右側有模板字符串
a?.`{b}`
a?.b`{c}`

// 鏈判斷運算符的左側是 super
super?.()
super?.foo

// 鏈運算符用於賦值運算符左側
a?.b = c
複製代碼

(5).右側不得爲十進制數值

爲了保證兼容之前的代碼,容許foo?.3:0被解析成foo ? .3 : 0,所以規定若是?.後面緊跟一個十進制數字,那麼?.再也不被當作是一個完整的運算符,而會按照三元運算符進行處理,也就是說,那個小數點會歸屬於後面的十進制數字,造成一個小數。

Null 判斷符

讀取對象屬性的時候,若是某個屬性的值是null或undefined,有時候須要爲它們指定默認值。常見作法是經過||運算符指定默認值。

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

上面的三行代碼都經過||運算符指定默認值,可是這樣寫是錯的。開發者的原意是,只要屬性的值爲null或undefined,默認值就會生效,可是屬性的值若是爲空字符串或false或0,默認值也會生效。

爲了不這種狀況,ES2020 引入了一個新的 Null 判斷運算符??。它的行爲相似||,可是隻有運算符左側的值爲null或undefined時,纔會返回右側的值。

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

上面代碼中,默認值只有在屬性值爲null或undefined時,纔會生效。

這個運算符的一個目的,就是跟鏈判斷運算符?.配合使用,爲null或undefined的值設置默認值。

const animationDuration = response.settings?.animationDuration ?? 300;
複製代碼

上面代碼中,response.settings若是是null或undefined,就會返回默認值300。

Object.is()

ES5 比較兩個值是否相等,只有兩個運算符:相等運算符(==)和嚴格相等運算符(===)。它們都有缺點,前者會自動轉換數據類型,後者的NaN不等於自身,以及+0等於-0。JavaScript 缺少一種運算,在全部環境中,只要兩個值是同樣的,它們就應該相等。

ES6 提出「Same-value equality」(同值相等)算法,用來解決這個問題。Object.is就是部署這個算法的新方法。它用來比較兩個值是否嚴格相等,與嚴格比較運算符(===)的行爲基本一致。

Object.is('foo', 'foo')
// true
Object.is({}, {})
// false
複製代碼

不一樣之處只有兩個:一是+0不等於-0,二是NaN等於自身。

+0 === -0 //true
NaN === NaN // false

Object.is(+0, -0) // false
Object.is(NaN, NaN) // true
複製代碼

Object.keys(),Object.values(),Object.entries()

ES5 引入了Object.keys方法,返回一個數組,成員是參數對象自身的(不含繼承的)全部可遍歷(enumerable)屬性的鍵名。

var obj = { foo: 'bar', baz: 42 };
Object.keys(obj)
// ["foo", "baz"]
複製代碼

Object.values()

Object.values方法返回一個數組,成員是參數對象自身的(不含繼承的)全部可遍歷(enumerable)屬性的鍵值。

const obj = { foo: 'bar', baz: 42 };
Object.values(obj)
// ["bar", 42]
複製代碼

返回數組的成員順序爲:

  • 首先遍歷全部數值鍵,按照數值升序排列。
  • 其次遍歷全部字符串鍵,按照加入時間升序排列。
  • 最後遍歷全部 Symbol 鍵,按照加入時間升序排列。

例如:

const obj = { 100: 'a', 2: 'b', 7: 'c' };
Object.values(obj)
// ["b", "c", "a"]
複製代碼

上面代碼中,屬性名爲數值的屬性,是按照數值大小,從小到大遍歷的,所以返回的順序是b、c、a。

規則以下:

  • Object.values會過濾屬性名爲 Symbol 值的屬性。
  • 若是Object.values方法的參數是一個字符串,會返回各個字符組成的一個數組。
Object.values('foo')
// ['f', 'o', 'o']
複製代碼
  • 若是參數不是對象,Object.values會先將其轉爲對象。因爲數值和布爾值的包裝對象,都不會爲實例添加非繼承的屬性。因此,Object.values會返回空數組。
Object.values(42) // []
Object.values(true) // []
複製代碼

Object.entries()

Object.entries()方法返回一個數組,成員是參數對象自身的(不含繼承的)全部可遍歷(enumerable)屬性的鍵值對數組。

const obj = { foo: 'bar', baz: 42 };
Object.entries(obj)
// [ ["foo", "bar"], ["baz", 42] ]
複製代碼

除了返回值不同,該方法的行爲與Object.values基本一致。

  • 用途1:Object.entries的基本用途是遍歷對象的屬性。
let obj = { one: 1, two: 2 };
for (let [k, v] of Object.entries(obj)) {
  console.log(
    `${JSON.stringify(k)}: ${JSON.stringify(v)}`
  );
}
// "one": 1
// "two": 2
複製代碼
  • 用途2:Object.entries可將對象轉爲真正的Map結構。
const obj = { foo: 'bar', baz: 42 };
const map = new Map(Object.entries(obj));
map // Map { foo: "bar", baz: 42 }
複製代碼

Object.fromEntries()

Object.fromEntries()方法是Object.entries()的逆操做,用於將一個鍵值對數組轉爲對象。

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

該方法的主要目的,是將鍵值對的數據結構還原爲對象,所以特別適合將 Map 結構轉爲對象。

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

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

// 例二
const map = new Map().set('foo', true).set('bar', false);
Object.fromEntries(map)
// { foo: true, bar: false }
複製代碼

該方法的一個用處是配合URLSearchParams對象,將查詢字符串轉爲對象。

Object.fromEntries(new URLSearchParams('foo=bar&baz=qux'))
// { foo: "bar", baz: "qux" }
複製代碼

Set 和 Map 數據結構

Set

ES6 提供了新的數據結構 Set。它相似於數組,可是成員的值都是惟一的,沒有重複的值。 Set自己是一個構造函數,用來生成 Set 數據結構。 Set 接收一個數組或者類數組做爲參數,用來初始化。

// 例一
const set = new Set([1, 2, 3, 4, 4]);
[...set]
// [1, 2, 3, 4]
// 可使用 Set 來給數組去重

// 例三
const set = new Set(document.querySelectorAll('div'));
set.size // 56
複製代碼

上面的代碼也展現了去除數組重複成員的方法

// 去除數組的重複成員
[...new Set(array)]
複製代碼

也能夠用來去除字符串裏面的重複字符串

[...new Set('ababbc')].join('')
// "abc"
複製代碼

Array.from 方法也能夠將 Set結構轉換爲數組,這就提供了去重的另外一種方法

const items = new Set([1, 1, 2, 3, 3, 4, 5]);
const array = Array.from(items);
複製代碼

Set 實例的屬性和方法

1. size:返回 Set 實例的成員總數
2. add(value):添加某個值,返回Set結構自己
3. delete(value):刪除某個值,返回一個布爾值,表示刪除是否成功。
4. has(value):返回一個布爾值,表示該值是否爲Set的成員
5. clear():清除全部成員,沒有返回值

遍歷操做

Set 結構的四個遍歷方法

1. keys():返回鍵名
2. values():返回鍵值
3. entries():返回鍵值對
4. forEach(): 使用回調函數遍歷每一個成員
let set = new Set(['red', 'green', 'blue']);

for (let item of set.keys()) {
  console.log(item);
}
// red
// green
// blue

for (let item of set.values()) {
  console.log(item);
}
// red
// green
// blue

for (let item of set.entries()) {
  console.log(item);
}
// ["red", "red"]
// ["green", "green"]
// ["blue", "blue"]
複製代碼

Map

Map 數據結構,它相似於對象,也是鍵值對的集合,可是「鍵」的範圍不限於字符串,各類類型的值(包括對象)均可以看成鍵。也就是說,Object 結構提供了「字符串—值」的對應,Map 結構提供了「值—值」的對應,是一種更完善的 Hash 結構實現。若是你須要「鍵值對」的數據結構,Map 比 Object 更合適。

Map 函數接收數組,或者類數組(每一個成員都是一個雙元素的數組,看成Map構造函數的參數,這就是說,Set 和 Map 均可以用來生成新的 Map。

const set = new Set([
  ['foo', 1],
  ['bar', 2]
]);
const m1 = new Map(set);
m1.get('foo') // 1

const m2 = new Map([['baz', 3]]);
const m3 = new Map(m2);
m3.get('baz') // 3
複製代碼

若是對同一個鍵屢次賦值,後面的值將覆蓋前面的值。

const map = new Map();

map
.set(1, 'aaa')
.set(1, 'bbb');

map.get(1) // "bbb"
複製代碼

注意,只有對同一個對象的引用,Map 結構纔將其視爲同一個鍵。這一點要很是當心。

const map = new Map();

map.set(['a'], 555);
map.get(['a']) // undefined
複製代碼

上面代碼的set和get方法,表面是針對同一個鍵,但實際上這是兩個不一樣的數組實例,內存地址是不同的,所以get方法沒法讀取該鍵,返回undefined。

const map = new Map();
const list = ['a']
map.set(list, 555);
map.get(list) // 555
複製代碼

將數組賦值給一個變量後,就能夠獲得想象中的結果了。

若是 Map 的鍵是一個簡單類型的值(數字、字符串、布爾值),則只要兩個值嚴格相等,Map 將其視爲一個鍵,好比0和-0就是一個鍵,布爾值true和字符串true則是兩個不一樣的鍵。另外,undefined和null也是兩個不一樣的鍵。雖然NaN不嚴格相等於自身,但 Map 將其視爲同一個鍵

let map = new Map();

map.set(-0, 123);
map.get(+0) // 123

map.set(true, 1);
map.set('true', 2);
map.get(true) // 1

map.set(undefined, 3);
map.set(null, 4);
map.get(undefined) // 3

map.set(NaN, 123);
map.get(NaN) // 123
複製代碼
相關文章
相關標籤/搜索