es6入門(一)

一、定義變量

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 {
  // ...
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章