1. 程式人生 > >ES678重要知識點總結

ES678重要知識點總結

ES6:也就使es2015,這一版更新了非常重要的知識點,也是目前前端面試內容佔比最多的一部分

1、let,const.

    1.11塊級作用域:見到這種變數首先想到的就是es6新添了一種作用域,塊級作用域。而生效過程即使在有let和const存在就會有會計作用域,顧名思義就是在大括號裡有作用域,即for,if等語句中也存在作用域

    1.12不存在變數提升:傳統的會有變數提升,先var v1;console.log(v1);v1=2;let不存在變數提升就會報錯

    

    1.13統一塊級作用域不允許重複宣告 

    1.13const宣告時必須賦值 ,否則報錯,且const a=引用型別資料時改變不會報錯

    1.14暫時性死區:一個塊級作用域內部如果定義了局部變數,就不會使用外部變數。

2、結構賦值,其實很簡單,就是一一對應物件或陣列中的值進行賦值(介紹的比較簡單,其實很複雜,字串也可以結構賦值等等...結構賦值的知識點比較多,也很雜,有興趣的可以單獨瞭解一下,這裡介紹最常用的)

 

let [a, [[b], c]] = [1, [[2], 3]];
console.log(a, b, c); // 1, 2, 3

let [ , , c] = [1, 2, 3];
console.log(c);       // 3

let [a, , c] = [1, 2, 3];
console.log(a,c);     // 1, 3

let [a, ...b] = [1, 2, 3];
console.log(a,b);     // 1, [2,3]

let [a, b, ..c.] = [1];
console.log(a, b, c); // 1, undefined, []

3、字串函式的拓展,在String.prototype上添加了一些方法 

  • includes():返回布林值,表示是否找到引數字串
  • startsWith():返回布林值,表示引數字串是否在原字串的頭部
  • endsWith():返回布林值,表示引數字串是否在原字串的尾部
  • repeat方法返回一個新字串,表示將原字串重複n次。

第一個 引數是查詢的值,第二個引數是開始查詢的下標,允許負數,及倒數。。

includes和indexOf十分相似,但注意的是includes支援識別NaN等 

4、模板字串、用了這個就能減少字串的拼接了,最討厭的就是字串拼接,現在這種十分牛X的功能解決一項心腹大患

// ES6之前
let a = 'abc' + v1 + 'def';
// ES6之後
let a = `abc${v1}def`

5、箭頭函式,箭頭函式沒有作用域,this指向外部作用域,箭頭函式是函式的簡化  

var fn=x=>x;fn(5)
function fn(x){//不用箭頭函式
    return x
}

6、Array.from方法用於將類似陣列的物件或可遍歷的物件轉為真正的陣列

7、引數預設值

function log(x, y = 'World') {
	console.log(x, y);
}

log('Hello') 		// Hello World
log('Hello', 'China') 		// Hello China
log('Hello', '') 		// Hello
log('Hello', undefined)	// Hello World

8、

ES6 引入 rest 引數(形式為“...變數名”),用於獲取函式的多餘引數,這樣就不需要使用arguments物件了。rest 引數搭配的變數是一個數組,該變數將多餘的引數放入陣列中。

rest 引數中的變數代表一個數組,所以陣列特有的方法都可以用於這個變數。下面是一個利用 rest 引數改寫陣列push方法的例子。

	function push(array, ...items) {
		items.forEach(function(item) {
			array.push(item);
			console.log(item);
		});
	}

	var a = [];
	push(a, 1, 2, 3)

//注意,rest 引數之後不能再有其他引數(即只能是最後一個引數),否則會報錯。

9、Symbol型別,表示獨一無二的值。它是 JS 的第七種資料型別,前六種是:undefined、null、Boolean、String、Number、Object。

var s = Symbol();

typeof(s);

//產生的原因:為了防止重名造成的衝突,所以引入了Symbol。

10、ES6 提供了新的資料結構 Set。它類似於陣列,但是成員的值都是唯一的,沒有重複的值。

const s = new Set();
// 將陣列中的每個元素,通過add方法,新增到set結構中
[2, 3, 5, 4, 5, 2, 2].forEach(x => s.add(x));
console.log(Array.from(s));
console.log(s.size);	// 獲取長度
console.log(s.has(3));	// 是否存在元素3
console.log(s.delete(2));// 刪除元素2,如果刪除成功,則返回真
console.log(Array.from(s));
//s.clear();	// 清除所有元素,無返回值
//console.log(Array.from(s));
//遍歷:
let set = new Set(["ab", "xx", "123"]);
set.forEach((value, key, arr) => console.log(value, key, arr) )		// 注意:value和key相同
//forEach支援第二個引數,用來繫結this,但箭頭函式中,this永遠指向window
const obj = {
	fn: function(key, value) {
		console.log(key, value);
	}
};
let set = new Set(["ab", "xx", "123"]);
set.forEach(function(value, key, arr){
	this.fn(key, value);
}, obj)

11、map結構:

JavaScript 的物件(Object),本質上是鍵值對的集合(Hash 結構),但是傳統上只能用
字串當作鍵。這給它的使用帶來了很大的限制。

	const data = {};
	const element = document.getElementById('myDiv');

	data[element] = 'metadata';
	data['[object HTMLDivElement]'] // "metadata"

上面程式碼原意是將一個 DOM 節點作為物件data的鍵,但是由於物件只接受字串作為鍵名,
所以element被自動轉為字串[object HTMLDivElement]。
為了解決這個問題,ES6 提供了 Map 資料結構。它類似於物件,也是鍵值對的集合,
但是“鍵”的範圍不限於字串,各種型別的值(包括物件)都可以當作鍵。也就是說,
Object 結構提供了“字串—值”的對應,Map結構提供了“值—值”的對應,是一種更
完善的 Hash 結構實現。如果你需要“鍵值對”的資料結構,Map 比 Object 更合適。

	const m = new Map();
	const o = {p: 'Hello World'};
	console.log(o);	// {p: 'Hello World'}
	m.set(o, 'content')
	console.log(m.get(o)); // "content"
	console.log(m.has(o)); // true
	console.log(m.delete(o)); // true
	console.log(m.has(o)); // false	

上面程式碼使用 Map 結構的set方法,將物件o當作m的一個鍵,然後又使用get方法讀取這個鍵。

12、generators生成器函式,現在已經逐漸被async函式取代,但是redux-saga還是基於它實現的

注意:

  1. 與普通函式相比,生成器函式需要在 關鍵字function 和 函式名之間,加一個星號,星號前後是否寫空格無所謂,帶有星號的函式,就是生成器函式,即 Generator函式。

  2. yield類似return,中文為產出的意思,表示程式執行到 yield時,程式暫停,產出一個結果,這個結果為物件 {value: 值, done:[false| true]},value指的就是yield後面跟的值,done指程式是否已經完成。

  3. 生成器函式本身只返回一個物件,這個物件具有next方法,執行next方法時,函式體內容碰到yield才會暫停

Generator 函式,它最大的特點,就是可以交出函式的執行權,即暫停執行。

	function * fn(num1, num2){
		var a = num1 + num2;
		yield a;
		var b = a - num2;
		yield b;
		var c = b * num2;
		yield c;
		var d = c / num2;
		yield d;
	} 
	var f = fn(1, 2);
	console.log( f.next() );		//	{value:3, done:false}
	console.log( f.next() );		//	{value:1, done:false}
	console.log( f.next() );		//	{value:2, done:false}
	console.log( f.next() );		//	{value:1, done:false}
	console.log( f.next() );		//	{value:undefined, done:true}

es7:es7的內容就很少了,嚴格來說就兩點

1、Array.prototype.includes()方法

includes()用於查詢一個值是否在陣列中,如果在返回true,否則返回false

['a', 'b', 'c'].includes('a');     // true
['a', 'b', 'c'].includes('d');     // false

2.2 指數操作符(**)

let a = 3 ** 2 ; // 9
// 等效於
Math.pow(3, 2);  // 9

es8:es8主要更新了一個受人吹捧的async函式,非常好用,但還是基於promise的,所以promise還是很重要的!!!

ES8引入async函式,是為了使非同步操作更加方便,其實它就是Generator函式的語法糖。
async函式使用起來,只要把Generator函式的**(*)**號換成asyncyield換成await即可。對比如下:

// Generator寫法
const fs = require('fs');
const readFile = function (fileName) {
  return new Promise(function (resolve, reject) {
    fs.readFile(fileName, function(error, data) {
      if (error) return reject(error);
      resolve(data);
    });
  });
};
const gen = function* () {
  const f1 = yield readFile('/etc/fstab');
  const f2 = yield readFile('/etc/shells');
  console.log(f1.toString());
  console.log(f2.toString());
};

// async await寫法
const asyncReadFile = async function () {
  const f1 = await readFile('/etc/fstab');
  const f2 = await readFile('/etc/shells');
  console.log(f1.toString());
  console.log(f2.toString());
};

對比Genenrator有四個優點:

  • (1)內建執行器 Generator函式執行需要有執行器,而async函式自帶執行器,即async函式與普通函式一模一樣:
async f();
  • (2)更好的語義 asyncawait,比起星號yield,語義更清楚了。async表示函式裡有非同步操作,await表示緊跟在後面的表示式需要等待結果。
  • (3)更廣的適用性 yield命令後面只能是 Thunk 函式或 Promise 物件,而async函式的await命令後面,可以是 Promise 物件和原始型別的值(數值、字串和布林值,但這時等同於同步操作)。
  • (4)返回值是Promise async函式的返回值是 Promise 物件,這比 Generator 函式的返回值是 Iterator 物件方便多了。你可以用then方法指定下一步的操作。

進一步說,async函式完全可以看作多個非同步操作,包裝成的一個 Promise 物件,而await命令就是內部then命令的語法糖。

async函式返回一個Promise物件,可以使用then方法添加回調函式,函式執行時,遇到await就會先返回,等到非同步操作完成,在繼續執行。

async function f(item){
    let a = await g(item);
    let b = await h(item);
    return b;
}
f('hello').then(res => {
    console.log(res);
})

async表明該函式內部有非同步操作,呼叫該函式時,會立即返回一個Promise物件。
另外還有個定時的案例,指定時間後執行:

function f (ms){
    return new Promise(res => {
        setTimeout(res, ms);
    });
}
async function g(val, ms){
    await f(ms);
    console.log(val);
}
g('leo', 50);

async函式還有很多使用形式:

// 函式宣告
async function f (){...}

// 函式表示式
let f = async function (){...}

// 物件的方法
let a = {
    async f(){...}
}
a.f().then(...)

// Class的方法
class c {
    constructor(){...}
    async f(){...}
}

// 箭頭函式
let f = async () => {...}

返回Promise物件

async內部return返回的值會作為then方法的引數,另外只有async函式內部的非同步操作執行完,才會執行then方法指定的回撥函式。

async function f(){
    return 'leo';
}
f().then(res => { console.log (res) }); // 'leo'

async內部丟擲的錯誤,會被catch接收。

async function f(){
    throw new Error('err');
}
f().then (
    v => console.log(v),
    e => console.log(e)
)
// Error: err

await命令

通常await後面是一個Promise物件,如果不是就返回對應的值。

async function f(){
    return await 10;
}
f().then(v => console.log(v)); // 10

我們常常將async awaittry..catch一起使用,並且可以放多個await命令,也是防止非同步操作失敗因為中斷後續非同步操作的情況。

async function f(){
    try{
        await Promise.reject('err');
    }catch(err){ ... }
    return await Promise.resolve('leo');
}
f().then(v => console.log(v)); // 'leo'

使用注意

  • (1)await命令放在try...catch程式碼塊中,防止Promise返回rejected
  • (2)若多個await後面的非同步操作不存在繼發關係,最好讓他們同時執行。
// 效率低
let a = await f();
let b = await g();

// 效率高
let [a, b] = await Promise.all([f(), g()]);
// 或者
let a = f();
let b = g();
let a1 = await a();
let b1 = await b();
  • (3)await命令只能用在async函式之中,如果用在普通函式,就會報錯。
// 錯誤
async function f(){
    let a = [{}, {}, {}];
    a.forEach(v =>{  // 報錯,forEach是普通函式
        await post(v);
    });
}

// 正確
async function f(){
    let a = [{}, {}, {}];
    for(let k of a){
        await post(k);
    }
}

2、Object原型上加了一些方法,Object.values(),Object.entries()

我們知道Object.keys(),是把物件的key放到一個數組中,那麼values是把value放到陣列中,entries是把key,value都放到陣列中

var a = { f1: 'hi', f2: 'leo'};
Object.keys(a); // ['f1', 'f2']
let a = { f1: 'hi', f2: 'leo'};//如果不是物件返回空陣列
Object.values(a); // ['hi', 'leo']
let a = { f1: 'hi', f2: 'leo'};
Object.entries(a); // [['f1','hi'], ['f2', 'leo']]

3、字串填充 padStart和padEnd

用來為字串填充特定字串,並且都有兩個引數:字串目標長度填充欄位,第二個引數可選,預設空格。

'es8'.padStart(2);          // 'es8'
'es8'.padStart(5);          // '  es8'
'es8'.padStart(6, 'woof');  // 'wooes8'
'es8'.padStart(14, 'wow');  // 'wowwowwowwoes8'
'es8'.padStart(7, '0');     // '0000es8'

'es8'.padEnd(2);            // 'es8'
'es8'.padEnd(5);            // 'es8  '
'es8'.padEnd(6, 'woof');    // 'es8woo'
'es8'.padEnd(14, 'wow');    // 'es8wowwowwowwo'
'es8'.padEnd(7, '6');       // 'es86666'
從上面結果來看,填充函式只有在字元長度小於目標長度時才有效,若字元長度
已經等於或小於目標長度時,填充字元不會起作用,而且目標長度如果小於字元
串本身長度時,字串也不會做截斷處理,只會原樣輸出。