ES6简单总结(搭配简单的讲解和小案例)
在學習es6的過程中,為了方便自己復習,以及查看,對api做了一個極簡用例介紹。如有錯誤多多指正。
一 let和const
1.let
(1)一個大括號就是一個塊級作用域,let聲明的變量只在自己作用域有效; (2)es6強制開啟嚴格模式,變量未聲明不能引用,所以會報 Uncaught ReferenceError
function test() {for (let i = 1; i < 3; i++) {console.log(i)}console.log(i); // Uncaught ReferenceError: i is not defined } test(); 復制代碼(3)let不能重復聲明
function test() {let a = 1; let a = 2; } test(); 復制代碼(4)let不存在變量提升(這個地方有問題)
// var 的情況 console.log(a); // 輸出undefined var a = 2;// let 的情況 console.log(b); // 報錯ReferenceError let b = 2; 復制代碼2.const
(1)const聲明之后必須賦值,否則會編譯不通過; (2)const聲明的值不允許修改;
const PI = 3.14; // PI = 2; // const PI; console.log(PI); 復制代碼(3)const如果是對象的話,可以向對象中添加屬性,也可以修改a的屬性;json是指向內存地址的一個指針,指針的指向不變,但是那個被json指針所指向的內存地址所存儲的內容是可以變化的;
const json = {a: 2 } json.a = 3; json.b = 3; console.log(json.a) //3 console.log(json.b) //3 復制代碼二 解構賦值
1.基本用法
先上兩個例子了解什么是解構賦值
{let a, b, rest;[a, b, rest] = [1, 2];console.log(a, b, rest); //1 2 undefined } 復制代碼{let a, b, rest;[a, b, ...rest] = [1, 2, 3, 4, 5, 6, 7];console.log(a, b, rest); //1 2 [3, 4, 5, 6, 7] } 復制代碼2.對象的解構賦值
{let a, b;({ a, b } = { a: 1, b: 2 }); //a,b 順序不影響其結構結果console.log(a, b); // 1 2 } 復制代碼3.默認值
{let a, b, rest;[a, b, rest = 3] = [1, 2]; console.log(a, b, rest); // 1 2 3 } 復制代碼4.實際應用
變量的交換
{let a = 1;let b = 2;[a, b] = [b, a];console.log(a, b); //2 1 } 復制代碼接收函數返回的值
{function f() {return [12, 13];}let a, b;[a, b] = f();console.log(a, b); //12 13 }{function f() {return [12, 13, 14, 15, 16];}let a, b;[a, , , b] = f(); //函數返回多個值,可以選擇性的接收對應的值console.log(a, b); // 12 16 }{function f() {return [12, 13, 14, 15, 16];}let a, b;[a, , ...b] = f(); //取出對應的值,其他的值可以直接賦值給數據console.log(a, b); // 12 [14, 15, 16] } 復制代碼5.對象的解構賦值的應用
{let o = { p: 42, q: true };let { p, q } = o;console.log(p, q); //42 true }{let { a = 10, b = 11 } = { a: 3 } // 對象的默認值更改console.log(a,b); // 3, 11 } 復制代碼6.解構賦值的簡單應用舉例
{let metaData = {title: 'abc',test: [{title: 'gaojingbo',desc: 'description'}]}let { title: esTitle, test: [{ title: cnTitle }] } = metaData;console.log(esTitle, cnTitle); } 復制代碼三 正則的擴展
1.構造函數來創建正則
{let regex1 = new RegExp('xyz', 'i');let regex2 = new RegExp(/xyz/i);console.log(regex1.test('xyz123'), regex2.test('xyz123')); // true truelet regex3 = new RegExp(/xyz/ig, 'i'); // 后面的修飾符會把前面的修飾符給覆蓋掉console.log(regex3.flags); // es6新增的,用來獲取正則表達式的修飾符 } 復制代碼2.g修飾符和y修飾符
y修飾符的作用與g修飾符類似,也是全局匹配,后一次匹配都從上一次匹配成功的下一個位置開始。不同之處在于,g修飾符只要剩余位置中存在匹配就可,而y修飾符確保匹配必須從剩余的第一個位置開始。
{let s = 'bbb_bb_b';let a1 = /b+/g; // g只要匹配到都算let a2 = /b+/y; // y必須是下一個開始的字母開始匹配console.log('one', a1.exec(s), a2.exec(s)); // g修飾符匹配到都可以,y修飾符必須從第一個開始匹配,如果一第個不是b則會輸出nullconsole.log('two', a1.exec(s), a2.exec(s)); // 第二次匹配,g修飾符會只要匹配到都可以,y修飾符必須從緊鄰的下一個字符開始匹配console.log(a1.sticky, a2.sticky); // 判斷是否開啟了y修飾符 false true } 復制代碼one和two的輸出結果
3.u修飾符(unicode)
ES6 對正則表達式添加了u修飾符,含義為“Unicode模式”,用來正確處理大于\uFFFF的 Unicode 字符。
{console.log('u-1', /^\uD83D/.test('\uD83D\uDC2A')); // 不加u把后面的四個字節當成兩個字符console.log('u-2', /^\uD83D/u.test('\uD83D\uDC2A')); // 加u把后面的4個字節當作一個字符console.log(/\u{61}/.test('a')); // false 大括號括起來代表一個unicode字符,所以必須加u才能識別console.log(/\u{61}/u.test('a')); // trueconsole.log(`\u{20BB7}`);let s = '?';console.log('u-1', /^.$/.test(s)); //false 字符串大于兩個字節,必須加u修飾符才能匹配到console.log('u-2', /^.$/u.test(s)); //trueconsole.log('test-1', /?{2}/.test('??')); // falseconsole.log('test-2', /?{2}/u.test('??')); // true } 復制代碼四 字符串擴展
1.unicode的表示方法
{console.log('a', '\u0061'); // a aconsole.log('s', '\u20BB7'); // s ?7 把前兩個字節當作一個整體console.log('s', '\u{20BB7}'); // s ? unicode編碼用{}可以正常識別 } 復制代碼2.codePointAt和charCodeAt的對比
對于4個字節的字符,JavaScript不能正確處理,字符串長度會誤判為2,而且charAt方法無法讀取整個字符,charCodeAt方法只能分別返回前兩個字節和后兩個字節的值。ES6提供了codePointAt方法,能夠正確處理4個字節儲存的字符,返回一個字符的碼點。
{let s = '?';console.log(s.length); // 2console.log('0', s.charAt(0)); // 0 � //es5未對多個字節的字符做處理console.log('1', s.charAt(1)); // 1 �console.log('at0', s.charCodeAt(0)); //at0 55362console.log('at1', s.charCodeAt(1)); //at1 57271let s1 = '?a';console.log('length', s1.length); // 3console.log('code0', s1.codePointAt(0)); // code0 134071console.log('code0', s1.codePointAt(0).toString(16)); // code0 es6會自動把多個字節的字符當作一個整體來處理 console.log('code1', s1.codePointAt(1)); // code1 57271console.log('code2', s1.codePointAt(2)); // code2 97 } 復制代碼3.fromCharCode和fromCodePoint
ES5提供String.fromCharCode方法,用于從碼點返回對應字符,但是這個方法不能識別Unicode編號大于0xFFFF。ES6提供了String.fromCodePoint方法,可以識別大于0xFFFF的字符,彌補了String.fromCharCode方法的不足。在作用上,正好與codePointAt方法相反。注意,fromCodePoint方法定義在String對象上,而codePointAt方法定義在字符串的實例對象上。
{console.log(String.fromCharCode('0x20bb7')); //?console.log(String.fromCodePoint('0x20bb7')) //? } 復制代碼4.字符串遍歷器
{// es5let str = '\u{20bb7}abc';for (let i = 0; i < str.length; i++) {console.log('es5', str[i]);//� � a b c }//es6for (let code of str) {console.log('es6', code);// ? a b c} } 復制代碼5.一些常用的字符串api
{let str = 'string';console.log('includes', str.includes('c')); // 判斷是否包含 falseconsole.log('start', str.startsWith('s')); // 以什么開頭 trueconsole.log('end', str.endsWith('ng')); // 以什么結尾 trueconsole.log('repeat', str.repeat(2)); // 字符串重復兩次 stringstring } 復制代碼ES6 引入了字符串補全長度的功能。如果某個字符串不夠指定長度,會在頭部或尾部補全。padStart()用于頭部補全,padEnd()用于尾部補全。如果原字符串的長度,等于或大于指定的最小長度,則返回原字符串。如果用來補全的字符串與原字符串,兩者的長度之和超過了指定的最小長度,則會截去超出位數的補全字符串。
{console.log('1'.padStart(2,'0')); // 01console.log('1'.padEnd(2,'0')); // 10 } 復制代碼6.模板字符串
{let name = "List";let info = "hello world";let m = `i am ${name} ${info}`;console.log(m); //i am List hello world } 復制代碼7.標簽模板
{let user = {name:'list',info:'hello world'}function fn(s,v1,v2){console.log(s,v1,v2);return s+v1+v2;}console.log(fn`i am ${user.name} ${user.info}`) // ``符號相當于一個函數的參數fn(i am ${user.name} ${user.info}); } 復制代碼輸出結果
8.String.row API
ES6還為原生的String對象,提供了一個raw方法。String.raw方法,往往用來充當模板字符串的處理函數,返回一個斜杠都被轉義(即斜杠前面再加一個斜杠)的字符串,對應于替換變量后的模板字符串。
{console.log('raw '+String.raw`hi\n${1+2}`)console.log('noRaw '+`hi\n${1+2}`) } 復制代碼輸出結果
五 數值擴展
1.二進制八進制表示法
從 ES5 開始,在嚴格模式之中,八進制就不再允許使用前綴0表示,ES6進一步明確,要使用前綴0o表示。如果要將0b和0o前綴的字符串數值轉為十進制,要使用Number方法。
{console.log('B',0b11010101010); //二進制表示,b大小寫都可以console.log('O',0O1237637236); // 八進制表示法 } 復制代碼2.Number.isFinite()和Number.isNaN()
Number.isFinite()用來判斷數字是否有限(無盡小數),Number.isNaN()來判斷一個數是不是小數
{console.log('15',isFinite(15)); //trueconsole.log('NaN',isFinite(NaN)); //falseconsole.log('1/0',isFinite(1/0)); //falseconsole.log('isNaN',Number.isNaN(15)); // falseconsole.log('isNaN',Number.isNaN(NaN)); // true } 復制代碼3.Number.isInteger
Number.isInteger用來判斷一個數是不是整數
{console.log('13',Number.isInteger(13)); // trueconsole.log('13.0',Number.isInteger(13.0)); // true console.log('13.1',Number.isInteger(13.1)); //falseconsole.log('13',Number.isInteger('13')); // false } 復制代碼4.Number.MAX_SAFE_INTEGER,Number.MIN_SFAE_INTEGER和isSafeInterger
Number.MAX_SAFE_INTEGER,Number.MIN_SFAE_INTEGER表示js可以準確表示的值的范圍,isSafeInterger用來判斷這個值是否在安全范圍內。
{console.log(Number.MAX_SAFE_INTEGER,Number.MIN_SFAE_INTEGER);console.log('15',Number.isSafeInteger(15));console.log('9999999999999999999999',Number.isSafeInteger(9999999999999999999999)); } 復制代碼5.Math.trunc和Math.sign
Math.trunc方法用于去除一個數的小數部分,返回整數部分。Math.sign方法用來判斷一個數到底是正數、負數、還是零。對于非數值,會先將其轉換為數值。
{console.log('4.1',Math.trunc(4.1)); //4console.log('4.9',Math.trunc(4.9)); //4 } {console.log('-5',Math.sign(-5)) //-1console.log('5',Math.sign(5)) //+1console.log('0',Math.sign(0)) //0console.log('50',Math.sign(50)) //+1console.log('NaN',Math.sign(NaN)) //NaN } 復制代碼6.cbrt
cbrt用來計算一個數的開方
{console.log('-1',cbrt(-1)); //-1console.log('8',cbrt(8)); //2 } 復制代碼六 數組擴展
1. Array.of
Array.of方法用于將一組值,轉換為數組,這個方法的主要目的,是彌補數組構造函數Array()的不足。因為參數個數的不同,會導致Array()的行為有差異。
{let arr = Array.of(1,2,3,4);console.log('arr=',arr); // arr= [1, 2, 3, 4]let emptyArr = Array.of();console.log(emptyArr); // []//與Array方法對比Array() // []Array(3) // [, , ,]Array(3, 11, 8) // [3, 11, 8] } 復制代碼2.Array.from
Array.from方法用于將兩類對象轉為真正的數組:類似數組的對象和可遍歷的對象(包括ES6新增的數據結構Set和Map)。
<p>你好</p> <p>我好</p> <p>大家好</p>{let p = document.querySelectorAll('p');let pArr = Array.from(p);pArr.forEach(function(item){console.log(item.textContent); // 你好 我好 大家好})console.log(Array.from([1,3,5],function(item){return item*2})) // [2,6,10] } 復制代碼3.Array.fill
fill方法使用給定值,填充一個數組。
{console.log('fill-7',[1,3,'undefined'].fill(7)); //[7,7,7]console.log('fill,pos',[1,2,3,4,5,7,8].fill(7,1,4)); //[1, 7, 7, 7, 5, 7, 8] // 后兩個參數表示索引的位置 } 復制代碼4.entries(),keys() 和 values()
ES6 提供三個新的方法——entries(),keys()和values()——用于遍歷數組。
{for(let index of [1,2,3,4].keys()){console.log('index',index);// index 0// index 1// index 2// index 3}for(let value of [1,2,3,4].values()){console.log('value',value);// value 1// value 2// value 3// value 4}for(let [index,value] of [1,2,4,5,6].entries()){console.log(index,value);// 0 1// 1 2// 2 4// 3 5// 4 } } 復制代碼5.Array.copyWithin
截取一定長度的數字并且替換在相對應的索引的位置
{console.log([1,4,9,6,7,2,3].copyWithin(1,3,5)); // [1, 6, 7, 6, 7, 2, 3] // 截取3-5的位置的數字,從索引1的位置開始替換console.log([1,4,9,6,7,2,3].copyWithin(1,3,6)); // [1, 6, 7, 2, 7, 2, 3] } 復制代碼6.findIndex和find
數組實例的find方法,用于找出第一個符合條件的數組成員。它的參數是一個回調函數,所有數組成員依次執行該回調函數,直到找出第一個返回值為true的成員,然后返回該成員。如果沒有符合條件的成員,則返回undefined。數組實例的findIndex方法的用法與find方法非常類似,返回第一個符合條件的數組成員的位置,如果所有成員都不符合條件,則返回-1。
{console.log([1,2,3,4,5,6].find(function(item){return item > 3})); //4console.log([1,2,3,4,5,6].findIndex(function(item){return item > 3})); // 3 } 復制代碼7.includes
Array.prototype.includes方法返回一個布爾值,表示某個數組是否包含給定的值,與字符串的includes方法類似。ES2016 引入了該方法。
{console.log([1,2,NaN].includes(1)); // trueconsole.log([1,2,NaN].includes(NaN)); // true } 復制代碼8.擴展運算符
擴展運算符(spread)是三個點(...)。將一個數組轉為用逗號分隔的參數序列。
console.log(...[1, 2, 3]) // 1 2 3console.log(1, ...[2, 3, 4], 5) // 1 2 3 4 5[...document.querySelectorAll('div')] // [<div>, <div>, <div>] 復制代碼七 函數擴展
1.默認值
ES6 之前,不能直接為函數的參數指定默認值;ES6允許為函數的參數設置默認值,即直接寫在參數定義的后面。
{function fn(x,y='hello'){ // 默認值后面不能再出現形參console.log(x,y);}fn('word'); // word hellofn('word','nihao') // word nihao }{let a = 'nihao';function test(a,b=a){ //1.//let a = 1; 參數變量是默認聲明的,所以不能用let或const再次聲明console.log(a,b);}test('word'); // word word test(); //undefined undefined } {let a = 'nihao';function test(x,b=a){ //2.console.log(x,b)}test('hello');// hello nihao } 復制代碼3.rest參數
ES6 引入rest參數(形式為...變量名),用于獲取函數的多余參數,這樣就不需要使用arguments對象了。rest參數搭配的變量是一個數組,該變量將多余的參數放入數組中。
{function fn(...arg){for(let v of arg){console.log(v);}}fn(1,2,3,4);//1//2//3//4 } {console.log(...[1,2,3,4]); // 1,2,3,4console.log('a',...[1,2,3,4]); // a,1,2,3,4 } 復制代碼4.箭頭函數
ES6 允許使用“箭頭”(=>)定義函數。
{let arr = v => v*2;console.log(arr(2));var sum = (num1, num2) => { return num1 + num2; } //如果箭頭函數的代碼塊部分多于一條語句,就要使用大括號將它們括起來,并且使用return語句返回。 } 復制代碼使用注意點 箭頭函數有幾個使用注意點。
(1)函數體內的this對象,就是定義時所在的對象,而不是使用時所在的對象。
(2)不可以當作構造函數,也就是說,不可以使用new命令,否則會拋出一個錯誤。
(3)不可以使用arguments對象,該對象在函數體內不存在。如果要用,可以用 rest 參數代替。
(4)不可以使用yield命令,因此箭頭函數不能用作 Generator 函數。
5.綁定 this
函數綁定運算符是并排的兩個冒號(::),雙冒號左邊是一個對象,右邊是一個函數。該運算符會自動將左邊的對象,作為上下文環境(即this對象),綁定到右邊的函數上面。
foo::bar; // 等同于 bar.bind(foo);foo::bar(...arguments); // 等同于 bar.apply(foo, arguments);const hasOwnProperty = Object.prototype.hasOwnProperty; function hasOwn(obj, key) {return obj::hasOwnProperty(key); } 復制代碼尾調用(Tail Call)是函數式編程的一個重要概念,本身非常簡單,一句話就能說清楚,就是指某個函數的最后一步是調用另一個函數。
{function fn1(x){console.log('fn1',x);}function fn2(x){return fn1(x); // 對fn1的調用必須在最后一步操作}fn2(2); } 復制代碼八 對象擴展
1.屬性的簡介表示法
ES6 允許直接寫入變量和函數,作為對象的屬性和方法。這樣的書寫更加簡潔。
{let a = 5,b=6;let es5 = {a:a,b:b}let es6 = {a,b}console.log(es5,es6) // {a: 5, b: 6} {a: 5, b: 6}let es5_fn = { // fn:function(){console.log('hello')}}let es6_fn = {fn(){console.log('hello')}}console.log(es5_fn.fn,es6_fn.fn); } 復制代碼2.動態key值
es6允許屬性的key值是動態的變量
{let a = 'b';let es5_obj = {a:'c',b:'c'}let es6_obj = {[a]:'c' // a是動態的變量,可以自由賦值}console.log(es5_obj, es6_obj); } 復制代碼3.Object.is
這個方法相當于es5 中的 ===,來判斷屬性是否相等
{console.log('is',Object.is('a','a')); // trueconsole.log('is',Object.is([],[])); // false 數組對象擁有不同的地址, } 復制代碼4.Object.assign
Object.assign方法用于對象的合并,將源對象的所有可枚舉屬性,復制到目標對象。
{console.log('拷貝',Object.assign({a:1},{b:2})); //淺拷貝let test = {a:2,b:3}for(let [key,value] of Object.entries(test)){ // 遍歷console.log([key,value]); //[a:2]//[b:3]} } 復制代碼九 Symbol
1.Symbol簡單舉例
ES6引入了一種新的原始數據類型Symbol,表示獨一無二的值。
{let a1 = Symbol();let a2 = Symbol();console.log(a1===a2) // falselet a3 = Symbol.for('a3');let a4 = Symbol.for('a3');console.log(a3===a4); //true } 復制代碼2.Symbol的一些API
Symbol.for可以用來命名具有相同的key值的對象。 Object.getOwnPropertySymbols方法返回一個數組,成員是當前對象的所有用作屬性名的 Symbol 值。 Reflect.ownKeys方法可以返回所有類型的鍵名,包括常規鍵名和 Symbol 鍵名。
{let a1 = Symbol.for('abc');let obj = {[a1]:123,abc:234,c:345}console.log(obj); // abc:234// c:345// Symbol(abc):123Object.getOwnPropertySymbols(obj).forEach(function(item){console.log('symbol',item,obj[item]); //symbol Symbol(abc) 123})Reflect.ownKeys(obj).forEach(function(item){console.log(item,obj[item]); //abc 234//c 345//Symbol(abc) 123})} 復制代碼十 Map和Set數據結構
1.set的基本用法
ES6 提供了新的數據結構 Set。它類似于數組,但是成員的值都是唯一的,沒有重復的值。Set 本身是一個構造函數,用來生成 Set 數據結構。 Set 結構不會添加重復的值
{let list = new Set();list.add(2);list.add(3);console.log(list.size); //2let arr = [1,2,3,4,5];let list2 = new Set(arr);console.log(list2.size); //5console.log(list2) //{1, 2, 3, 4, 5}let arr2 = [1,2,3,4,2,1]; //這里可以當作數組去重let list3 = new Set(arr2);console.log(list3) //{1, 2, 3, 4}} 復制代碼add(value):添加某個值,返回Set結構本身。 delete(value):刪除某個值,返回一個布爾值,表示刪除是否成功。 has(value):返回一個布爾值,表示該值是否為Set的成員。 clear():清除所有成員,沒有返回值。
{let arr = ['add','delete','clear','has'];let list = new Set(arr);console.log(list); // {"add", "delete", "clear", "has"}list.delete('add');console.log(list); // {"delete", "clear", "has"}console.log(list.has('clear')); // truelist.clear(); console.log(list); //{}//set遍歷方法{let arr = ['add','delete','clear','has'];let list = new Set(arr);for(let key of list.keys()){console.log('keys',key)//keys add//keys delete//keys clear//keys has}for(let value of list.values()){console.log('values',value)//values add//values delete//values clear//values has}for(let [key,value] of list.entries()){console.log(key,value);//add add//delete delete//clear clear//has has}list.forEach(function(item){console.log(item)})// add// delete// clear// has} }復制代碼2.WeakSet基本用法
WeakSet結構與Set類似,也是不重復的值的集合。但是,它與 Set有兩個區別。首先,WeakSet 的成員只能是對象,而不能是其他類型的值。 WeakSet中的對象都是弱引用,即垃圾回收機制不考慮 WeakSet 對該對象的引用,也就是說,如果其他對象都不再引用該對象,那么垃圾回收機制會自動回收該對象所占用的內存,不考慮該對象還存在于 WeakSet 之中。 WeakSet.prototype.add(value):向 WeakSet 實例添加一個新成員。 WeakSet.prototype.delete(value):清除 WeakSet 實例的指定成員。 WeakSet.prototype.has(value):返回一個布爾值,表示某個值是否在
{const ws = new WeakSet();ws.add(1)// TypeError: Invalid value used in weak setws.add(Symbol())// TypeError: invalid value used in weak setlet weakset = new WeakSet() // 沒有clear,set方法,不能遍歷let obj = {} weakset.add(obj)// weekset.add(2) WeakSet必須添加的是對象,弱引用 console.log(weakset); } 復制代碼3.Map的基本用法
ES6 提供了 Map 數據結構。它類似于對象,也是鍵值對的集合,但是“鍵”的范圍不限于字符串,各種類型的值(包括對象)都可以當作鍵。也就是說,Object結構提供了“字符串—值”的對應,Map結構提供了“值—值”的
{const map = new Map([['name', '張三'],['title', 'Author']]);map.size // 2map.has('name') // truemap.get('name') // "張三"map.has('title') // truemap.get('title') // "Author" } {let map = new Map();let arr = ['123'];map.set(arr,'456');console.log(map,map.get(arr)) // {["123"] => "456"} "456" }{let map = new Map([['a',123],['b',456]])console.log(map); //{"a" => 123, "b" => 456}console.log(map.size); //2console.log('123'+map.delete('a')); //trueconsole.log(map) // {"b" => 456}map.clear()console.log(map); //{} } 復制代碼4.WeakMap的一些API
WeakMap只接受對象作為鍵名(null除外),不接受其他類型的值作為鍵名。 WeakMap的鍵名所引用的對象都是弱引用,即垃圾回收機制不將該引用考慮在內。因此,只要所引用的對象的其他引用都被清除,垃圾回收機制就會釋放該對象所占用的內存。也就是說,一旦不再需要,WeakMap里面的鍵名對象和所對應的鍵值對會自動消失,不用手動刪除引用。 WeakMap 與 Map 在 API 上的區別主要是兩個,一是沒有遍歷操作(即沒有key()、values()和entries()方法),也沒有size屬性。因為沒有辦法列出所有鍵名,某個鍵名是否存在完全不可預測,跟垃圾回收機制是否運行相關。這一刻可以取到鍵名,下一刻垃圾回收機制突然運行了,這個鍵名就沒了,為了防止出現不確定性,就統一規定不能取到鍵名。二是無法清空,即不支持clear方法。因此,WeakMap只有四個方法可用:get()、set()、has()、delete()。
{let weakmap = new WeakMap() //沒有clear,set方法,不能遍歷let o = {}weakmap.set(o,123);console.log(weakmap.get(o)); } 復制代碼十一 proxy和reflect
1.Proxy
Proxy用于修改某些操作的默認行為,等同于在語言層面做出修改,所以屬于一種“元編程”(meta programming),即對編程語言進行編程。Proxy 可以理解成,在目標對象之前架設一層“攔截”,外界對該對象的訪問,都必須先通過這層攔截,因此提供了一種機制,可以對外界的訪問進行過濾和改寫。Proxy這個詞的原意是代理,用在這里表示由它來“代理”某些操作,可以譯為“代理器”。
{let obj = {name:'gaojingbo',time:'2017-08-13',emp:'123',}let temp = new Proxy(obj,{get(target,key){return target[key].replace('2017','2018');},set(target,key,value){if(key === 'name'){return target[key] = value;}else{return target[key];}},has(target,key){if(key === 'name'){return target[key];}else{return false;}},deleteProperty(target,key){if(key.indexOf('i') > -1){delete target[key];return true;}else{return target[key];}},ownKeys(target){return Object.keys(target).filter(item=>item!='name');}})console.log('get',temp.time); //get 2018-08-13temp.time = '2018';console.log('set',temp.name,temp); //set gaojingbo {name: "gaojingbo", time: "2017-08-13", temp: "123"}temp.name = 'hexiaofei';console.log('set',temp.name,temp); // set hexiaofei {name: "hexiaofei", time: "2017-08-13", temp: "123"}console.log('has','name' in temp,'time' in temp); //has true falsedelete temp.time;console.log('delete',temp); //delete {name: "hexiaofei", temp: "123"}console.log('ownkeys',Object.keys(temp)); //["emp"] } 復制代碼2.Reflect
Reflect對象與Proxy對象一樣,也是 ES6 為了操作對象而提供的新 API。Reflect對象的設計目的有這樣幾個。 (1) 將Object對象的一些明顯屬于語言內部的方法(比如Object.defineProperty),放到Reflect對象上。現階段,某些方法同時在Object和Reflect對象上部署,未來的新方法將只部署在Reflect對象上。也就是說,從Reflect對象上可以拿到語言內部的方法。 (2) 修改某些Object方法的返回結果,讓其變得更合理。比如,Object.defineProperty(obj, name, desc)在無法定義屬性時,會拋出一個錯誤,而Reflect.defineProperty(obj, name, desc)則會返回false。 (3) 讓Object操作都變成函數行為。某些Object操作是命令式,比如name in obj和delete obj[name],而Reflect.has(obj, name)和Reflect.deleteProperty(obj, name)讓它們變成了函數行為。 (4)Reflect對象的方法與Proxy對象的方法一一對應,只要是Proxy對象的方法,就能在Reflect對象上找到對應的方法。這就讓Proxy對象可以方便地調用對應的Reflect方法,完成默認行為,作為修改行為的基礎。也就是說,不管Proxy怎么修改默認行為,你總可以在Reflect上獲取默認行為。
{let obj = {name:'gaojingbo',time:'2017-08-13',emp:'123',}console.log('reflect get',Reflect.get(obj, 'name')); // reflect get gaojingboReflect.set(obj,'name','hexaiofei');console.log(obj); // {name: "hexaiofei", time: "2017-08-13", emp: "123"}console.log('reflect has', Reflect.has(obj,'name')); //reflect has true } 復制代碼3.簡單應用
{function validator(target,validator) {return new Proxy(target,{_validator:validator,set(target,key,value,proxy){if(target.hasOwnProperty(key)){let va = this._validator[key];if(!!va(value)){return Reflect.set(target,key,value,proxy);}else{throw Error(`不能設置${key}到${value}`);}}else{throw Error(`${key}不存在`);}}})}const personValidators={name(value){return typeof value === 'string'},age(value){return typeof value === 'number' && value > 18;}}class Person{constructor(name,age) {this.name = name;this.age = age;return validator(this,personValidators)}}const person = new Person('lilei',30);console.log(person);person.name = 48;} 復制代碼十二 Class的基本語法
1.簡介
ES6 提供了更接近傳統語言的寫法,引入了Class(類)這個概念,作為對象的模板。通過class關鍵字,可以定義類。基本上,ES6的class可以看作只是一個語法糖,它的絕大部分功能,ES5 都可以做到,新的class寫法只是讓對象原型的寫法更加清晰、更像面向對象編程的語法而已。
{class Parent {constructor(name='gaojingbo') {this.name = name;} }let v_parent = new Parent();console.log(v_parent); //{name: "gaojingbo"} } 復制代碼2.繼承
Class可以通過extends關鍵字實現繼承,這比ES5的通過修改原型鏈實現繼承,要清晰和方便很多。
{class Parent {constructor(name='gaojingbo') {this.name = name;} }class child extends Parent {}let v_child = new child();console.log(v_child); //{name: "gaojingbo"} } 復制代碼3.constructor
constructor方法是類的默認方法,通過new命令生成對象實例時,自動調用該方法。一個類必須有constructor方法,如果沒有顯式定義,一個空的constructor方法會被默認添加。
4.super關鍵字
super這個關鍵字,既可以當作函數使用,也可以當作對象使用。在這兩種情況下,它的用法完全不同。第一種情況,super作為函數調用時,代表父類的構造函數。ES6 要求,子類的構造函數必須執行一次super函數。第二種情況,super作為對象時,在普通方法中,指向父類的原型對象;在靜態方法中,指向父類。super()在子類constructor構造方法中是為了獲取this上下文環境,所以如果在constructor中使用到this,必須在使用this之前調用super(),反之不在constructor中使用this則不必調用super()
{class Parent {constructor(name='gaojingbo') {this.name = name;} }class child extends Parent {constructor(name='child'){super(name);this.type = 'child'}}let v_child = new child();console.log(v_child); //{name: "child", type: "child"} } 復制代碼5.getter和setter
與 ES5 一樣,在“類”的內部可以使用get和set關鍵字,對某個屬性設置存值函數和取值函數,攔截該屬性的存取行為。
{class Parent {constructor(name='gaojingbo') {this.name = name;} get longName(){return 'mk' + this.name;}set longName(value){// console.log(value);this.name = value;}}let v_parent = new Parent();console.log('get',v_parent.longName); //get mkgaojingbov_parent.longName = 'hello';console.log('get',v_parent.longName); //get mkhello } 復制代碼6.靜態方法
類相當于實例的原型,所有在類中定義的方法,都會被實例繼承。如果在一個方法前,加上static關鍵字,就表示該方法不會被實例繼承,而是直接通過類來調用,這就稱為“靜態方法”。
{class Parent {constructor(name='gaojingbo') {this.name = name;} static tell(){console.log('tell');}}let v_parent = new Parent();console.log(v_parent); //{name: "gaojingbo"}Parent.tell(); // tell } 復制代碼7.靜態屬性
靜態屬性指的是Class本身的屬性,即Class.propName,而不是定義在實例對象(this)上的屬性。
{class Parent {constructor(name='gaojingbo') {this.name = name;} }Parent.tell = 'nihao';let v_parent = new Parent();console.log(v_parent); //{name: "gaojingbo"}console.log(Parent.tell); // nihao } 復制代碼十三 Promise
Promise 是異步編程的一種解決方案,比傳統的解決方案——回調函數和事件——更合理和更強大。它由社區最早提出和實現,ES6 將其寫進了語言標準,統一了用法,原生提供了Promise對象。所謂Promise,簡單說就是一個容器,里面保存著某個未來才會結束的事件(通常是一個異步操作)的結果。從語法上說,Promise 是一個對象,從它可以獲取異步操作的消息。Promise 提供統一的 API,各種異步操作都可以用同樣的方法進行處理。 Promise對象有以下兩個特點。 (1)對象的狀態不受外界影響。Promise對象代表一個異步操作,有三種狀態:Pending(進行中)、Fulfilled(已成功)和Rejected(已失敗)。只有異步操作的結果,可以決定當前是哪一種狀態,任何其他操作都無法改變這個狀態。這也是Promise這個名字的由來,它的英語意思就是“承諾”,表示其他手段無法改變。 (2)一旦狀態改變,就不會再變,任何時候都可以得到這個結果。Promise對象的狀態改變,只有兩種可能:從Pending變為Fulfiled和從Pending變為Rejected。只要這兩種情況發生,狀態就凝固了,不會再變了,會一直保持這個結果,這時就稱為 Resolved(已定型)。如果改變已經發生了,你再對Promise對象添加回調函數,也會立即得到這個結果。這與事件(Event)完全不同,事件的特點是,如果你錯過了它,再去監聽,是得不到結果的。
注意,為了行文方便,本章后面的Resolved統一只指Fulfilled狀態,不包含Rejected狀態。
有了Promise對象,就可以將異步操作以同步操作的流程表達出來,避免了層層嵌套的回調函數。此外,Promise對象提供統一的接口,使得控制異步操作更加容易。
Promise也有一些缺點。首先,無法取消Promise,一旦新建它就會立即執行,無法中途取消。其次,如果不設置回調函數,Promise內部拋出的錯誤,不會反應到外部。第三,當處于Pending狀態時,無法得知目前進展到哪一個階段(剛剛開始還是即將完成)。
如果某些事件不斷地反復發生,一般來說,使用 Stream 模式是比部署Promise更好的選擇。
1.基本用法
Promise構造函數接受一個函數作為參數,該函數的兩個參數分別是resolve和reject。它們是兩個函數,由 JavaScript 引擎提供,不用自己部署。
resolve函數的作用是,將Promise對象的狀態從“未完成”變為“成功”(即從 Pending 變為 Resolved),在異步操作成功時調用,并將異步操作的結果,作為參數傳遞出去;reject函數的作用是,將Promise對象的狀態從“未完成”變為“失敗”(即從 Pending 變為 Rejected),在異步操作失敗時調用,并將異步操作報出的錯誤,作為參數傳遞出去。
Promise實例生成以后,可以用then方法分別指定Resolved狀態和Rejected狀態的回調函數。
// ES5的回調函數 {let ajax = function(callback){console.log('nihao');setTimeout(function(){callback && callback.call()},1000)}ajax(function(){console.log('timeout1');}) } // es6 Promise的用法 {let ajax = function(){console.log('wohao');return new Promise((resolve, reject) => {setTimeout(function(){resolve();},1000);});}ajax().then(function(){console.log('promise','timeout1');}) }promise.then(function(value) { // promise的用法// success }, function(error) {// failure }); 復制代碼2.Promise.prototype.then()
Promise實例具有then方法,也就是說,then方法是定義在原型對象Promise.prototype上的。它的作用是為 Promise 實例添加狀態改變時的回調函數。前面說過,then方法的第一個參數是Resolved狀態的回調函數,第二個參數(可選)是Rejected狀態的回調函數。 then方法返回的是一個新的Promise實例(注意,不是原來那個Promise實例)。因此可以采用鏈式寫法,即then方法后面再調用另一個then方法。
{let ajax = function(){console.log('dajiahao');return new Promise((resolve, reject) => {setTimeout(function(){resolve();},1000);});};ajax().then(function(){return new Promise((resolve, reject) => {setTimeout(function(){resolve();},2000)});}).then(function(){console.log('timeout3');}) } 復制代碼3.Promise.prototype.catch()
Promise.prototype.catch方法是.then(null, rejection)的別名,用于指定發生錯誤時的回調函數。
{let ajax = function(num){console.log('dajiahao');return new Promise((resolve, reject) => {if(num>6){console.log('6');}else{throw new Error('出錯了');}});};ajax(3).then(function(){console.log('3');}).catch(error=>{console.log(error) //出錯了})} 復制代碼4.Promise.all
Promise.all方法用于將多個 Promise 實例,包裝成一個新的 Promise 實例。
var p = Promise.all([p1, p2, p3]); 復制代碼上面代碼中,Promise.all方法接受一個數組作為參數,p1、p2、p3都是 Promise 實例,如果不是,就會先調用下面講到的Promise.resolve方法,將參數轉為 Promise 實例,再進一步處理。(Promise.all方法的參數可以不是數組,但必須具有 Iterator 接口,且返回的每個成員都是 Promise 實例。)
p的狀態由p1、p2、p3決定,分成兩種情況。
(1)只有p1、p2、p3的狀態都變成fulfilled,p的狀態才會變成fulfilled,此時p1、p2、p3的返回值組成一個數組,傳遞給p的回調函數。
(2)只要p1、p2、p3之中有一個被rejected,p的狀態就變成rejected,此時第一個被reject的實例的返回值,會傳遞給p的回調函數。
{function loadImg(src){return new Promise((resolve, reject) => {let img = document.createElement('img');img.src=src;img.onload = function(){resolve(img);}img.onerror = function(error){reject(error); }});}function showImgs(imgs){imgs.forEach(function(img){document.body.appendChild(img);})}Promise.all([loadImg(''),loadImg(''),loadImg(''),]).then(showImgs) } 復制代碼4.Promise.race
Promise.race方法同樣是將多個Promise實例,包裝成一個新的Promise實例。
var p = Promise.race([p1, p2, p3]); 復制代碼上面代碼中,只要p1、p2、p3之中有一個實例率先改變狀態,p的狀態就跟著改變。那個率先改變的 Promise 實例的返回值,就傳遞給p的回調函數。 Promise.race方法的參數與Promise.all方法一樣,如果不是 Promise 實例,就會先調用下面講到的Promise.resolve方法,將參數轉為 Promise 實例,再進一步處理。 下面是一個例子,如果指定時間內沒有獲得結果,就將Promise的狀態變為reject,否則變為resolve。
{function loadImg(src){return new Promise((resolve, reject) => {let img = document.createElement('img');img.src=src;img.onload = function(){resolve(img);}img.onerror = function(error){reject(error); }});}function showImg(img){let img = document.createElement('p');p.appendChild(img);document.body.appendChild(p);}Promise.race([loadImg(''),loadImg(''),loadImg(''),]).then(showImgs) } 復制代碼十四 Iterator 和 for...of 循環
Iterator 接口的目的,就是為所有數據結構,提供了一種統一的訪問機制,即for...of循環。當使用for...of循環遍歷某種數據結構時,該循環會自動去尋找 Iterator 接口。一種數據結構只要部署了 Iterator 接口,我們就稱這種數據結構是”可遍歷的“(iterable)。 ES6 規定,默認的 Iterator 接口部署在數據結構的Symbol.iterator屬性,或者說,一個數據結構只要具有Symbol.iterator屬性,就可以認為是“可遍歷的”(iterable)。Symbol.iterator屬性本身是一個函數,就是當前數據結構默認的遍歷器生成函數。執行這個函數,就會返回一個遍歷器。至于屬性名Symbol.iterator,它是一個表達式,返回Symbol對象的iterator屬性,這是一個預定義好的、類型為 Symbol的特殊值,所以要放在方括號內。
1.數組的Symbol.iterator屬性
變量arr是一個數組,原生就具有遍歷器接口,部署在arr的Symbol.iterator屬性上面。所以,調用這個屬性,就得到遍歷器對象。
{let arr = ['hellow','world'];let map = arr[Symbol.iterator]();console.log(map.next()); //{value: "hellow", done: false}console.log(map.next()); //{value: "world", done: false}console.log(map.next()); //{value: "undefined", done: false} } 復制代碼2.自定義的Iterator接口
{let obj = {start:[1,3,2],end:[7,8,9],[Symbol.iterator](){let self = this;let index = 0;let arr = self.start.concat(self.end);let len = arr.length;return {next(){if(index<len){return {value:arr[index++],done:false}}else{return {value:arr[index++],done:true}}}}}}for(let key of obj){console.log(key); //1 3 2 7 8 9} } 復制代碼十五 Genertor
1.基本概念
Generator 函數有多種理解角度。從語法上,首先可以把它理解成,Generator函數是一個狀態機,封裝了多個內部狀態。執行 Generator 函數會返回一個遍歷器對象,也就是說,Generator函數除了狀態機,還是一個遍歷器對象生成函數。返回的遍歷器對象,可以依次遍歷Generator函數內部的每一個狀態。形式上,Generator 函數是一個普通函數,但是有兩個特征。一是,function關鍵字與函數名之間有一個星號;二是,函數體內部使用yield表達式,定義不同的內部狀態(yield在英語里的意思就是“產出”)。
{let tell = function* (){yield 'a';yield 'b';return 'c';}let k = tell();console.log(k.next()); //{value: "a", done: false}console.log(k.next()); //{value: "b", done: false}console.log(k.next()); //{value: "c", done: true}console.log(k.next()); //{value: undefined, done: true} } 復制代碼2.與 Iterator 接口的關系
由于 Generator 函數就是遍歷器生成函數,因此可以把Generator賦值給對象的Symbol.iterator屬性,從而使得該對象具有 Iterator 接口。
{let obj = {};obj[Symbol.iterator] = function* (){yield '1';yield '2';yield '3';}for(let value of obj){console.log(value); // 1 2 3} } 復制代碼3.next方法
{let state = function* (){yield 'a';yield 'b';yield 'c';}let status = state();console.log(status.next()); //aconsole.log(status.next()); //bconsole.log(status.next()); //cconsole.log(status.next()); //aconsole.log(status.next()); //bconsole.log(status.next()); //cconsole.log(status.next()); //a } 復制代碼4.Genertor的簡單應用
//簡單的抽獎 {let draw = function(count){console.info(`剩余${count}次`);}let chou = function *(count){while (count>0) {count--;yield draw(count);}}let start = chou(5);let btn = document.createElement('button');btn.id = 'start';btn.textContent = '抽獎';document.body.appendChild(btn);document.getElementById('start').addEventListener('click',function(){start.next();},false); } // 長輪詢 {let ajax = function* (){yield new Promise((resolve, reject) => {setTimeout(function(){resolve({code:1})},200)});}let pull = function(){let generator = ajax();let step = generator.next();step.value.then(function(d){if(d.code != 0){setTimeout(function(){console.log('wait'); //隔一秒輸出 waitpull();},1000)}else{console.log(d);}})}pull(); } 復制代碼十六修飾器
1.方法的修飾
修飾器函數一共可以接受三個參數,第一個參數是所要修飾的目標對象,即類的實例(這不同于類的修飾,那種情況時target參數指的是類本身);第二個參數是所要修飾的屬性名,第三個參數是該屬性的描述對象。
{let readonly = function(target,name,descriptor){descriptor.writable = false;return descriptor;};class test{@readonlytime(){return '2017-08-27'}}let tests = new test();console.log(tests.time()); // 2017-08-27// let testss = new test();// // tests.time = function(){// // console.log('2017-08-28');// // }// console.log(tests.time()); //Cannot assign to read only property 'time' of object } 復制代碼2.類的修飾
修飾器是一個對類進行處理的函數。修飾器函數的第一個參數,就是所要修飾的目標類。
{let typename = function(target,name,descriptor){target.myname = 'hello';};@typenameclass test{}console.log(test.myname) // hello } 復制代碼十七模塊化
ES6 模塊不是對象,而是通過export命令顯式指定輸出的代碼,再通過import命令輸入。
{export let A = 123;export function text(){console.log('123');}export class hello{text(){console.log('345');}} }{let A = 123;function text(){console.log('123');}class hello{text(){console.log('345');}}export default {A,text,hello} } 復制代碼借鑒了阮一峰ECMAScript 6 入門的內容
轉載于:https://juejin.im/post/5a7167cbf265da3e3d4974d3
總結
以上是生活随笔為你收集整理的ES6简单总结(搭配简单的讲解和小案例)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 码上公益首秀,让科技更有温度!
- 下一篇: python coverage 使用技巧