ES6入門學習筆記-持續更新中

ES6學習筆記

學習開課吧 石川老師視頻教程

兼容性

各大瀏覽器的最新版本,對 ES6 的支持可以查看kangax.github.io/compat-table/es6/。隨着時間的推移,支持度已經越來越高了,超過 90%的 ES6 語法特性都實現了。
ES6(ES2015)——IE10+、Chorme、FirFox、移動端、NodeJS

編譯轉換:

  • 在線轉換
  • 提前編譯(babel==browser.js)

ES6特性

  1. 變量
  2. 函數
  3. 數組
  4. 字符串
  5. 面向對象
  6. Promise(異步操作)
  7. generator(yield)(異步操作)
  8. 模塊化

1.變量

var

  1. 可重複聲明
  2. 無法限制修改(無常量概念)
  3. 沒有塊級作用域

let 不能重複聲明,變量:可修改,有塊級作用域,不存在變量提升
const 不能重複聲明,常量:不可修改,有塊級作用域,不存在變量提升,一旦聲明必須初始化

<script>
		window.onload = function(){
				var aBtn = document.getElementsByTagName('input');
				for(var i=0;i<aBtn.length;i++){
						aBtn[i].onclick = funtion(){
							arlet(i);//3
						};
				}
		}
</script>
<body>
		<input type="button" value="按鈕1">
		<input type="button" value="按鈕2">
		<input type="button" value="按鈕3">
</body>

以前解決:

<script>
		window.onload = function(){
				var aBtn = document.getElementsByTagName('input');
				for(var i=0;i<aBtn.length;i++){
					(function (i){
						aBtn[i].onclick = funtion(){
							arlet(i);
						};
					})(i);
				}
		}
</script>

es6 let解決

<script>
		window.onload = function(){
				var aBtn = document.getElementsByTagName('input');
				for(let i=0;i<aBtn.length;i++){
						aBtn[i].onclick = funtion(){
							arlet(i);//3
						};
				}
		}
</script>

暫時性死區

ES6 明確規定,如果區塊中存在let和const命令,這個區塊對這些命令聲明的變量,從一開始就形成了封閉作用域。凡是在聲明之前就使用這些變量,就會報錯。

總之,在代碼塊內,使用let命令聲明變量之前,該變量都是不可用的。這在語法上,稱爲“暫時性死區”(temporal dead zone,簡稱 TDZ)。

變量一定要在聲明之後使用,否則就報錯。(typeof)

暫時性死區的本質就是,只要一進入當前作用域,所要使用的變量就已經存在了,但是不可獲取,只有等到聲明變量的那一行代碼出現,纔可以獲取和使用該變量。

2.箭頭函數

	//標準函數:
	function 名字(){
	
	}
	//箭頭函數
	()=>{
	
	}
  1. 如果只有一個參數,圓括號()可以少
  2. 如果只有一個return,大括號{}可以少

3.函數參數

參數拓展/展開

擴展運算符(spread)是三個點(…)。它好比 rest 參數的逆運算,將一個數組轉爲用逗號分隔的參數序列。

function show(a,b,...args){
	alert(a);
	alert(b);
	alert(args);
}
show(12,15,8,9,20) //12   15   8,9,20

擴展運算符後面還可以放置表達式。

const arr = [
  ...(x > 0 ? ['a'] : []),
  'b',
];

如果擴展運算符後面是一個空數組,則不產生任何效果。

[...[], 1]
// [1]

注意,只有函數調用時,擴展運算符纔可以放在圓括號中,否則會報錯。

(...[1, 2])
// Uncaught SyntaxError: Unexpected number

console.log((...[1, 2]))
// Uncaught SyntaxError: Unexpected number

console.log(...[1, 2])
// 1 2

作用

  • 收集剩餘的參數 *Rest Parameter必須是最後一個
  • 展開數組 *展開後的效果,跟直接把數組內容寫出一樣(替代函數的 apply 方法)

應用

  • 複製數組:直接複製的話,只是複製了指向底層數據結構的指針,而不是克隆一個全新的數組。
  • 合併數組
  • 與解構賦值結合,注意如果將擴展運算符用於數組賦值,只能放在參數的最後一位,否則會報錯。
  • 將字符串轉爲真正的數組。(能夠正確識別四個字節的 Unicode 字符)
let arr = [1,2,3];
//等價於
...arr

默認參數

4.解構賦值

注意:

  1. 左右兩邊結構必須一樣
  2. 右邊必須是個東西
  3. 聲明和賦值不能分開(必須在一句話內完成)
let [a,b,c]=[12,5,8];
let {a,b,c}={a:12,b:5,c:8};

5.數組

ES5新增的數組方法:

  • map(映射):一個對一個
let arr = [12,5,8];
let result=arr.map( item=> item*2;);
alert(result);
  • reduce (彙總):一堆出來一個(算總數/平均數)
let arr = [12,69,180,8673];
let result =arr.reduce(function(tmp,item,index){
	//算總數
	return tmp +item;
	
	//算平均數
	if(index!=arr.length-1){
		return tmp+item;
	}else{
		return (tmp+item)/arr.length
	}
}
alert(result);
  • filter (過濾器)
let arr=[12,5,8,99,27,75,11];
let result = arr.filter(item=>item%3==0);
alert(result);//12,99,27,75
let arr=[
	{title:'男士襯衫',price:75},
	{title:'女士包',price:57842},
	{title:'男士包',price:65},
	{title:'女士鞋',price:27531},
]
let result = arr.filter(json=>json.price>=10000);
console.log(result);
  • foreach(循環/迭代)
let arr=[12,5,8,9];
arr.forEach((item,index)=>{
	alert(index +':'+item);
});

ES6新增的數組方法:

  • Array.from
    將兩類對象轉爲真正的數組:類似數組的對象(array-like object)和可遍歷(iterable)的對象(包括 ES6 新增的數據結構 Set 和 Map)。
let arrayLike = {
    '0': 'a',
    '1': 'b',
    '2': 'c',
    length: 3
};

// ES5的寫法
var arr1 = [].slice.call(arrayLike); // ['a', 'b', 'c']

// ES6的寫法
let arr2 = Array.from(arrayLike); // ['a', 'b', 'c']

*任何有length屬性的對象,都可以通過Array.from方法轉爲數組,而此時擴展運算符就無法轉換。

Array.from()可以將各種值轉爲真正的數組,並且還提供map功能。這實際上意味着,只要有一個原始的數據結構,你就可以先對它的值進行處理,然後轉成規範的數組結構,進而就可以使用數量衆多的數組方法。

  • Array.of
    用於將一組值,轉換爲數組。
Array.of(3, 11, 8) // [3,11,8]
Array.of(3) // [3]
Array.of(3).length // 1

Array.of基本上可以用來替代Array()或new Array(),並且不存在由於參數不同而導致的重載。它的行爲非常統一。
Array.of總是返回參數值組成的數組。如果沒有參數,就返回一個空數組。

  • 數組實例的 copyWithin()
    在當前數組內部,將指定位置的成員複製到其他位置(會覆蓋原有成員),然後返回當前數組。
Array.prototype.copyWithin(target, start = 0, end = this.length)

它接受三個參數。

  1. target(必需):從該位置開始替換數據。如果爲負值,表示倒數。
  2. start(可選):從該位置開始讀取數據,默認爲0。如果爲負值,表示從末尾開始計算。
  3. end(可選):到該位置前停止讀取數據,默認等於數組長度。如果爲負值,表示從末尾開始計算。

這三個參數都應該是數值,如果不是,會自動轉爲數值。

// 將3號位複製到0號位
[1, 2, 3, 4, 5].copyWithin(0, 3, 4)
// [4, 2, 3, 4, 5]

// -2相當於3號位,-1相當於4號位
[1, 2, 3, 4, 5].copyWithin(0, -2, -1)
// [4, 2, 3, 4, 5]

// 將3號位複製到0號位
[].copyWithin.call({length: 5, 3: 1}, 0, 3)
// {0: 1, 3: 1, length: 5}

// 將2號位到數組結束,複製到0號位
let i32a = new Int32Array([1, 2, 3, 4, 5]);
i32a.copyWithin(0, 2);
// Int32Array [3, 4, 5, 4, 5]

// 對於沒有部署 TypedArray 的 copyWithin 方法的平臺
// 需要採用下面的寫法
[].copyWithin.call(new Int32Array([1, 2, 3, 4, 5]), 0, 3, 4);
// Int32Array [4, 2, 3, 4, 5]
  • 數組實例的 find() 和 findIndex()
    find方法,用於找出第一個符合條件的數組成員。
[1, 5, 10, 15].find(function(value, index, arr) {
  return value > 9;
}) // 10

上面代碼中,find方法的回調函數可以接受三個參數,依次爲當前的值、當前的位置和原數組。

數組實例的findIndex方法的用法與find方法非常類似,返回第一個符合條件的數組成員的位置,如果所有成員都不符合條件,則返回-1。

[1, 5, 10, 15].findIndex(function(value, index, arr) {
  return value > 9;
}) // 2

這兩個方法都可以接受第二個參數,用來綁定回調函數的this對象。

function f(v){
  return v > this.age;
}
let person = {name: 'John', age: 20};
[10, 12, 26, 15].find(f, person);    // 26

上面的代碼中,find函數接收了第二個參數person對象,回調函數中的this對象指向person對象。

另外,這兩個方法都可以發現NaN,彌補了數組的indexOf方法的不足。

  • fill()
    fill方法使用給定值,填充一個數組。
    fill方法用於空數組的初始化非常方便。數組中已有的元素,會被全部抹去。
    fill方法還可以接受第二個和第三個參數,用於指定填充的起始位置和結束位置。
['a', 'b', 'c'].fill(7)
// [7, 7, 7]

new Array(3).fill(7)
// [7, 7, 7]

['a', 'b', 'c'].fill(7, 1, 2)
// ['a', 7, 'c']

注意,如果填充的類型爲對象,那麼被賦值的是同一個內存地址的對象,而不是深拷貝對象

  • entries(),keys() 和 values()
    entries(),keys()和values()——用於遍歷數組。
    它們都返回一個遍歷器對象,可以用for…of循環進行遍歷,唯一的區別是keys()是對鍵名的遍歷、values()是對鍵值的遍歷,entries()是對鍵值對的遍歷。
for (let index of ['a', 'b'].keys()) {
  console.log(index);
}
// 0
// 1

for (let elem of ['a', 'b'].values()) {
  console.log(elem);
}
// 'a'
// 'b'

for (let [index, elem] of ['a', 'b'].entries()) {
  console.log(index, elem);
}
// 0 "a"
// 1 "b"
  • includes()
    返回一個布爾值,表示某個數組是否包含給定的值,與字符串的includes方法類似。
    該方法的第二個參數表示搜索的起始位置,默認爲0。如果第二個參數爲負數,則表示倒數的位置,如果這時它大於數組長度(比如第二個參數爲-4,但數組長度爲3),則會重置爲從0開始。
[1, 2, 3].includes(2)     // true
[1, 2, 3].includes(4)     // false
[1, 2, NaN].includes(NaN) // true

[1, 2, 3].includes(3, 3);  // false
[1, 2, 3].includes(3, -1); // true

indexOf方法有兩個缺點,一是不夠語義化,它的含義是找到參數值的第一個出現位置,所以要去比較是否不等於-1,表達起來不夠直觀。二是,它內部使用嚴格相等運算符(===)進行判斷,這會導致對NaN的誤判。
includes()可以判斷是否包含NaN。

  • flat(),flatMap()
    用於將嵌套的數組“拉平”,變成一維的數組。該方法返回一個新數組,對原數據沒有影響。
    參數爲想要拉平的層數,默認一層
[1, 2, [3, 4]].flat()
// [1, 2, 3, 4]

[1, 2, [3, [4, 5]]].flat()
// [1, 2, 3, [4, 5]]

[1, 2, [3, [4, 5]]].flat(2)
// [1, 2, 3, 4, 5]

[1, [2, [3]]].flat(Infinity)
// [1, 2, 3]

[1, 2, , 4, 5].flat()  //會跳過空位
// [1, 2, 4, 5]

flatMap()方法對原數組的每個成員執行一個函數(相當於執行Array.prototype.map()),然後對返回值組成的數組執行flat()方法。該方法返回一個新數組,不改變原數組。
只能展開一層數組。
參數是一個遍歷函數,該函數可以接受三個參數,分別是當前數組成員、當前數組成員的位置(從零開始)、原數組。

// 相當於 [[2, 4], [3, 6], [4, 8]].flat()
[2, 3, 4].flatMap((x) => [x, x * 2])
// [2, 4, 3, 6, 4, 8]

// 相當於 [[[2]], [[4]], [[6]], [[8]]].flat()
[1, 2, 3, 4].flatMap(x => [[x * 2]])
// [[2], [4], [6], [8]]
  • 數組的空位
    ES5 對空位的處理,已經很不一致了,大多數情況下會忽略空位。
    forEach(), filter(), reduce(), every() 和some()都會跳過空位。
    map()會跳過空位,但會保留這個值
    join()和toString()會將空位視爲undefined,而undefined和null會被處理成空字符串。

ES6 則是明確將空位轉爲undefined。
Array.from方法會將數組的空位,轉爲undefined。
擴展運算符(…)也會將空位轉爲undefined。
fill()會將空位視爲正常的數組位置。
for…of循環也會遍歷空位。
entries()、keys()、values()、find()和findIndex()會將空位處理成undefined。

6.字符串

startsWith

判斷字符串是否以參數爲開頭,返回一個布爾值。

let str="asdfasw";

alert(str.startsWith('a'))  //true

endsWith

判斷字符串是否以參數爲結尾,返回一個布爾值。

let str ="1.txt";
if(str.endsWith('.txt')){
	alert('文本文件');
}else if(str.endsWith('.jpg')){
	alert('JPG圖片');
}else{
	alert('其他')
}

字符串模板

傳統js中,輸出模板:

$('#result').append(
  'There are <b>' + basket.count + '</b> ' +
  'items in your basket, ' +
  '<em>' + basket.onSale +
  '</em> are on sale!'
);

ES6 引入了模板字符串:

$('#result').append(`
  There are <b>${basket.count}</b> items
   in your basket, <em>${basket.onSale}</em>
  are on sale!
`);

模板字符串(template string)是增強版的字符串,用反引號(`)標識。它可以當作普通字符串使用,也可以用來定義多行字符串,或者在字符串中嵌入變量。

// 普通字符串
`In JavaScript '\n' is a line-feed.`

// 多行字符串
`In JavaScript this is
 not legal.`

console.log(`string text line 1
string text line 2`);

// 字符串中嵌入變量
let name = "Bob", time = "today";
`Hello ${name}, how are you ${time}?`

如果在模板字符串中需要使用反引號,則前面要用反斜槓轉義。

let greeting = `\`Yo\` World!`;

所有的空格和縮進都會被保留
如果你不想要這個換行,可以使用trim方法消除它。
模板字符串中嵌入變量,需要將變量名寫在${}之中。大括號內部可以放入任意的 JavaScript 表達式,可以進行運算,以及引用對象屬性,還能調用函數。

模板字符串甚至還能嵌套。

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));
//結果
// <table>
//
//   <tr><td><Jane></td></tr>
//   <tr><td>Bond</td></tr>
//
//   <tr><td>Lars</td></tr>
//   <tr><td><Croft></td></tr>
//
// </table>

字符的 Unicode 表示法

ES6 加強了對 Unicode 的支持,允許採用\uxxxx(\u0000~\uFFFF)形式表示一個字符,其中xxxx表示字符的 Unicode 碼點。
只要將碼點放入大括號,就能正確解讀xxxx超過0xFFFF的數值。

字符串的遍歷器接口

ES6 爲字符串添加了遍歷器接口,使得字符串可以被for…of循環遍歷。最大的優點是可以識別大於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);
}
// "𠮷"

直接輸入 U+2028 和 U+2029

JavaScript 字符串允許直接輸入字符,以及輸入字符的轉義形式。
但是,JavaScript 規定有5個字符,不能在字符串裏面直接使用,只能使用轉義形式。

U+005C:反斜槓(reverse solidus)
U+000D:回車(carriage return)
U+2028:行分隔符(line separator)
U+2029:段分隔符(paragraph separator)
U+000A:換行符(line feed)

字符串裏面不能直接包含反斜槓,一定要轉義寫成\或者\u005c。

麻煩在於 JSON 格式允許字符串裏面直接使用 U+2028(行分隔符)和 U+2029(段分隔符)。這樣一來,服務器輸出的 JSON 被JSON.parse解析,就有可能直接報錯。爲了消除這個報錯,ES2019 允許 JavaScript 字符串直接輸入 U+2028(行分隔符)和 U+2029(段分隔符)。

JSON.stringify() 的改造

根據標準,JSON 數據必須是 UTF-8 編碼。但是,現在的JSON.stringify()方法有可能返回不符合 UTF-8 標準的字符串。
爲了確保返回的是合法的 UTF-8 字符,ES2019 改變了JSON.stringify()的行爲。如果遇到0xD800到0xDFFF之間的單個碼點,或者不存在的配對形式,它會返回轉義字符串,留給應用自己決定下一步的處理。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章