一、定義變量
1.1 使用let定義變量
語法格式:
let 變量名 [= 變量值]
let和var的區別?
1)let聲明變量的作用域只在當前代碼塊中有效,而var可以在代碼塊中使用,也可以在全局範圍內使用;
2)let聲明的變量必須要先聲明後使用,否則報錯,而var會返回undefined,不會報錯;
3)在同一個代碼塊中使用let聲明的變量不允許出現重複;
4)var聲明的全局變量是保存在頂層對象window中,而let聲明的全局變量不是保存在window對象中,而是保存在globalThis對象中;
一般在全局環境中獲取頂層對象都是通過this變量來獲取。但是,this在不同語言環境的作用可能不相同。比如在Node或ES6中,this返回的是當前模塊。後臺ECMA引入globalThis作爲頂層對象。也就是說,任何環境下,globalThis都是存在的,都可以從它拿到頂層對象,指向全局環境下的this。
例如:
<script>
// 定義變量,只在當前代碼塊中有效
let a = 10
//alert("a = " + a);
// 定義常量,一旦定義就無法改變它的值
const b = 10
//b = 20
//alert("b = " + b)
let sayHello = function() {
alert("hello es6")
}
sayHello()
</script>
注意:ES6 的塊級作用域必須有大括號,如果沒有大括號,JavaScript 引擎就認爲不存在塊級作用域。
1.2 使用const定義變量
語法格式:
const 變量名 = 變量值
let與const的區別
1)const聲明的變量不得改變值,而let聲明的變量可以改變它的值;
2)const聲明變量的時候必須要初始化,而let不需要;
注意:如果const變量類型是引用類型,const只能夠保證變量這個指針地址是固定的,而不能夠保證她指向的數據結構是否可變。因此,使用const聲明對象的時候必須要小心。
例如:
<script>
const user = {
id : 110,
name : 'jacky'
}
// 下面註釋代碼報錯
/*user = {
id : 220,
name : 'mickey'
}*/
user.id = 220
alert(user.id)
</script>
二、變量解構(Destructuring)
2.1 數組解構
ES6 允許按照一定模式,從數組和對象中提取值,對變量進行賦值,這被稱爲解構。例如:
<script>
let arr = [10, 20, 30]
let [a, b, c] = arr
alert("a = " + a + ", b = " + b + ", c = " + c)
</script>
上面代碼同時聲明a、b、c三個變量,它們的值爲數組arr下標爲0、1、2的三個元素的值。
也可以不完全解構,例如:
<script>
let [a, b, c] = [ , , 30]
alert("a = " + a + ", b = " + b + ", c = " + c)
</script>
上面代碼輸出結果爲:a = undefined, b = undefined, c = 30
另一種情況是不完全解構,即等號左邊的模式,只匹配一部分的等號右邊的數組。例如:
<script>
let [a, b, c] = [10, 20, 30, 50, 99]
alert("a = " + a + ", b = " + b + ", c = " + c)
</script>
上面代碼屬於不完全解構,但也能夠解構成功。輸出結果爲:a = 10, b = 20, c = 30
注意:如果等號的右邊不是數組,或者嚴格來說不是可遍歷的結構,那麼就會報錯。例如:
<script>
let [a] = 10
</script>
上面的語句都會報錯,因爲等號右邊的值,要麼轉爲對象以後不具備 Iterator 接口。控制檯提示錯誤信息:
Uncaught TypeError: 10 is not iterable
2.2 默認值
<script>
let [a = 10] = [] // a = 10
let [x, y = 'b'] = ['a']; // x = 'a', y = 'b'
</script>
注意,ES6 內部使用嚴格相等運算符(===),判斷一個位置是否有值。所以,只有當一個數組成員嚴格等於undefined,默認值纔會生效。例如:
<script>
let [a = 10] = [undefined] // a = 10
let [x, y = 'b'] = [null]; // x = null, y = 'b'
</script>
上面第二行代碼的數組成員是null,默認值就不會生效,因爲null不嚴格等於undefined。
默認值還可以是表達式,例如:
<script>
function f() {
return 10
}
let [x = f()] = [1]
alert(x) // x = 1
let [x = f()] = []
alert(x) // x = 10
</script>
如果x能取到值,所以函數f()不會被執行。
默認值可以引用解構賦值的其他變量,但該變量必須已經聲明。
<script>
let [x = 1, y = x] = [] // x=1; y=1
let [x = 1, y = x] = [2] // x=2; y=2
let [x = 1, y = x] = [1, 2] // x=1; y=2
let [x = y, y = 1] = [] // ReferenceError: y is not defined
</script>
2.3 對象解構
解構不僅可以用於數組,還可以用於對象。例如:
<script>
let { foo, bar } = {bar: 'bbb', foo: 'aaa'}
alert(bar)
</script>
對象的解構與數組有一個重要的不同。數組的元素是按次序排列的,變量的取值由它的位置決定;而對象的屬性沒有次序,變量必須與屬性同名,才能取到正確的值。
<script>
let { foo, baz } = {bar: 'bbb', foo: 'aaa'}
alert(baz) // undefined
</script>
上面代碼沒有baz變量的定義,所以解構失敗,變量的值等於undefined。
如果變量名和屬性名不一致,那麼在變量名前面需要指定模式,模式就是關聯對象的屬性名。例如:
let { foo: baz } = { foo: 'aaa', bar: 'bbb' };
上面baz前面指定關聯對象的foo屬性。所以baz變量的值爲aaa。
與數組一樣,解構也可以用於嵌套結構的對象。例如:
<script>
let obj = {
p: [
'Hello',
{ y: 'World' }
]
};
let {p: [x, { y }]} = obj;
</script>
上面代碼中變量x的值爲hello,y的值爲world。
注意:上面代碼最後一行的p是模式,不是變量,因此不會被賦值。如果想p也要作爲變量賦值,可以寫成:
let {p, p: [x, { y }]} = obj;
對象的解構賦值也可以取到繼承的屬性。
<script>
const obj1 = {};
const obj2 = { foo: 'bar' };
// obj1繼承了obj2的原型
Object.setPrototypeOf(obj1, obj2);
const { foo } = obj1;
alert(foo) // 這裏輸出bar
</script>
上面代碼中,對象obj1的原型對象是obj2。foo屬性不是obj1自身的屬性,而是繼承自obj2的屬性,解構賦值可以取到這個屬性。
Object.setPrototypeOf()ECMAScript 6最新草案中的方法,用於設置一個指定的對象的原型到另一個對象。相對於 Object.prototype,它被認爲是修改對象原型更合適的方法。
注意事項:
1)如果要將一個已經聲明的變量用於解構賦值,必須非常小心。例如:
let x;
{x} = {x: 1};
上面代碼會報錯。因爲 JavaScript 引擎會將{x}理解成一個代碼塊。只有不將大括號寫在行首,避免 JavaScript 將其解釋爲代碼塊,才能解決這個問題。例如:
let x;
({x} = {x: 1});
2)解構賦值允許等號左邊的模式之中,不放置任何變量名。例如:
({} = [true, false]);
({} = 'abc');
({} = []);
上面的代碼不會報錯,但是沒有任何意義。
3)由於數組本質是特殊的對象,因此可以對數組進行對象屬性的解構。例如:
<script>
let arr = [1, 2, 3];
let {0 : first, [arr.length - 1] : last} = arr;
</script>
上面變量first的值爲1,last的值爲3。
2.4 字符串解構
字符串也可以解構賦值。這時候字符串被轉換成了一個類似數組的對象。例如:
const [a, b, c, d, e] = 'hello';
let {length : len} = 'hello';
上面代碼變量len的值爲字符串hello的length屬性的值。
2.5 函數解構
函數的參數也可以使用解構賦值。例如:
function add([x, y]){
return x + y;
}
add([1, 2]); // 3
上面代碼中,函數add的參數表面上是一個數組,但在傳入參數的那一刻,數組參數就被解構成變量x和y。對於函數內部的代碼來說,它們能感受到的參數就是x和y。
2.6 解構賦值的應用場景
(1)交換變量的值
<script>
let x = 1;
let y = 2;
[x, y] = [y, x];
</script>
(2)從函數返回多個值
如果函數返回多個值,除了可以把它們放在數組或對象裏面以外,還可以使用解構賦值。例如:
<script>
function f() {
return [1, 2, 3];
}
let [a, b, c] = f();
</script>
變量的值爲:a = 1, b = 2, c = 3
<script>
function example() {
return {
foo: 1,
bar: 2
};
}
let { foo, bar } = example();
</script>
變量的值爲:foo = 1, bar = 2
(3)函數參數定義
解構賦值可以方便地將一組參數與變量名對應起來。
// 參數是一組有次序的值
function f([x, y, z]) { ... }
f([1, 2, 3]);
// 參數是一組無次序的值
function f({x, y, z}) { ... }
f({z: 3, y: 2, x: 1});
(4)提取json數據
解構賦值可以快速提取 JSON 數據的值。
<script>
let jsonData = {
id: 42,
status: "OK",
data: [867, 5309]
};
let {id, status, data} = jsonData;
console.log(id, status, data);
</script>
除了上面這些用途以外,結構函數還可以給函數參數默認值,遍歷Map結構,加載模塊指定方法等。
三、字符串擴展
ES6 對字符串進行了改造和增強。
3.1 字符的 Unicode 表示法
ES6 加強了對 Unicode 的支持,允許採用\uxxxx形式表示一個字符,其中xxxx表示字符的 Unicode 碼點。例如:
"\u0061" 表示字符‘a’
但是,這種表示法只限於碼點在\u0000~\uFFFF之間的字符。超出這個範圍的字符,必須用兩個雙字節的形式表示。
"\u20BB7" 表示“空格 + 7”
上面代碼表示,如果直接在\u後面跟上超過0xFFFF的數值(比如\u20BB7),JavaScript 會理解成\u20BB+7。由於\u20BB是一個不可打印字符,所以只會顯示一個空格,後面跟着一個7。
ES6 對這一點做出了改進,只要將碼點放入大括號,就能正確解讀該字符。例如:
"\u{20BB7}"
3.2 增加字符串遍歷接口
for (let c of 'foo') {
console.log(c)
}
除了遍歷字符串,這個遍歷器最大的優點是可以識別大於0xFFFF的碼點,傳統的for循環無法識別這樣的碼點。例如:
let text = String.fromCodePoint(0x20BB7);
for (let i = 0; i < text.length; i++) {
console.log(text[i]);
}
// " "
// " "
for (let i of text) {
console.log(i);
}
// "?"
上面代碼中,字符串text只有一個字符,但是for循環會認爲它包含兩個字符(都不可打印),而for…of循環會正確識別出這是一個字符。
3.3 模板字符串
模板字符串(template string)是增強版的字符串,用反引號(`)標識。它可以當作普通字符串使用,也可以用來定義多行字符串。例如:
// 普通字符串
`In JavaScript '\n' is a line-feed.`
// 多行字符串
`In JavaScript this is
not legal.`
如果使用模板字符串表示多行字符串,所有的空格和縮進都會被保留在輸出之中。
注意:如果在模板字符串中需要使用反引號,則前面要用反斜槓轉義。例如:
let greeting = `\`Yo\` World!`;
可以在模板字符串中使用嵌入變量。模板字符串中嵌入變量,需要將變量名寫在${}之中。
// 字符串中嵌入變量
let name = "Bob", time = "today";
`Hello ${name}, how are you ${time}?`
注意:1)如果大括號中的值是一個對象,將默認調用對象的toString方法;2)如果模板字符串中的變量沒有聲明,將報錯;
也可以在模板字符串中調用函數。
function fn() {
return "Hello World";
}
`foo ${fn()} bar`
模板字符串還可以嵌套。
const tmpl = addrs => `
<table>
${addrs.map(addr => `
<tr><td>${addr.first}</td></tr>
<tr><td>${addr.last}</td></tr>
`).join('')}
</table>
`;
const data = [
{ first: '<Jane>', last: 'Bond' },
{ first: 'Lars', last: '<Croft>' },
];
console.log(tmpl(data));
3.4 標籤模板(tagged template)
模板字符串的功能,不僅僅是上面這些。它可以緊跟在一個函數名後面,該函數將被調用來處理這個模板字符串。
alert`123`
// 等同於
alert(123)
但是,如果模板字符裏面有變量,就不是簡單的調用了,而是會將模板字符串先處理成多個參數,再調用函數。
let a = 5;
let b = 10;
tag`Hello ${ a + b } world ${ a * b }`;
// tag函數定義
function tag(stringArr, value1, value2){
...
}
上面tag函數調用等同於:
tag(['Hello ', ' world ', ''], 15, 50);
tag函數的第一個參數是一個數組,該數組的成員是模板字符串中那些沒有變量替換的部分,比如:['Hello ', ’ world ', ‘’]。從第二個參數開始是模板字符串各個變量被替換後的值。因此,value1的值爲15, value2的值爲50。
3.5 字符串新增方法
3.5.1 String.raw方法
ES6 還爲原生的 String 對象,提供了一個raw()方法。該方法返回一個斜槓都被轉義(即斜槓前面再加一個斜槓)的字符串,往往用於模板字符串的處理方法。例如:
String.raw('hello world\n')
如果原字符串的斜槓已經轉義,那麼String.raw()會進行再次轉義。
String.raw()方法可以作爲處理模板字符串的基本方法,它會將所有變量替換,而且對斜槓進行轉義,方便下一步作爲字符串來使用。例如:
<script>
let aa = (name) => String.raw`hello ${name}\n`
let bb = aa('jacky')
alert(bb)
</script>
如果String.raw()方法也可以作爲正常的函數使用。這時,它的第一個參數,應該是一個具有raw屬性的對象,且raw屬性的值應該是一個數組。例如:
String.raw({ raw: 'test' }, 0, 1, 2);
// 等同於
String.raw({ raw: ['t','e','s','t'] }, 0, 1, 2);
上面String.raw函數返回“t0e1s2t”。
3.5.2 includes, startsWith, endsWith函數
傳統上,JavaScript 只有indexOf方法,可以用來確定一個字符串是否包含在另一個字符串中。ES6 又提供了三種新方法。
- includes():返回布爾值,表示是否找到了參數字符串;
- startsWith():返回布爾值,表示參數字符串是否在原字符串的頭部;
- endsWith():返回布爾值,表示參數字符串是否在原字符串的尾部;
例如:
<script>
let s = 'Hello world!';
console.log(s.startsWith('Hello')) // true
console.log(s.endsWith('!')) // true
console.log(s.includes('o')) // true
</script>
這三個方法都支持第二個參數,表示開始搜索的位置。例如:
<script>
let s = 'Hello world!';
console.log(s.startsWith('Hello', 6)) // false
console.log(s.endsWith('!', 5)) // false
console.log(s.includes('o', 6)) // true
</script>
上面代碼表示,使用第二個參數n時,endsWith的行爲與其他兩個方法有所不同。它針對前n個字符,而其他兩個方法針對從第n個位置直到字符串結束。
3.5.3 repeat函數
repeat方法返回一個新字符串,表示將原字符串重複n次。例如:
<script>
let s = 'x'.repeat(3)
alert(s); // "xxx"
</script>
注意事項:
- 如果參數是0,則返回空;
- 如果參數是小數,會被取整;
- 如果參數是小於-1的負數或Infinity,則報錯;
- 如果參數是0到-1之間的小數,則取整後就變成0。
- 如果參數是字符串,則會先轉換成數字。
3.5.4 padStart、padEnd
ES2017 引入了字符串補全長度的功能。如果某個字符串不夠指定長度,會在頭部或尾部補全。
'x'.padStart(5, 'ab') // 'ababx'
'x'.padStart(4, 'ab') // 'abax'
'x'.padEnd(5, 'ab') // 'xabab'
'x'.padEnd(4, 'ab') // 'xaba'
如果原字符串的長度,等於或大於最大長度,則字符串補全不生效,返回原字符串。
'xxx'.padStart(2, 'ab') // 'xxx'
'xxx'.padEnd(2, 'ab') // 'xxx'
如果用來補全的字符串與原字符串,兩者的長度之和超過了最大長度,則會截去超出位數的補全字符串。
'abc'.padStart(10, '0123456789') // '0123456abc'
如果省略第二個參數,默認使用空格補全長度。
3.5.5 trimStart、trimEnd
ES2019 對字符串實例新增了trimStart()和trimEnd()這兩個方法。它們的行爲與trim()一致,trimStart()消除字符串頭部的空格,trimEnd()消除尾部的空格。它們返回的都是新字符串,不會修改原始字符串。
const s = ' abc ';
s.trim() // "abc"
s.trimStart() // "abc "
s.trimEnd() // " abc"
除了空格鍵,這兩個方法對字符串頭部(或尾部)的 tab 鍵、換行符等不可見的空白符號也有效。
3.5.6 matchAll
matchAll()方法返回一個正則表達式在當前字符串的所有匹配。不過,它返回的是一個遍歷器(Iterator),而不是數組。
<script>
const regex = /\b[a-z]{5}\b/ig
const s = 'hello javax hello php hello vue'
// 返回所有匹配的迭代器對象
let itr = s.matchAll(regex)
// 把迭代器轉成數組
let arr = [...itr]
// 遍歷數組
for (var i in arr) {
document.write(arr[i] + '<br/>')
}
</script>
四、正則表達式擴展
4.1 增加正則修飾符
(1)u修飾符
(2)i修飾符
(3)y修飾符
(4)s修飾符
五 數值的擴展
5.1 進製表示法
ES6 提供了二進制和八進制數值的新的寫法,分別用前綴0b(或0B)和0o(或0O)表示。如果要將0b和0o前綴的字符串數值轉爲十進制,要使用Number方法。
Number(0b0101) // 將二進制轉換成十進制
Number(0o10) // 將八進制轉換成十進制
5.2 Number.isFinite、Number.isNaN
Number.isFinite():用來檢查一個數值是否爲有限的(finite),即不是Infinity。如果是有限的,則返回true,否則返回false。
Number.isFinite(15); // true
Number.isFinite(0.8); // true
Number.isFinite(NaN); // false
Number.isFinite(Infinity); // false
Number.isFinite(-Infinity); // false
Number.isFinite('foo'); // false
Number.isFinite('15'); // false
Number.isFinite(true); // false
注意:如果參數不是數值,則返回false。
Number.isNaN():用來檢查一個數值是否爲NaN。如果是有限的,則返回true,否則返回false。
Number.isNaN(NaN) // true
Number.isNaN(15) // false
Number.isNaN('15') // false
Number.isNaN(true) // false
Number.isNaN(9/NaN) // true
Number.isNaN('true' / 0) // true
Number.isNaN('true' / 'true') // true
如果參數類型不是NaN,Number.isNaN一律返回false。
5.3 Number.parseInt、Number.parseFloat
傳統javascript的parsetInt和parseFloat方法是保存在全局window對象中。而ES6將它們移植到了Number對象中。這樣做的目的,是逐步減少全局性方法,使得語言逐步模塊化。
// ES5的寫法
parseInt('12.34') // 12
parseFloat('123.45#') // 123.45
// ES6的寫法
Number.parseInt('12.34') // 12
Number.parseFloat('123.45#') // 123.45
六、函數擴展
6.1 函數默認值
ES6 允許爲函數的參數設置默認值,即直接寫在參數定義的後面。例如:
function log(x, y = 'World') {
console.log(x, y);
}
log('Hello') // Hello World
log('Hello', 'China') // Hello China
log('Hello', '') // Hello
參數默認值可以與解構賦值的默認值,結合起來使用。
function foo({x, y = 5}) {
console.log(x, y);
}
foo({}) // undefined 5
foo({x: 1}) // 1 5
foo({x: 1, y: 2}) // 1 2
foo() // TypeError: Cannot read property 'x' of undefined
如果函數foo調用時沒提供參數,變量x和y就不會生成,從而報錯。通過提供函數參數的默認值,就可以避免這種情況。
function foo({x, y = 5} = {}) {
console.log(x, y);
}
foo() // undefined 5
上面代碼指定,如果沒有提供參數,函數foo的參數默認爲一個空對象。
另外一個值得注意的地方,定義默認值的參數應該是尾參數。例如:
function f(x = 1, y) {
return [x, y];
}
f() // [1, undefined]
f(2) // [2, undefined])
f(, 1) // 報錯
f(undefined, 1) // [1, 1]
6.2 函數的length屬性
函數length屬性返回函數參數個數,當時不包含指定了默認值的參數,也不包含rest參數。例如:
(function (a) {}).length // 1
(function (a = 5) {}).length // 0
(function (a, b, c = 5) {}).length // 2
(function(...args) {}).length // 0
如果設置了默認值的參數不是尾參數,那麼length屬性也不再計入後面的參數了。
(function (a = 0, b, c) {}).length // 0
(function (a, b = 1, c) {}).length // 1
6.3 Rest參數
ES6 引入 rest 參數(形式爲…變量名),用於獲取函數的多餘參數,這樣就不需要使用arguments對象了。rest 參數搭配的變量是一個數組,該變量將多餘的參數放入數組中。
// 求和
function add(...values) {
let sum = 0
for (var i in values) {
sum += values[i]
}
return sum;
}
注意:Rest參數之後不能夠再有其他參數,否則報錯。
6.4 嚴格模式
從 ES5 開始,函數內部可以設定爲嚴格模式。
function foo() {
`use strict`
}
ES2016 做了一點修改,規定只要函數參數使用了默認值、解構賦值、或者擴展運算符,那麼函數內部就不能顯式設定爲嚴格模式,否則會報錯。
// 報錯
function doSomething(a, b = a) {
'use strict';
// code
}
// 報錯
const doSomething = function ({a, b}) {
'use strict';
// code
};
// 報錯
const doSomething = (...a) => {
'use strict';
// code
};
這樣規定的原因是,函數內部的嚴格模式,同時適用於函數體和函數參數。但是,函數執行的時候,先執行函數參數,然後再執行函數體。這樣就有一個不合理的地方,只有從函數體之中,才能知道參數是否應該以嚴格模式執行,但是參數卻應該先於函數體執行。
兩種方法可以規避這種限制:
一種方法是設置全局性的嚴格模式,例如:
'use strict';
function doSomething(a, b = a) {
// code
}
另外一種方法:是把函數包在一個無參數的立即執行函數裏面。
let doSomething = (function() {
'use strict'
return function(a, b = a) {
// code
}
})
6.5 箭頭函數
與java一樣,es6開始支持使用箭頭函數。
var f = function(v) {
return v;
}
// 使用箭頭函數替換
var f = v => v;
如果箭頭函數不需要參數,或者有多個參數,使用圓括號括起來。
var f = () => 5;
var sum = (a, b) => a + b;
如果箭頭函數體部分有多條語句,那麼使用大括號括起來,並使用return語句返回。
var sum = (a, b) = {return a + b}
如果箭頭函數返回一個對象,那麼必須在對象外面使用大括號括起來。
let foo = (id, name) => ({stuId: id, stuName: name})
箭頭函數可以與結構函數一起使用。
function(person) {
return person.firstName + "" + person.lastName;
}
// 箭頭函數和變量解構結合使用
const full = ({firstName, lastName}) => firstName + "" + lastName;
箭頭函數的一個用處是簡化回調函數。
var values = [21, 12, 9, 10, 13];
var result = values.sort(function (a, b) {
return a - b;
});
// 使用箭頭函數代替
var result = values.sort((a, b) => a - b);
使用箭頭函數的注意點:
- 箭頭函數體中並沒有this對象,所以在箭頭函數中使用this,該this就是定義時所在對象;
// ES6
function foo() {
setTimeout(() => {
console.log('id:', this.id);
}, 100);
}
// ES5
function foo() {
var _this = this;
setTimeout(function () {
console.log('id:', _this.id);
}, 100);
}
- 箭頭函數不可作爲構造函數使用;
- 箭頭函數體中沒有arguments對象,所以在箭頭函數中使用arguments,實際上該arguments是箭頭函數所在函數的arguments對象。
function foo() {
setTimeout(() => {
console.log('args:', arguments);
}, 100);
}
foo(2, 4, 6, 8) // args: [2, 4, 6, 8]
- 不可以使用yield命令;
箭頭函數不適合場景:
- 定義對象方法時候,如果方法體中使用了this,那麼不適用使用箭頭函數定義;
const cat = {
lives: 9,
jumps: () => {
this.lives--;
}
}
上面jumps方法中的this代表全局對象,不是cat對象。
- 需要動態this的時候,也不應使用箭頭函數;
var button = document.getElementById('press');
button.addEventListener('click', () => {
this.classList.toggle('on');
});
上面代碼運行時,點擊按鈕會報錯,因爲button的監聽函數是一個箭頭函數,導致裏面的this就是全局對象。如果改成普通函數,this就會動態指向被點擊的按鈕對象。
另外,如果函數體很複雜,有許多行,或者函數內部有大量的讀寫操作,不單純是爲了計算值,這時也不應該使用箭頭函數,而是要使用普通函數,這樣可以提高代碼可讀性。
6.6 函數參數的尾逗號
ES2017 允許函數的最後一個參數有尾逗號(trailing comma)。
function foo(
param1,
param2,
)
foo(
'aa',
'bb',
)
這樣的規定也使得,函數參數與數組和對象的尾逗號規則,保持一致了。
6.7 catch命令的參數省略
JavaScript 語言的try…catch結構,以前明確要求catch命令後面必須跟參數,接受try代碼塊拋出的錯誤對象。
try {
// ...
} catch (err) {
// 處理錯誤
}
但是很多時候,catch代碼塊可能用不到這個參數。但是,爲了保證語法正確,還是必須寫。ES2019 做出了改變,允許catch語句省略參數。
try {
// ...
} catch {
// ...
}