ES6基礎語法總結(大部分)

注:由於是直接從Typora文件複製粘貼過來的,因此有些格式可能會錯位,見諒 須要這個文件的同窗能夠直接發郵件給我 408579331@qq.comnode

參考阮一峯的ES6文檔(es6.ruanyifeng.com/#docs/let)

一:let 和 const 命令

1 let 命令
  • <1> 用於聲明變量,但聲明的變量只在當前代碼塊有效(塊級做用域),即做用域在 { } 內
  • <2> 不存在變量提高,即:無預解析
  • <3> 暫時性死區,即:只要 塊級做用域 中存在 let 命令,那麼他所聲明的變量就"綁定"到當前區域, ​ 不在受外部的影響,若 let 聲明的變量在此以前使用,則會報錯
  • <4> 不容許在同一個做用域中屢次聲明
  • <5> 【注:】ES5 只有函數做用域 和 全局做用域,沒有塊級做用域
var tem = 123;
if(true){
    console.log(tem); // 報錯
    let tem = 0;
}

let a = a ; // 報錯

let b = 0;
let b = 1; // 報錯
複製代碼
2 函數聲明

【注】ES5 中 不容許塊級做用域中聲明函數,但爲了兼容老代碼,因此ES6的規定中瀏覽器能夠不遵照此規定,有本身的行爲方式,因此通常函數的聲明會像 var同樣會進行函數名的提高,可是隻做用於當前的塊級做用域es6

【注】ES6 中 塊級做用域中函數的聲明必須包含在 { } 中,如 if(true) f(){}; 會報錯,正確寫法if(true) { f(){} };ajax

3 const 命令
  • <1> 用於聲明一個常量的值,一旦聲明,常量的值就不能改變,若改變則會報錯正則表達式

  • <2> 聲明時必須賦值,若只聲明不賦值,就會報錯算法

  • <3> 做用域與 let 相同,只存在於當前做用域中json

  • <4> 沒有預解析數組

  • <5> 存在暫時性死區的特性promise

  • <6> 同一個變量不能屢次聲明瀏覽器

    本質:const實際上保證的是變量指向的那個內存地址所保存的值是不能改變的,因此:服務器

    • 1. 當保存爲基本類型時,內存地址保存的就是一個值,此時就爲常量
    • 2. 當保存爲複雜類型時,內存地址保存的就是一個地址,即:指針,他只能保證這個地址不能改變,但不能保證這個地址指向堆中的數據不能改變,因此,將對象保存爲常量時需當心使用
const PI = 3.141592654;
console.log(PI);
PI = 3 ; // 報錯

const a ; //報錯

const b = [];
b.push('hello');  // 可執行
b.length = 10; // 可執行
b = ['aaa']  // 報錯

// 若是想將對象凍結,需使用 Object.freeze() 方法 freeze:凍結
var c = Object.freeze({});
// 常規模式下,下面這行代碼不起做用
// 嚴格模式下會報錯
c.prop = 123;
複製代碼
6 頂層對象

​ 在 ES5 中 瀏覽器的頂層對象就是 window ,頂層對象的屬性與全局變量時等價的 ​ Node 裏面,是 global ​ 在 ES6 中 ,var 和 function聲明的變量依舊是頂層對象的屬性,但 let const class 聲明的全局變量不屬於頂層對象的屬性

二:變量的解構賦值

1 數組的解構賦值

解構:ES6中容許按照必定模式,從數組和對象中提取值,對變量進行賦值,這稱之爲解構數組的解構賦值是按照元素的順序依次賦值

let [a,b,c] = [1,2,3]
	// a:1 b:2 c:3
let [,,a] = [1,2,3]
	// a:3
let [a,b] = [1,2,3]
	// a:1 b:2
let [a,...b] = [1,2,3,4]
	// a:1 b:[2,3,4]
	// ... 擴展運算符,將一個數組變成參數序列
let [a,b,...c] = [1]
	// a:1 b:undefined c:[]
let [a] = [];
	// a:undefined
let [a] = 1;
	// 報錯

// 默認值
	//**注意:當一個數組成員嚴格等於( === )undefined時,默認值纔會生效**
let [x=1] = [undefined];
	// x:1
let [x=1] = ['undefined'];
	// x:'undefined'
let [x=1] = [null];
	// x:null;
let [x=1] = [2];
	// x:2
複製代碼
2 對象的解構賦值

變量與對象的解構賦值是變量與屬性同名,再進行賦值 例:let {a} = {a:1}對象與對象的解構賦值是先找到同名的屬性,再賦值給對應的變量 例:let {a:b} = {a:1} b=>1

let {x,y}={x:1,y:2};
	// x:1 y:2;
// 當變量名與屬性名不一致時
let a = {x:1,y:2};
let {x:a,y:b}=a;
	// a:1 b:2

let {a:b} = {a:2};
	// b:2
	// a:報錯,not undefined
// 對象與對象的解構賦值的內部機制,是先找到同名屬性,而後再賦給對應的變量。真正被賦值的是後者,而不是前者

// 例:
	const node = {loc: {start: {line: 1,column: 5}}};
    let { loc, loc: { start }, loc: { start: { line }} } = node;
         console.log(loc); 		{start:{line:1,column:5}}
         console.log(start);	{line:1,column:5}
         console.log(line);		1
	let { loc, loc: { start }, loc: { start: { line }} } = 
        {loc: {start: {line: 1,column: 5}}};

// 例2
	let obj = {p: ['Hello',{ y: 'World' }]};    
    let { p, p: [x, { y }] } = obj;
    	console.log(p);		['Hello',{ y: 'World' }]
    	console.log(x);		'Hello'
    	console.log(y);		'World'

// 例3
	let obj = {};
    let arr = [];
    ({ foo: obj.prop, bar: arr[0] } = { foo: 123, bar: true });
        console.log(obj);	{prop:123}
        console.log(arr);	[true]
	不加一對小括號時,js在行首遇到{}會解析成代碼塊,從而引起語法錯誤

// 有默認值時
	//**注意:當一個數組成員嚴格等於( === )undefined時,默認值纔會生效**
	let {a,b=1}={a:1};
		// a:1 b:1
	let {x: y = 3} = {};
		// y:3 x:報錯,not undefined
	let {x,y = 3} = {};
		// y:3 x:undefined
	let {foo: {bar}} = {baz: 'baz'};
		// 報錯,由於foo是undefined,因此它的子對象就會報錯

// 數組的解構賦值
	let arr = [1, 2, 3];
	let {0 : first, [arr.length - 1] : last} = arr;
	// 因爲數組的本質是一個特殊的對象,因此 arr=>{0:1,1:2,2:3} ?
	console.log(first);
	console.log(last); 
複製代碼
3 字符串的解構賦值
const [a,b,c,d,e] = 'hello';
	// a:'h' 
	// b:'e' 
	// c:'l' 
	// d:'l' 
	// e:'o'

let {length:len} = 'hello'
	// len:5
	// 字符串是一個類數組,因此具備 length 屬性
複製代碼
4 數值和布爾值的解構賦值

解構賦值的規則:只要等號右邊的值不是對象或者數組,就先將其轉換成對象,在進行賦值

let {toString:s} = 123;
	s === Number.prototype.toString // true
let {toString:s} = true
	s === Boolean.prototype.toString // true
	// 由於 數值和布爾 的包裝對象都具備 toString 屬性,因此 變量s 都會被賦值

let {toString:x} = undefined ; // 報錯:TypeError
let {toString:x} = null ; // 報錯:TypeError
複製代碼
5 函數的解構賦值
function xy([a,b]){
    return a+b;
}
xy([1,2]) ===> 3

let arr = [[1,2],[3,4]].map(([a,b])=>a+b);
	// .map()方法:數組中的每個元素執行map方法中的函數或者方法,返回一個新的數組
	// arr ===> [3,7]

// 函數參數也可使用默認值
// 變量默認值
function xy({x=0,y=0}={}){
    return x+y;
}
	xy({x:1,y:2}) ===> 3
	xy({x:1,a:2}) ===> 1
	xy({}) ===> 0
	xy() ===> 0

// 參數默認值
function move({x,y}={x:0,y:0}){
    return x+y;
}
	move({x:1,y:2}) ===> 3
	move({x:1}) ===> NaN 由於 y的值是undefined,因此最終結果爲NaN
    move({}) ===> NaN
	// 注意:上述是爲參數指定默認值,而不是變量
複製代碼
6 用途
// (1). 交換變量的值
	let x = 1;
	let y = 2;
	[x,y] = [y,x];

// (2). 函數返回多個值
    function xy(){
		return [1,2,3,4];
    }
	let [a,b,c,d] = xy(); 
	// a:1 b:2 c:3 d:4

// (3). 函數參數的定義
	function xy([x,y,z]){ ... }
    	xy([1,2,3])
    function xy({x,y,z}){ ... }
    	xy({z:1 , y:2 , x:3})
                         
// (4). 提取 JSON 數據
    let jsonData = {
		id:1,
        status:'OK',
        data:[111,222]
    }
    let {id,status,data:arr} = jsonData;
     // id:1 status:'OK arr:[111,222]
                         
// (5). 函數參數的默認值
    let ajax = function(url,{ async = true, // async 異步 beforeSend = function(){},
        cache = true, // 隱藏
        complete = function(){}, // complete 完整的,完成
        crossDomain = false, // cross 交叉 domain 領域
        global = true, // 全球的,整體的
    } = {} ){ ... }
        
// (6). 遍歷map解構
        const map = new Map([
        	[{a:1},1];  // 鍵是對象
        	['a',1]		// 鍵是字符串
        ]);
    /* Map()構造函數,是一個鍵值對的集合,其中鍵能夠時任意類型 集合是一個數組,其中數組中的每個數組項都是Map實例的鍵和值*/
    map.set('first','hello');  	// 添加一組鍵值對
    map.get('first')		   	// 獲取指定的屬性值
    map.has('first')			// 判斷是否存在某個屬性,返回bool
    map.delete('first')			// 刪除指定的屬性,返回bool
    map.size;				   // 獲取數組的長度
    map.clear()					// 清除全部
    // map 的遍歷方法--返回一個迭代器,相似一個對象?
       .keys()	// 返回鍵名的遍歷器
       .values()	// 返回鍵值的遍歷器
       .entries()// 返回全部成員(鍵值對)的遍歷器
       .forEach()// 遍歷Map的全部成員
    // 例:
       for(let val of map.kes()){
       		console.lof(val);                    
       }
       for(let [key,value] of map.entries()){
       		console.lof(key+"==="+value);                    
       }  
       // 只想得到鍵名
       for(let [key] of map){
        	console.log(key);
       }
       // 只想得到值
       for(let [,val] of map){
            console.log(value);                 
       }      
// Set() 構造函數
複製代碼

三:字符串的擴展

1. 字符的 Unicode 表示法
// 能夠以 \uxxxx 表示一個字符,其中 xxxx 時 Unicode碼點
'\u{7A}' === 'z' 

複製代碼
2. codePointAt()
// 對於字節超出 Unicode 碼點的字符,charAt()方法沒法讀取
// 因此提供了 codePointAt()方法來讀取碼點

複製代碼
3. String.fromCodePoint()
// 經過碼點獲取字符,能夠識別編號大於 0xFFFF 的字符編碼
String.fromCodePoint(0x20BB7);

複製代碼
4. 字符串的遍歷器接口
// 使用 for of 遍歷字符串,能夠識別大於 0xFFFF 碼點的字符
for(let code of 'foo'){
    console.log(code); // 'f' 'o' 'o';
}

複製代碼
5. normalize()
/* 用於他國語言的語調符號和重音符號 Ǒ(\u01D1)和 O(\u004F)和ˇ(\u030C)合成Ǒ(\u004F\u030C) 兩種合成符的判斷,js中直接判斷爲false ,加上 .noemalize()方法後爲true */

複製代碼
6. 判斷字符串是否存在
let s = "Hello World";
s.startsWith("Hello")  // true 判斷參數是否在字符串的開頭
s.endWith("World")  // true 判斷參數是否在字符串的結尾
s.includes('o')  // true 判斷是否存在該字符串
s.startWith("World",6) // true 從第6個位置到結束是不是以"World"開頭
s.includes("Hello",6) // false 從第6個位置到結束中是否包含指定字符串
// 注意--------------
s.endWith("Hello",5) // 前5個字符中是否包含指定字符串

複製代碼
7. repeat()
// 返回一個新字符串,表示將指定字符串複製n次
let str = "a".repeat(2); // "aa";
let str = "xy".repeat(2); // "xyxy";
// 參數爲小數則會取整,負數則報錯,0則是一個空字符串
let str = "xy".repeat(2.9); //"xyxy"
let str = "xy".repeat(-1); // 報錯
let str = "xy".repeat(0); // 空字符串
// 若是參數是 0~-1之間的小數,則會先取整,也就是按 0 計算
// 若是參數是 NaN 則會按 0 進行計算
// 若是參數是字符串,則先會用 Number() 進行轉換再進行計算

複製代碼
8. padStart() padEnd()
// 字符串填充
.padStart()  // 頭部補全
.padEnd()	 // 尾部補全
'xy'.padStart(3,'0'); // "0xy"
'xy'.padEnd(4,'0'); // "xy00"
'xy'.padStart(5,'ab'); // "abaxy"
'xy'.padEnd(5,'ab'); // "xyaba"
// 第二個參數省略,默認用空格補全
'xy'.padEnd(5); // "xy "

複製代碼
9. matchAll()
// 返回一個正則表達式在當前字符串的全部匹配

複製代碼
10. 模板字符串
let str = `<div>${a+1}</div>`;
let str = `<div>${fn()}</div>`;

複製代碼
11. at()
// 返回指定索引對應的字符
let str = "123456"
at(0)  // 1

複製代碼

四 數值的擴展

1. Number.isInteger()
// 判斷一個數值是否爲整數
Number.isInteger(25); // true
Number.isInteger(25.5); // false

複製代碼
2. Number.EPSILON
/* 可以接受的偏差範圍 Number.EPAILON 是一個常量,表示1與大於1的最小浮點數之差,即 1 與 1.000...0001(51個零) 等同於 Math.pow(2,-52) 經常使用於浮點數計算後的偏差判斷,若是小於這個值,則表示偏差沒有意義,即:不存在偏差*/

   	function withinErrorMargin (left, right) {
  		return Math.abs(left - right) < Number.EPSILON * Math.pow(2, 2);
	}

複製代碼
3. Number.isSafeInteger()
// 判斷整數是否是在 -2^53 到 2^53 之間,由於在js內超過這個數值,判斷就會出錯
Number.isSafeInteger(num)  // 返回一個布爾值,注意,只判斷數字,其他都爲 false

複製代碼
4. Math靜態方法的擴展
// 1. Math.trunc() 
	// 用於去除一個數的小數部分,返回整數部分
		Math.trunc(1.222)  // 1
		Math.trunc(-0.111) // 0
	// 對於非數字,會先用 Number() 進行內部轉換
		Math.trunc(true) // 1
		Math.trunc(false) // 0
	// 轉換失敗則返回 NaN
		Math.trunc(NaN)  // NaN
		Math.trunc('foo') // NaN
		Math.trunc()	 // NaN
		Math.trunc(undefined)  // NaN

// 2. Math.sign() 
	// 判斷一個數是 正數 負數 零 ,若是是非數值,則會先進行 Number() 轉換
	// 返回 1:正數 -1:負數 0:零 -0:(輸入-0的時候) NaN:轉換失敗 報錯:參數語法錯誤時
		Math.sign(55)      // 1
		Math.sign(-1546)   // -1
		Math.sign(0)	   // 0
		Math.sign(-0)	   // -0
		Math.sign('ss')	   // NaN
		Math.sign(2aa)	   // 報錯

// 3. Math.cbrt()
	// 用於計算一個數的立方根 , 若是是非數值,則會先進行 Number() 轉換
	// 返回: 計算後的值 NaN
		Math.cbrt(8)	// 2
		Math.cbrt('8')	// 2
		Math.cbrt('ss')	// NaN
// 4. Math.hypot()
	// 返回全部參數的平方和的平方根
	// 若是參數不是數值,則會先用 Number() 進行轉換,只要有一個爲NaN,則返回 NaN
	// 能夠寫多個參數
		Math.hypot(3,4) // 5
		Math.hypot()    // 0
		Math.hypot(NaN)	// NaN
		Math.hypot(3,4,'a')  // NaN


複製代碼
5. ** 指數運算符
2 ** 2 // 4
2 ** 3 // 8
2 ** 4 // 16
// 計算方式是右結合,即從右往左計算
	2 ** 3 ** 2 ==> 2 ** (3 ** 2) // 512
// 能夠與 = 結合
	let a = 2;
	a **= 3 // 8 

複製代碼

五:函數的擴展

1 參數默認值
function abc(a=1, b=2){
    ruturn a+b;
}
// 注意:使用參數默認值時,函數不能有同名的形參
// 參數也能夠是一個表達式
	let i = 100;
    function abs(y = i + 1){
		console.log(y);
    }
	abs(); // 101

// 與解構賦值一塊兒使用
    function foo({x,y = 5} = {}){
        console.log(x,y);
    }
	foo({x:1, y:2}); // 1,2
	foo();			 // undefined 5
	// 注意,若是不設置默認值是 foo()調用會出錯,由於只有foo的參數是一個對象時,x,y纔會經過結構賦值生成,若果不生成就會報錯

// 當知道了默認值後,函數length屬性的計算將去掉該參數
// 函數.length : 該函數預約義傳入參數的個數
	(function(a, b = 1){}).length  // 1

// 做用域
// 當設置的參數的默認值時,函數聲明初始化時會造成一個單獨的 參數 做用域,當初始化結束,該做用域消失
// 若是沒有設置默認值,則不存在該做用域
	function abc(x, y = x){ return y;}
    	// 當abs進行初始化時,參數會造成一個單獨的做用域,此時 y 的默認值 x 指向 第一個參數 x
		// 因此 abc(90) 會返回 90 
	let x = 1;
    function foo(y = x){
		let x = 2;
        console.log(y);
    }
		// 當foo進行初始化時,參數會造成一個單獨的做用域,因爲做用域鏈的問題,因此 x 會像上查找,
		// 查找不到則會報錯,即:此時初始化結束後就至關於 y = 1 ; 


複製代碼
2. rest參數

ES6中引入了rest參數(形式爲 ...變量名),用於獲取函數的多餘參數,獲取後的格式爲一個數組

function foo(x, ...values){
    let sum = 0 + x;
    for(let val of values){
        sum += val;
    }
    return sum;
}
foo(1,2,3,4,5,6)   21
// 函數的 length 屬性不包括 rest 參數

複製代碼
3. name屬性
// 返回該函數的函數名
	function foo(){};
	foo.name; // 'foo'
	
	var a = function(){};
    a.name;   // ES5總爲 '' ES6中爲 'a'

複製代碼
4. 箭頭函數

注意:使用了箭頭函數後,這個函數裏面就沒有本身的this,裏面所出現的this是外部函數的this,而不是指向的this,這種狀況也稱爲this指向的固定化

// 只有一個參數
    let f = v => v;
    // 等同於
    let f = function (v) {
        return v;
    }

// 無參數
    let f = () => 5;
    // 等同於
    let f = function () {
        return 5;
    }

// 多個參數
    let sum = (num1,num2) => num1 + num2;
    // 等同於
    let sum  = function(num1, num2){
        return num1 + num2;
    }
    
// 返回一個對象
    // 因爲代碼塊是用 {} 包含起來的,因此返回一個對象時需用 () 包含起來,不然對象的 {} 會被解析成函數體
    let a = id => ({id:id,num:1})

// 與解構賦值一塊兒使用
    let a = ({first,last}) => first + '' + last;

// 與 rest 參數一塊兒使用
	let a = (...arr) => arr;

複製代碼
5. 雙冒號運算符

改變this指向,即:雙冒號左邊的對象是右邊函數中的this

// 1. obj::foo
	等同於 foo.bind(obj)

複製代碼
6. 尾調用優化

尾調用:指某個函數的最後一步調用了一個函數,即:return y(x); 的嚴格格式尾調用優化:每一次函數調用都會在內存中造成一個"調用記錄",又稱「調用幀」,保存調用位置和內部變量等信息,全部的調用幀稱之爲 調用棧 ,若是內部函數用到外部函數的變量,就不會進行尾調用優化

尾遞歸:函數調用自身,稱之爲遞歸,尾調用自身,稱之爲尾遞歸

六:數組的擴展

1. 擴展運算符
// ... ,將一個數組轉爲用逗號分割的參數列表,內部使用for...of循環
	console.log(...[1,2,3]) // 1 2 3
// 通常用於函數調用
	let arr = [1,2,3,4,5,6];
	foo(...arr)
// 數組最大值判斷
	let arr = [1,2,3,4,5,6];
	Math.max(...arr);
// 數組中的每一項添加到另外一個數組中
	let arr = [1,2,3,4];
	let brr = [5,6,7,8];
	arr.push(...brr);
// 數組複製--淺拷貝
	let arr = [1,2,3];
	let brr = [];
	brr = [...arr];
// 數組合並--淺拷貝
	let arr = [1,2,3,4];
	let brr = [5,6,7,8];
	let crr = [...arr , ...brr];
// 數組與結構賦值一塊兒使用
	const [first, ...rest] = [1, 2, 3, 4, 5];
	first // 1
	rest  // [2, 3, 4, 5]
// 字符串轉數組
    let arr = [...'hello']
    // ['h','e','l','l','o']
// 類數組轉換成規定的數組
    let liArr = document.querySelectorAll('li');
	let arr = [...liArr];
	/* query.selectorAll 方法返回的是一個NodeList對象。不是一個數組,而是一個相似數組的對象, 之因此能夠用數組的方法,是由於nodeList對象實現了Iterator(迭代)接口*/

複製代碼
2. Array.from()

將兩類對象轉換成規定的數組:相似數組的對象(具備length屬性),可遍歷迭代對象若是參數是一個規定的數組,該方法會返回一個如出一轍的新數組------即:複製

let arrayLike = {
    '0':'a',
    '1':'b',
    '2':'c',
    length:3
}
let arr = Array.from(arrayLike);
// ['a','b','c','d']

Array.from()方法還有第二個參數,做用相似於map()方法,將數組中的被一個元素進行處理並返回
Array.from(arr,x=>x*x)
// 等同於
Array.from(arr).map(x=>x*x);

// 例:取出每一個節點的內容,並造成一個數組
	let liObj = document.querySelectorAll('li');
	let arr = Array.from(li,v=>v.innerHTML);
// 例:將布爾值爲false的數組項轉換成0
	let arr = [1,2,,3,,5,,0,];
	let brr = Array.from(arr,v=>v||0);
	// [1, 2, 0, 3, 0, 5, 0, 0]

複製代碼
3. Array.of()

用於將一組值轉換成數組

Array.of(1,2,3);
	// [1,2,3]

複製代碼
4. entries() , keys() , values()
var arr = ['a','b','c', 1,2,3]
arr.keys(); 	// 返回一個對鍵名的遍歷器---- 一個對象
arr.values();	// 返回一個對鍵值的遍歷器---- 一個對象
arr.entries();	// 返回一個對鍵值隊的遍歷器---- 一個對象
// 遍歷器中有一個next()方法,裏面存放着一條數據,可循環調用來一次輸出結果
arr.keys().next(); === {value: 0, done: false}
arr.values().next(); === {value: "a", done: false}
arr.entries().next();  === {value: Array(2), done: false}
arr.entries().next().value; === [ 0,'a']
// 例:用 for of 來循環遍歷
    for(var [key,value] of arr.entries()){
		console.log(key+"="+value);
    }
	// 0='a' 1='b' 2='c' 3=1 4=2 5=3
 	

複製代碼
5. flat()
// 將多維數組「拉平」
	[1,[2]].flat(); 
	// [1,1]
	[1,[2,[3]]].flat(); 
	// [1,2,[3]] 默認拉平一層,從外向內拉平
// flat(number);
	number:設置拉平的層數
    Infinity 關鍵字,表示無限
// 若是數組有空位,flat()方法會跳過空位
    [1,2,3,,4].flat(); 
	// [1,2,3,4]

複製代碼
6. flatMap()
// 對原數組的每個成員執行一個函數(至關於執行了map()方法),返回一個新數組
// 執行完後再執行flat()方法
[1,2,3,4,5,6].flatMap(x=>x*x); //[1,4,9,16,25,36]
[1,2,3,4].flatMao(x=>[x,x*x]); //[1,1,2,4,3,9,4,16]

複製代碼
7. 數組的空位
/* ES6中 Array.from(),(...),entries(),keys(),values(),find(),findIndex() 等會將空位處理成 undefined */
	[...[,1]]  // [undefined,1]

複製代碼

七. 對象的擴展

1. 屬性簡潔寫法
// ES6 容許直接在對象中直接寫入變量,此時,變量名爲屬性名,變量值爲屬性值
	let aaa = 1;
	let obj = {aaa}; // {'aaa':1}

複製代碼
2. 屬性名錶達式
let aaa = 'a'
let obj = {
    ['a'+'bc']:1,
    [aaa]:2
}
obj.abc // 1
obj.a   // 2
obj.aaa // undefined
obj[aaa]// 2


複製代碼
3. 可枚舉性
// 對象中的每一個屬性的都有一個描述對象(Descriptor),用來控制該屬性的行爲
	Object.getOwnPropertyDescriptor() 方法能夠獲取該屬性的描述對象
    let obj = {foo:123};
	Object.getOwnPropertyDescriptor(obj,'foo');  // 返回一個對象
	// {
	// value: 123,
	// writable: true,
	// enumerable: true, //可枚舉性
	// configurable: true
	// }
	// 由於for in 遍歷會返回繼承的屬性,因此能夠經過設置 enumerable 屬性值爲 false 來讓其忽略該屬性
	Object.getOwnPropertyDescriptor(Object.prototype, 'toString')
// ES7 引入了Object.getOwnPropertyDescriptors方法,
	// 返回指定對象全部自身屬性(非繼承屬性)的描述對象

複製代碼
4. 屬性的遍歷
(1) for...in
    循環遍歷對象自身的和繼承的可枚舉屬性(不包含Symbol屬性)

(2) Object.keys(obj)
	返回一個數組,包含對象自身的全部屬性的(不含繼承)全部可枚舉屬性(不含Symbol屬性)的鍵名
   
(3) Object.getOwnPropertyNames(obj)
	返回一個數組,包含對象自身的全部屬性(不含Symbol屬性,可是包括不可枚舉屬性)的鍵名
    
(4) Object.getOwnPropertySymbols(obj)
	返回一個數組,包含對象自身的全部鍵名,無論鍵名時Symbol 或字符串,也無論是否可枚舉
  
(5) Reflect.ownKeys(obj)
	返回一個數組,包含對象自身的全部鍵名,無論鍵名時Symbol或者字符串,也無論是否可枚舉
 
// 以上 5 種遍歷對象的鍵名都遵照一樣的屬性遍歷的次序規則
    - 首先遍歷全部的數值鍵,按照數值升序排序
	- 其次遍歷全部的字符串鍵,按照加入時間升序排列
	- 最後遍歷全部訂單 Symbol 鍵,按加入時間升序排序
    // 例:
    Reflect.ownKeys({ [Symbol()]:0, b:0, 10:0, 2:0, a:0 })
	// ['2','10','b','a',Symbol()]

複製代碼
5. super 關鍵字

表示指向當前對象的原型對象

let obj = {
    foo:123,
    foo(){
      return super.name;
	}
};
    Object.prototype.name="ybm";
    console.log(obj.foo());
// 注意,此關鍵詞只能用於對象的方法中,在其餘地方使用會報錯
    let obj = {
        foo:super.name
    }
    // 報錯,該關鍵詞用於對象的屬性中
    let obj = {
        foo:()=>super.name
    }
    let obj = {
        foo:function (){
            return super.name;
        }
    }
    // 報錯,由於在JS引擎的解析中,此時的super用在一個函數中,而後賦值給foo屬性。
    // 因此,目前只有對象方法的簡寫形式可讓js引擎確認定義的是對象的方法
    /* 在JS引擎的內部,super.foo等同於 Object.getPrototypeOf(this).foo 屬性 或 Object.getPrototypeOf(this).foo.call(this) 方法 */

複製代碼

八. 對象的新增方法

1. Object.is()
// 比較兩個值是否相等 可比較特殊的字符
Object.is(NaN,NaN) 	// true
Object.is(+0,-0)   	// false
Object.is({},{})	// false
Object.is(+0,0)		// true
Object.is(-0,0)		// false


複製代碼
2. Object.assign()
// 用於的對象的合併,將源對象的全部可枚舉的屬性複製到目標對象中,不拷貝繼承迭代屬性
// 若屬性名相同,則後面對象的屬性值會覆蓋前面的屬性值
    Object.assign(目標對象,源對象)
    const target = {a:1};
    const target1 = {b:2};
    const target2 = {c:3};
    const target3 = {a:4};
    Object.assign(target,target1,target2,target3)
// target {a:4,b:2,c:3};
// 第二個參數能夠爲一個字符串,若是是字符串,就會以數組的形式拷貝進目標的對象
// 數值和布爾類型則不會起做用
	let str = "abc";
	let obj = {a:1};
	Object.assign(obj,str);
	// obj {'0':'a', '1':'b', '2':'c', a:1}

// 1. 爲對象添加方法
    Object.assign(SomeClass.prototype,{
        someMethod(a,b){

        },
        anotherMethod(){

        }
    })
	// 等同於下面的寫法
	SomeClass.prototype.someMethod = function(a,b){};
	someClass.prototype.anotherMethod = function(){};

// 2. 拷貝對象
    function clone(obj){
        return Object.assign({},obj);
        // 此方法只能拷貝自身的值,不能拷貝繼承的值
    }

// 3. 合併多個對象
	const merge = (target,...sources) => Object.assign(target,...sources);


複製代碼
3. Object.getOwnPropertyDescriptors()
// 返回指定對象全部自身屬性(非繼承屬性)的描述對象
const obj = {
    foo:123,
    get bar(){return 'abc'}
};
Object.getOwnPropertyDescriptors(obj);
// { foo:
// { value: 123,
// writable: true,
// enumerable: true,
// configurable: true },
// bar:
// { get: [Function: get bar],
// set: undefined,
// enumerable: true,
// configurable: true } }

複製代碼
4. Object.create()
// 建立一個新對象,並指定新對象的 __proto__ 指向
// 語法 Object.create(proto); 第一個參數爲新對象的原型指向
	let obj1 = {a:1};
	let obj2 = Object.create(obj);
	obj2.a; // 1

複製代碼
5. Object.setPrototypeOf()
// 設置指定對象的原型對象,並返回當前對象
// 語法:Object.setPrototypeOf(object,prototype);
	let obj1 = {a:1};
	let obj2 = {b:2};
	Object.setPrototypeOf(obj1, obj2);
	obj1.b; // 2

複製代碼
6. Object.getPrototypeOf()
// 返回指定對象的原型對象
let obj = Object,getPrototypeOf(obj1);
obj {b:2};

複製代碼
7. keys() values() entries()
// Object.keys(obj) 
// 返回一個數組,成員是參數對象自身的(不含繼承的)全部可遍歷屬性的鍵名
	var obj = {foo:'bar',baz:44};
	var arr = Object.kes(obj);
	arr ['foo','baz'];

// Object.values()
// 返回一個數組,成員是參數對象自身的(不含繼承的)全部可遍歷屬性的屬性值
	var obj = {a:1,b:2};
	var arr = Object.values(obj);
	arr [1,2];

// Object.entries() 不支持IE
// 返回一個二維數組,每個數組項是參數對象自身的(不含繼承的)全部可遍歷屬性
// 的鍵值對造成的數組,忽略 Symbol
	var obj = {a:1,b:2};
	var arr = Object.entries(obj);
	arr [['a',1],['b',2]]

複製代碼
8. Object.fromEntries()
// Object.fromEntries() 方法是 Object.entries() 的逆操做,
// 用於將一個鍵值對數組轉換成一個鍵值對形式的對象
// 注:只兼容火狐瀏覽器
	Object.fromEntries([
  		['foo', 'bar'],
  		['baz', 42]
	])
    // { foo: "bar", baz: 42 }

複製代碼

九. Symbol

/* 1. Symbol 值經過 Symbol()函數生成 2. Symbol 函數能夠接受一個字符串做爲參數,表示對Symbol實例的描述 3. Symbol 能夠顯式轉換成字符串,布爾值,但不能轉換成數字 */
let si = Symbol('foo')
console.log(si)// Symbol(foo)

/*用法?*/
let abc = Symbol('abc');
let obj = {
    [abc]:'456',
    'abc':'457',
}

複製代碼

十 Set和Map 構造函數

1. Set構造函數

new Set() 生成的是Set的數據結構,其結構內不會有重複的值,是一個類數組對象

內部判斷兩個值是否相同使用的算法叫作「Same-value-zero equality」,相似於 === 比較,可是該算法中 NaN與NaN相等

let arr = [1,1,2,2,3,3]
const a = new Set();
arr.forEach(x=>a.add(x));
for(let i of a){
    console.log(i)
}//1 2 3 4

//1. Set函數能夠接受一個數組或具備iterable接口的其餘數據結構做爲參數
	例一:數組爲參數
        const set = new Set([1,2,3,4,5,6]);
        [...set] // [1,2,3,4,5,6]
	例二:具備iterable接口的僞數組做爲參數
    	const set = new Set(document.querySelectorAll('div'));
		set.size; // 110

//2. 數組去重
	var arr = [1,2,3,1,1,2,3,4];
	[...new Set(arr)]; // [1,2,3,4]

//3. 字符串去重
	var str = '123132451234561321';
	[...new Set(str)].join(''); // "123456"

//4. NaN
	var [a,b] = [NaN,NaN];
	let set = new Set();
	set.add(a);set.add(b);
	[...set]; // [NaN]
	
//5. 並集,交集,差集
	let a = new Set([1,2,3]);
	let b = new Set([2,3,4]);
	// 並集
		[...new Set(...a,...b)]; //[1,2,3,4]
	// 交集
		[...new Set([...a].filter(x=>b.has(x)))]; //[2,3]
	// 差集
		[...new Set([...a].filter(x=>!b.has(x)))]; //[1]

// Set 結構的實例屬性
	Set.prototype.constructor :構造函數,默認就是Set函數
    Set.prototype.size :返回 Set 實例的成員總數
// Set 結構的實例方法
    // 1> 操做方法
    	.add(value) :添加某個值,返回Set結構自己
    	.delete(value) :刪除某個值,返回一個布爾值,表示刪除是否成功
    	.has(value) :判斷是否存在這個值,返回一個布爾值
    	.clear() :清除全部的成員,無返回值
    // 2> 遍歷方法、
    	.keys() :返回鍵名的遍歷器
    	.value() :返回鍵值的遍歷器
    	.entries() :返回鍵值對的遍歷器
    	.forEach() ;使用回調函數遍歷每一個成員
    	// 因爲 Set 結構沒有鍵名(或者說鍵名和鍵值是同樣的),因此keys() 和 values() 方法獲得的結果同樣
    	var arr = [1,2,3];
		let set = new Set();
    	for (let item of set.entries()) {
          	console.log(item); // [1,1] [2,2] [3,3]
        }
    // Set 結構的實例默認是可遍歷的,默認遍歷器生成函數就是它的values方法
    // 因此能夠直接省略values方法,直接用 for...of遍歷
        for (let item of set) {
			console.log(item); // 1 2 3 
        }

複製代碼
2. WeakSet結構

1. 與Set相似,也是不重複的值的集合,可是WeakSet的成員只能是對象2. WeakSet爲弱引用,即:垃圾回收機制不計算WeakSet對該對象的引用次數。因此,WeakSet適合存儲一些臨時數組,當該數組在外部引用此時爲0時,他在WeakSet中的引用就會自動消失3. 因爲成員是弱引用,隨時會消失,因此ES6規定WeakSet不可遍歷4. 該構造函數能夠接受一個數組,或者一個類數組(具備 Iterable 接口)對象,該數組的成員會自動轉換成WeakSet實例對象的成員

// WeakSet結構的三個方法
	-WeakSet.prototype.add(value);
	-WeakSet.prototype.delete(value);
	-WeakSet.prototype.has(value);

let arr = [[1,2],[2,3]];
var weak = new WeakSet(arr);
// {[1,2],[2,3]}

複製代碼
3. Map數據結構

1. js對象本質上是鍵值對的集合,可是傳統上只能用字符串做爲鍵,因此限制性大,所以ES6提供了一種新的數據結構,相似對象,也是一個鍵值對的集合,但鍵名能夠是任意類型

// 實例的屬性和操做方法
	.size  //放回Map結構的成員總數
    .set(key,value)  //添加或者更新一組鍵值對,返回整個Map數據結構
	.get(key)  //返回指定鍵的值,若不存在,則返回undefined
	.has(key)  //判斷是否存在指定鍵,返回布爾值
	.delete(key)  //刪除指定鍵
	.clear(key)   //刪除全部的鍵,無返回值
// 遍歷方法---遍歷順序就是插入順序
	keys():返回鍵名的遍歷器。
	values():返回鍵值的遍歷器。
	entries():返回全部成員的遍歷器。
	forEach():遍歷 Map 的全部成員。
    // 默認的遍歷器接口爲entries()


// 1. 基本使用方法
	let map = new Map();
	let m = {a:'1'};
	map.set(m, 'content');
	map.get(m); // content;
	map.has(m); // true;
	map.delete(m); // true;
	map.has(m); // false
// 2. 能夠接受一個雙成員的二維數組,或者具備Iterable接口,且每一個成員都是一個雙元素的類數組對象做爲參數
	let map2 = new Map([['a',1],['b',10]]);
	map2.get('a'); // 1
	map2.get('b'); // 10

	// 使用Set 和 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

// 3. 讀取一個未知鍵,則返回undefined
	new Map().get('a'); // undefined

// 4. 在Map中 NaN與NaN相等
	let mp = new Map();
	mp.set(NaN,'1');
	mp.set(NaN,'2');
	mp.get(NaN); // 2

複製代碼
4. WeakMap

WeakMap結構與Map結構相同,也是用於生成鍵值對的集合1. 只接受鍵名做爲鍵名,2. 鍵名所對應的值不計入垃圾回收機制

// 通常用於對象在未來會消失,這樣這個對象所對應的鍵值也會被回收,不須要手動回收
    let myElement = document.getElementById('logo');
	let myWeakmap = new WeakMap();
	myWeakmap.set(myElement, {timesClicked: 0});
	myElement.addEventListener('click', function() {
  		let logoData = myWeakmap.get(myElement);
  		logoData.timesClicked++;
	}, false);
    // 當DOM元素被刪除時,WeakMap中該對象所對應的鍵值對也會自動刪除

// 操做方法
	.set()
	.get()
	.has()
	.delete()

複製代碼

十一:Promise

一種異步解決的方案,一個容器,保存着將來某個時間段某個異步操做的結果

特色:1. promise對象的狀態不受外界所改變,它表明着一種異步操做,有三種狀態:pending(進行中),fulfilled(成功),rejected(失敗),只有結果才能獲取是哪種狀態2. 狀態一旦改變一次,就不可再次更改,狀態改變只有兩種:pending--fulfilled,pending--rejected。只要這兩種情況發生,狀態就定型了,這是就稱爲resolved(已定型)

缺點1. 沒法取消,一旦新建就會當即執行,沒法中途取消2. 若是不設置回調函數,promise內部出現的錯誤不會反應到外部3. 當處於pending狀態時,不知道目標是處於那一階段(剛開始or已完成)

// 基本使用:
const promise = new Promise(function(resolve, reject){
    // 異步代碼...
    if('異步成功時'){
        resolve();//成功的回調函數調用
    }else{
        reject();//失敗的回調函數調用
    }
})
promise.then(callback1,callback2);
//.then()方法用於綁定該對象結果的兩個階段所對應的回調函數
//.then()方法會在當前腳本全部同步任務執行完後纔會執行
//若是第一個.then()方法中返回的是一個promise對象,
// 那麼第二個.then()方法會等待第一個的狀態改變時再來判斷是否執行
promise.then().catch(callback)
//.catch()方法:當異步操做拋出錯誤或者回調函數運行出錯時會被被該方法捕獲
//若是promise的狀態已經爲成功狀態,那麼再拋出異常就會無效 

複製代碼
.finally()
// 用於指定無論promise對象最後的狀態如何,都會執行的操做
promise.then(result => {...})
	   .catch(error => {...})
       .finally(()=>{...})
   // 本質是then()方法的特例,等同於
       .then(result => {},error => {}) //成功或者失敗的方法各寫一遍
       
// 例:請求完後關閉服務器
   promise.then().finally(server.stop);
                   

複製代碼
Promise.all()
// 用於將多個Promise實例,包裝成一個新的Promise實例,並返回
const p = Promise.all([p1, p2, p3]);
/* 接受一個數組做爲參數,數組中的每個成員都是一個Promise實例 p的狀態由 p1,p2,p3決定, 當3個都爲fulfilled時,p的狀態才爲fulfilled,此時p1,p2,p3的返回值會組成一個數組傳遞給p的回調函數 當其中一個爲reject時,p的狀態爲rejected,此時第一個rejected狀態的實例的返回值會傳遞給p的回調函數 注意:若做爲參數的promise實例本身定義了catch方法,那麼就不會觸發Promise.all()所定義的catch() */	

複製代碼
Promise.race()
// 用於將多個Promise實例,包裝成一個新的Promise實例
const p = Promise.race([p1, p2, p3]);
/* 接受一個數組做爲參數,數組中的每個成員都是一個Promise實例 當參數中某個Promise實例的狀態率先發生改變時,p的狀態也會發生改變,率先改變的返回值會傳遞給p的回調函數 */	
// 指定時間內沒有得到結構就返回rejected
var p = Promise.race([p1,
                      new Promise((res,error)=>{ 
                      	setTimeout(()=>{error();},5000);	
                      })]);
p.then().catch();	// 第一個參數5秒內沒有執行成功就拋出失敗

複製代碼
Promise.resolve()
將現有對象轉換成一個Promise對象
const ps = Promise.resolve(對象)
// 當參數是一個thenable對象,即:具備then()方法的對象時,轉換完後會當即執行該方法
// 當參數不是具備then()方法的對象,或根本不是一個對象時,該方法會自動生成一個新的Promise對象,狀態爲
// 成功狀態,並把參數傳遞給相對應的對調函數
// 當無參數時,該方法會自動建立一個新的Promise對象,狀態爲成功狀態

複製代碼
promise.reject()
返回一個新Promise實例,狀態爲rejected,並當即執行回調函數
//注:與resolve()不一樣的是reject()方法會把建立時的參數原封不動的傳遞給回調函數

複製代碼
promise.try()

爲了方便無論是同步仍是異步都用promise管理代碼

十二:Iterator(遍歷器)

是一種接口,爲不一樣的數據結構提供一種統一的訪問機制,任何數據只要部署了Iterator接口均可以完成遍歷操做

遍歷過程:

  • (1)建立了一個指針對象(即:遍歷器對象),指向當前數據結構的起始位置
  • (2)第一次調用指針對象的next()方法,指針就指向數據結構的第一個成員
  • (3)第二次調用指針對象的next()方法,指針就指向數據結構的第+-q二個成員
  • (4)依次類推,不斷調用指針對象的<fontcolor=red>next()方法,直到它指向數據結構的結束位置
  • 每一次調用next方法,都會返回數據結構的當前成員信息。即:一個包含 valuedone 兩個屬性的對象,其中 value 屬性時當前成員的值,done 屬性是一個布爾值,表示遍歷是否結束

ES6 規定,默認的 Iterator 接口部署在數據結構的Symbol.iterator屬性,這個屬性是一個函數表達式,執行它就會返回一個遍歷器for...of循環會調用Symbol.iterator屬性,返回返回對象中的value值

// 模擬next()方法
function makeIterator(obj){
    let nextIndex = 0;
    return {
        next:()=>{
            return nextIndex < obj.length ?
                {value:obj[nextIndex++], done:false}:
            	{value:undefined, done:true}
        }
    }
}

var arr = [1,2,3];
var obj = makeIterator(arr);
obj.next(); //{value:1}
obj.next(); //{value:2}
obj.next(); //{value:3}
obj.next(); //{done:true}


複製代碼
1.元素js中具備Iterator接口的數據結構:
Array
Map
Set
String
TypedArray
函數的 arguments 對象
NodeList 對象(相似數組的對象)
// 例:調用數組的 Symbol.iterator屬性
var arr = [1,2]
var iter = arr[Symbol.iterator]()
	// Symnol值要用[]括起來
iter.next(); // {value:1, done:false}
iter.next(); // {value:1, done:false}
iter.next(); // {value:undefined, done:false}

複製代碼
2.調用Iterator接口的場合
1. 解構賦值
var arr = new Set().add(1).add(2).add(3)
var [x,y] = arr // x:1 y:2
var [first,...rest] = arr  //first:1 rest:[2,3]

2. 擴展運算符
var arr = "hello"
[...arr] // ['h','l','l','o']

3. 特殊的類數組對象:
	例:querySelectorAll()
	例:
    	var arrayLike1 = {  
            0: 'a', 
            1: 'b',
            length: 2,
        	[Symbol.iterator]: Array.prototype[Symbol.iterator] 
            // 須要具備Symbol.iterator屬性
        };

        // 報錯
        for (let x of arrayLike1) {
          console.log(x);
        }

複製代碼
3. 任何接收數組做爲參數的場合
-for...of
-Array.from()
-Map(),Set(),WeakMap(),WeakSet()
-Promise.all()
-Promise.race()

複製代碼
4.遍歷器對象的return(),throw()方法
/* 遍歷器除了具備next()方法,還具備return()方法和throw()方法 當for...of循環提早退出(出錯時 或 break語句),就會調用 return 方法 注意:return方法必須返回一個對象,這是Generator規格規定 */
function readLinesSync(file) {
  return {
    [Symbol.iterator]() {
      return {
        next() {
          return { done: false };
        },
        return() {
          file.close();
          return { done: true };
        }
      };
    },
  };
}
// 狀況一
for (let line of readLinesSync(fileName)) {
  console.log(line);
  break;
}
/* 當執行break方法後就會執行遍歷器的return()方法 */
// 狀況二
for (let line of readLinesSync(fileName)) {
  console.log(line);
  throw new Error();
}
/* 狀況二在執行return方法關閉文件以後,再拋出錯誤 */

複製代碼

十三:Generator 函數

1.函數定義
// 1. function關鍵字與函數名的中間用 * 號鏈接
// 2. 函數體內部用 yield 表達式來表示不一樣的狀態
// 3. 調用Generator函數後返回一個遍歷器對象,即:指針對象,注:此時Generator函數內部代碼尚未執行
// 4. 遍歷器對象使用.next()方法進行執行函數體代碼,直到遇到 yield 表達式 或 return 語句中止
// 5. 遇到yield表達式時next()方法返回一個對象,{value:當前yield表達式的值, done:布爾值(當前遍歷的狀態)}
// 6. yield 關鍵字至關於一個暫停符,.next()方法就爲恢復執行
// 7. 返回的遍歷器對象不是this對象
// 8. 遍歷器對象能夠調用函數原型上的方法

function* hello(){
    console.log(1)
    field 'a'
    console.log(2)
    field 'b'
    console.log(3)
    return 'c'+'d'
    console.log(4)
}
var hl = hello()
hl.next() // 1 {value:a, done:false}
hl.next() // 2 {value:b, done:false}
hl.next() // 3 {value:cd, done:true} 遇到return時 done的值就爲 true
hl.next() // {value:undefined, done:true} // 由於上一句已經return了,因此4不會被輸出


複製代碼
2.next()方法的參數
// 1. yield 表達式自己是沒有返回值的,或者說老是undefined
// 2. next()方法能夠帶一個參數,該參數就會被看成上一個yield表達式的返回值
// 3. 所以第一個調用.next()方法裏面傳參是無效的,V8引擎會直接忽略第一次調用的參數
// 4. 調用函數後需調用一次next()方法來啓動Generator函數的內部代碼

function* f() {
  for(var i = 0; true; i++) {
    var reset = yield i;
    if(reset) { i = -1; }
  }
}
var g = f();
g.next() // { value: 0, done: false }
g.next() // { value: 1, done: false }
g.next() // { value: 2, done: false }
g.next(true) // { value: 0, done: false }
    // 前三次執行時,reset爲undefined,第四次執行時,next()方法傳了一個參數true,
	// 因此yield表達式的,返回值就爲true,i=1,i++就爲0

// 此特性能夠在特定階段從函數外部向內部傳入值
    function* foo(x) {
      var y = 2 * (yield (x + 1));
      var z = yield (y / 3);
      return (x + y + z);
    }
    var b = foo(5);
    b.next() // { value:6, done:false }
    b.next(12) // { value:8, done:false }
    b.next(13) // { value:42, done:true }

複製代碼
3.for ... of 循環
// for ... of 循環能夠自動遍歷Generator函數時所生成的iterator對象
// ----------------------------------------------------------
for in // 遍歷的是數組的索引--即鍵名
    ---遍歷時會包括數組的原型屬性和方法,因此通常用來遍歷對象而不是數組	
    ---用 arr.hasOwnPropery(屬性) 方法可判斷該屬性是否是該對象的實例屬性
    ---數組的鍵名是數字時,for..in循環會轉換成字符串獲取
    ---某些狀況下,遍歷順序是任意的
for of // 遍歷的是數組的元素值
    ---遍歷時不包括數組的原型屬性和方法
    ---遍歷數組時只返回具備數字屬性的值
// 例:實現斐波那鍥數列
function* fbnq(){
    let [a,b] = [0,1]
    for(;;){
        yield b
        [a,b] = [b,a+b] 
    }
}
for(var n of fbnq()){
    if(n>1000) break
    console.log(n)
}

複製代碼
4. return()方法
// 調用遍歷器對象的return()方法後返回對象中的value值就是return()方法的參數,而且done的值爲true
// 此時,Generator函數的遍歷就會中止,若是無參數,則value值爲undefined
function* gen() {
  yield 1;
  yield 2;
  yield 3;
}
var g = gen();
g.next()        // { value: 1, done: false }
g.return('foo') // { value: "foo", done: true }
g.next()        // { value: undefined, done: true }

複製代碼
5.yield* 表達式
// 用於在一個Generator函數中調用另一個Generator函數
// yield* 表示返回的是一個遍歷器對象,若不加js不會自動識別,會輸出這個對象

// 無 return 語句時
function* foo(){
    yield 'a'
    yield 'b'
}
function* bar(){
    yield 'x'
    yield* foo()
    yield 'y'
}
for(let n of bar()){
    console.log(n) // 'x' 'a' 'b' 'y'
}

// 有 return 語句時,能夠用一個變量來接收 field* foo 表達式的返回值
function* foo(){
    yield 'a'
    yield 'b'
    return 'c'
}
function* bar(){
    yield 'x'
    let a = field* foo()
    console.log(a)
    yield 'y'
}
for(let n of bar()){
    console.log(n) // 'x' 'a' 'b' 'c'y'
}

// 例:利用yield* 命令遍歷取出二維數組
function* iterTree(tree) {
  if (Array.isArray(tree)) {
    for(let i=0; i < tree.length; i++) {
      yield* iterTree(tree[i]);
    }
  } else {
    yield tree;
  }
}
const tree = [ 'a', ['b', 'c'], ['d', 'e'] ];
for(let x of iterTree(tree)) {
  console.log(x);
}
or  [...iterTree(tree)]

複製代碼
6 做爲對象屬性的 Generator 函數
let obj = {
    * myGeneratorMethod(){}  // myGeneratorMethod: function* (){}
}

複製代碼
7 狀態判斷保存
var clock = function* () {
  while (true) {
    console.log('Tick!');
    yield;
    console.log('Tock!');
    yield;
  }
};

複製代碼
8 Thunk 函數
// 傳值調用:參數爲表達式時,表達式在進入函數體以前就已經計算完成
// 傳名調用:參數爲表達式時,表達式只有在函數體中使用到時才進行計算

Thunk 函數的定義:將一個參數放到一個臨時函數內,再把臨時函數當參數傳入函數體中,
				這個臨時函數就是Thunk函數

複製代碼

十四:async函數

// 1. 語法與 Generator 函數類似
var asyncRead = async function(){
    const f1 = await f1()
}
// 1. 返回一個promise對象
// 2. 有兩個關鍵字 async await 分別對應 * yield
// 3. async 函數內置執行器,即:不須要像Generator函數須要.next()方法執行
// 4. await命令後面能夠是promise對象和原始數據類型(可是這時會當即自動轉換成resolved 的 promise對象)
// 5. async函數內部return 語句返回的值會成爲then方法回調函數的參數
// 6. async函數內部拋出錯誤會直接返回的Promise對象的變成reject狀態,而後被catch捕獲
// 7. 當遇到第一個await時,後面的代碼都會被放入隊列中執行
// 8. 只有當await後面的promise對象執行完後,他的狀態纔會改變
// 9. 只用當async函數內部的全部異步操做執行完後纔會執行then方法
// 10 若將異步操做放到try...catch裏面,則該異步操做不管是否成功,後面的異步操做都會繼續執行


複製代碼
1. 異步函數的觸發
// 1. 順序觸發
async function myFunction() {
    await getFoo()
    await getBar()
} // 只用getFoo()執行完後 getBar()纔會執行
// 2. 同時觸發
async function myFunction() {
    var fooPromise = getFoo()
    var barPromise = getBar()
    await fooPromise
    await barPromise
    // 此時就至關於兩個異步函數的執行結果被await攔截了
}
async function myFunction() {
	var [foo,bar] = await Promise.all([getFoo(),getBar()])
}


複製代碼

十五:Class類

1.定義
// Class 類的基本使用
class Point{
    constructor() {
        // 實例屬性
        this.name = 2
    }
    // 原型對象上的實例方法
    toString() {}
    // 靜態屬性
    static a = '41'
	// 靜態方法
	static show(){ }
}

var p = new Point()
p.toString()
// 1. 使用方法與構造函數相同
// 2. 方法之間不須要用逗號分隔
// 3. 類中的全部方法其實是定義在 類名的prototype上
    即等同於:Point.prototype = {
		constructor(){},
        toString(){}
    } 
	因此類的實例調用方法其實就是調用原型上的方法
// 4. 類中的全部的方法都是不可枚舉的
    Object.keys(Point.prototype) //[]
// 5. 類沒有變量提高

// 類名錶達式
	var cls = class Me{}
	var cls = class {}
	var cls = new class {} // 這樣就能夠直接調用class裏面的方法了


複製代碼
2. constructor() 方法
// 1. 每一個類在建立的時候必須有一個constructor()方法
// 2. 若是沒有顯示建立,則系統會默認建立一個
// 3. 該方法會在 new 命令後自動調用,默認返回實例對象,即:this,也能夠改寫此屬性,返回另外一個對象
class Point {
    z = 0;
  constructor(x, y) {
    this.x = x;
    this.y = y;
  }
  toString() {
    return '(' + this.x + ', ' + this.y + ','this.z+')';
  }
}
var p = new Point(1,2)
p.toString() // (1,2)

複製代碼
3. get set關鍵字
// 在類的內部經過 set get 關鍵字來攔截某個屬性的存取值的操做
// 調用時不能加括號,當表達式調用
class MyClass{
    set prop(val){
        this.val = val
        console.log(this.val+'a')
    }
    get prop(){
        console.log(this.val)
    }
}
var myclass = new MyClass()
myclass.prop = 1 // 注意,此時沒有加小括號 '1a'
myclass.prop 1


複製代碼
4. extends
// 繼承
	class Bar{}
    class aaa extends Bar {
        constructor(){
            super(); // 該關鍵詞的做用是調用父類的constructor方法,子類中必須寫,
            				// 不然建立實例時報錯---重寫constructor()時
        			 // 做爲對象時表明指向父類的原型對象,在靜態方法中,指向父類
            		 // 由於指向的是原型對象,因此父類上實例的屬性和方法,super訪問不到
            		 // 經過super調用父類上方法中的this表明的是當前子類的實例
        }
    }

// super()當函數時使用
class A {
    constructor(name,age){
        this.name = name
        this.age = age
    }
    say(){
        console.log(this.name,this.age)
    }
}
class B extends A{
    constructor(...args){
        super(...args) // 分配內存空間,指向this,同時將父類的屬性掛載到this上
        			   // super時父類構造器的一個引用,調用super就是調用父類的構造函數
        			   // super前不能使用this
    }
}
const b = new B('xy', 18)


// super當對象時使用
class A {
  p() {
    return 2;
  }
}
class B extends A {
  constructor() {
    super();
    console.log(super.p()); // 2
  }
}
let b = new B();

複製代碼
5. 屬性
// name屬性
	class Bar{}
	Bar.name // 'Bar'

// this
	class 中的 this 是指向當前實例 // static // 當一個方法名前加了static關鍵詞時,該方法就不會被實例所繼承,但能夠被他的 子類 繼承 class Bar{
        static add(){this}
        // 注意:其中的this是指類,而不是指實例
    }
// 靜態屬性的定義
    class Bar{
    }
	Bar.a = 1 //注意,寫在外面

複製代碼
6. Object.getPrototypeOf()
// 該方法能夠從子類上獲取父類
Object.getPrototypeOf(子類名) === 父類名
// 能夠用該方法來判斷一個類是否繼承了另外一個類

複製代碼
相關文章
相關標籤/搜索