您好,登錄后才能下訂單哦!
這篇文章主要講解了“ES6~ES12的特性有哪些”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“ES6~ES12的特性有哪些”吧!
ECMAScript是一種由Ecma國際(前身為歐洲計算機制造商協會,European Computer Manufacturers Association)通過ECMA-262標準化的腳本程序設計語言。也可以說是JavaScript的一個標準
在程序員的世界只有兩個版本:ES5
和 ES6
,說是ES6,實際上是2015年發布的,也是大前端時代正式開始的時間,也就是說以2015年為界限,2015年之前叫 ES5
,2016年之后則統稱ES6
let、const 和 var 之間的區別:
var 聲明的變量存在變量提升,而 let、const 不存在變量提升的問題。變量提升:變量是否可在聲明前調用
var 不存在塊級作用域,let 和 const 存在塊級作用域
var 可以重復聲明變量,let 和 const 在一個作用域內不允許重復聲明,并且 const 聲明的是一個 只讀 的變量,并且一定要賦值
另外,當const
聲明了一個對象,對象能的屬性可以改變,因為:const聲明的obj只保存著其對象的引用地址,只要地址不變,便不會出錯
按次序排列
可以從數組中提取值,按照對應位置,對變量賦值,這種寫法屬于模式匹配
可以使用 ...
進行解構,代表剩余全部
如果原數組沒有,則在對應值上可設置默認值,如果不設置,則為undefined
let [a, b, c] = [1, 2, 3] console.log(a, b, c) // 1 2 3 let [a, , c] = [1, 2, 3] console.log(a, , c) // 1 3 let [a, b, ...c] = [1, 2, 3, 4, 5] console.log(a, b, c) // 1 2 [3, 4, 5] let [a, b, ...c] = [1] console.log(a, b, c) // 1 undefined [] let [a = 1, b = a] = [] const.log(a, b) // 1 1 let [a = 1, b = a] = [2] const.log(a, b) // 2 2
無次序行,只需變量與屬性名同名即可
如果變量和對象的屬性名沒有重復,則會導致變量的值為undefined
注意:
,他相當于別名
let { a, b } = { a: 1, b: 2 }; console.log(a, b); // 1 2 let { a } = { b: 2 }; console.log(a); // undefined let { a, b = 2 } = { a: 1 }; console.log(a, b); // 1 2 let { a: b = 2 } = { a: 1 }; console.log(a); // 不存在 a 這個變量 console.log(b); // 1
字符串也可以進行解構,它相當于轉化為類似數組的對象
自帶一個 length
屬性,代表個數
let [a, b, c, d, e] = "hello" console.log(a, b, c, d, e) // h e l l o let { length } = "hello" console.log(length) // 5
解構的只要不死對象或數組,都會先將其轉化為對象,所以數字類型和布爾類型也換轉化為對象
let { toString: s } = 123; console.log(s === Number.prototype.toString) // true let { toString: s } = true; console.log(s === Boolean.prototype.toString) // true
函數的參數可以進行解構,也可以帶有默認值
undefined 可以觸發默認值
注意兩種指定默認值的方法,一種是對變量指定,一種是對參數指定,會得到不同的答案
let arr = [[1,2], [3, 4]] let res = arr.map([a, b] => a + b) console.log(res) // [3, 7] let arr = [1, undefined, 2] let res = arr.map((a = 'test') => a); console.log(res) // [1, 'test', 2] let func = ({x, y} = {x: 0, y: 0}) => { return [x, y] } console.log(func(1, 2)) // [undefined, undefined] console.log(func()) // [0, 0] console.log(func({})) // [undefined, undefined] console.log(func({x: 1})) // [1, undefined] let func = ({x=0, y=0}) => { return [x, y] } console.log(func({x:1,y:2})) // [1, 2] console.log(func()) // error console.log(func({})) // [0, 0] console.log(func({x: 1})) // [1, 0]
正則其實是一個非常難懂的知識點,要是有人能完全掌握,那真的是非常厲害,在這里就簡單的說下
首先分為兩種風格:JS分格
和 perl 分格
JS分格: RegExp()
let re = new RegExp('a'); //查找一個字符串內是否有a let re = new RegExp('a', 'i'); //第一個是查找的對象,第二個是選項
perl風格: / 規則 /選項,且可以跟多個,不分順序
let re = /a/; //查找一個字符串內是否有a let re = /a/i;//第一個是查找的對象,第二個是選項
這里介紹一個正則表達式在線測試(附有常見的正則表達式):正則在線測試
Unicode: 大括號包含
表示Unicode字符
codePointAt(): 返回字符對應碼點,與fromCharCode()對應
String.fromCharCode(): 將對對應的碼點返回為字符,與codePointAt()對應
String.raw():返回把字符串所有變量替換且對斜杠進行轉義的結果
startsWith(): 返回布爾值,表示參數字符串是否在原字符串的頭部。
endsWith():返回布爾值,表示參數字符串是否在原字符串的尾部。
repeat():方法返回一個新字符串,表示將原字符串重復n次
遍歷:for-of
includes():返回布爾值,表示是否找到了參數字符串。
trimStart(): 方法從字符串的開頭刪除空格。trimLeft() 是此方法的別名。
trimEnd(): 方法從一個字符串的末端移除空白字符。trimRight() 是這個方法的別名。
//Unicode console.log("a", "\u0061"); // a a console.log("d", "\u{4E25}"); // d 嚴 let str = 'Domesy' //codePointAt() console.log(str.codePointAt(0)) // 68 //String.fromCharCode() console.log(String.fromCharCode(68)) // D //String.raw() console.log(String.raw`Hi\n${1 + 2}`); // Hi\n3 console.log(`Hi\n${1 + 2}`); // Hi?3 let str = 'Domesy' //startsWith() console.log(str.startsWith("D")) // true console.log(str.startsWith("s")) // false //endsWith() console.log(str.endsWith("y")) // true console.log(str.endsWith("s")) // false //repeat(): 所傳的參數會自動向上取整,如果是字符串會轉化為數字 console.log(str.repeat(2)) // DomesyDomesy console.log(str.repeat(2.9)) // DomesyDomesy // 遍歷:for-of for(let code of str){ console.log(code) // 一次返回 D o m e s y } //includes() console.log(str.includes("s")) // true console.log(str.includes("a")) // false // trimStart() const string = " Hello world! "; console.log(string.trimStart()); // "Hello world! " console.log(string.trimLeft()); // "Hello world! " // trimEnd() const string = " Hello world! "; console.log(string.trimEnd()); // " Hello world!" console.log(string.trimRight()); // " Hello world!"
let str = `Dome sy` console.log(str) //會自動換行 // Dome // sy
const str = { name: '小杜杜', info: '大家好‘ } console.log(`${str.info}, 我是`${str.name}`) // 大家好,我是小杜杜
Array.of(): 將一組值轉化為數組,返回一個新數組,并且不考慮參數的數量或類型。
copyWithin():把指定位置的成員復制到其他位置,返回原數組
find(): 返回第一個符合條件的值
findIndex(): 返回第一個符合條件的索引
keys():對鍵名的遍歷,返回一個遍歷器對象,可用for-of循環,
values():與 keys() 用法一樣,不過是對 鍵值 的遍歷
entries():與 keys() 用法一樣,不過是對 鍵值對 的遍歷
Array.from(): 從一個類似數組或可迭代對象中創建一個新的數組實例。
fill(): 使用制定的元素填充數組,返回原數組
includes():判斷是否包含某一元素,返回布爾值,對 NaN 也有效,但不能進行定位
let arr = [1, 2, 3, 4, 5] //Array.of() let arr1 = Array.of(1, 2, 3); console.log(arr1) // [1, 2, 3] //copyWithin(): 三個參數 (target, start = 0, end = this.length) // target: 目標的位置 // start: 開始位置,可以省略,可以是負數。 // end: 結束位置,可以省略,可以是負數,實際位置是end-1。 console.log(arr.copyWithin(0, 3, 5)) // [4, 5, 3, 4, 5] //find() console.log(arr.find((item) => item > 3 )) // 4 //findIndex() console.log(arr.findIndex((item) => item > 3 )) // 3 // keys() for (let index of arr.keys()) { console.log(index); // 一次返回 0 1 2 3 4 } // values() for (let index of arr.values()) { console.log(index); // 一次返回 1 2 3 4 5 } // entries() for (let index of arr.entries()) { console.log(index); // 一次返回 [0, 1] [1, 2] [2, 3] [3, 4] [4, 5] } let arr = [1, 2, 3, 4, 5] // Array.from(): 遍歷的可以是偽數組,如 String、Set結構,Node節點 let arr1 = Array.from([1, 3, 5], (item) => { return item * 2; }) console.log(arr1) // [2, 6, 10] // fill(): 三個參數 (target, start = 0, end = this.length) // target: 目標的位置 // start: 開始位置,可以省略,可以是負數。 // end: 結束位置,可以省略,可以是負數,實際位置是end-1。 console.log(arr.fill(7)) // [7, 7, 7, 7, 7] console.log(arr.fill(7, 1, 3)) // [1, 7, 7, 4, 5] let arr = [1, 2, 3, 4] //includes() console.log(arr.includes(3)) // true console.log([1, 2, NaN].includes(NaN)); // true
// 其作用為展開數組 let arr = [3, 4, 5] console.log(...arr) // 3 4 5 let arr1 = [1, 2, ...arr] console.log(...arr1) // 1 2 3 4 5
Object.getPrototypeOf():返回對象的原型對象
Object.setPrototypeOf():設置對象的原型對象
proto:返回或設置對象的原型對象
Object.getOwnPropertyNames(): 返回對象自身非Symbol屬性鍵組成的數組
Object.getOwnPropertySymbols(): 返回對象自身非Symbol屬性鍵組成的數組
Reflect.ownKeys(): 返回對象自身全部屬性鍵組成的數組
Object.is():判斷兩個對象是否相等,數組指向的地址不同,所以只要是數組比較,必定為 false
遍歷:for-in
Object.keys():返回屬性名
Object.assign(): 用于將所有可枚舉屬性的值從一個或多個源對象復制到目標對象,返回目標對象,此時的目標對象也會改變
//Object.is() console.log(Object.is('abc', 'abc')) // true console.log(Object.is([], [])) // false //遍歷:for-in let obj = { name: 'Domesy', value: 'React' } for(let key in obj){ console.log(key); // 依次返回屬性值 name value console.log(obj[key]); // 依次返回屬性值 Domesy React } //Object.keys() console.log(Object.keys(obj)) // ['name', 'value'] //Object.assign() const target = { a: 1, b: 2 }; const source = { b: 4, c: 5 }; const result = Object.assign(target, source) console.log(result) // {a: 1, b: 4, c: 5} console.log(target) // {a: 1, b: 4, c: 5}
let a = 1; let b = 2; let obj = { a, b } console.log(obj) // { a: 1, b: 2 } let method = { hello() { console.log('hello') } } console.log(method.hello())// hello
let a = "b" let obj = { [a]: "c" } console.log(obj) // {b : "c"}
在ES9中增加了許多額外的功能,如合并、轉義字符串等操作
// 其作用為展開數組 let { a, b, ...c } = { a: 1, b: 2, c: 3, d: 4}; console.log(c) // {c: 3, d: 4} let obj1 = { c: 3 } let obj = { a: 1, b: 2, ...obj1} console.log(obj) // { a: 1, b: 2, c: 3}
二進制:0b
或 0B
開頭,表示二進制
八進制:00
或 0O
開頭,表示二進制
Number.isFinite(): 用來檢查一個數值是否有限的,返回布爾值
Number.isNaN(): 用來檢查一個數值是否是 NaN,返回布爾值
Number.isInteger(): 用來檢查一個數值是否是整數,返回布爾值
Number.isSafeInteger(): 用來檢查一個數值是否是“安全整數”(safe integer),返回布爾值
Math.cbrt(): 返回立方跟
Math.abrt()(): 返回立方跟
Math.cbrt(): 返回立方跟
Math.clz32(): 返回數值的32位無符號整數形式
Math.imul(): 返回兩個數值相乘
Math.fround(): 返回數值的32位單精度浮點數形式
Math.hypot(): 返回所有數值平方和的平方根
Math.expm1(): 返回e^n - 1
Math.log1p(): 返回1 + n的自然對數(Math.log(1 + n))
Math.log10(): 返回以10為底的n的對數
Math.log2(): 返回以2為底的n的對數
Math.trunc(): 將數字的小數部分去掉,只保留整數部分
Math.sign(): 返回數值類型 正數為1
、負數為-1
、正零 0
、負零 -0
、NaN
Math.abrt(): 返回立方根
Math.sinh(): 返回雙曲正弦
Math.cosh(): 返回雙曲余弦
Math.tanh(): 返回雙曲正切
Math.asinh(): 返回反雙曲正弦
Math.acosh(): 返回反雙曲余弦
Math.atanh(): 返回反雙曲正切
Number.parseInt(): 返回值的整數部分,此方法等價于 parseInt
Number.parseFloat(): 返回值得浮點數部分,此方法等價于 parseFloat
//二進制 console.log(0b101) // 5 console.log(0o151) //105 //Number.isFinite() console.log(Number.isFinite(7)); // true console.log(Number.isFinite(true)); // false //Number.isNaN() console.log(Number.isNaN(NaN)); // true console.log(Number.isNaN("true" / 0)); // true console.log(Number.isNaN(true)); // false //Number.isInteger() console.log(Number.isInteger(17)); // true console.log(Number.isInteger(17.58)); // false //Number.isSafeInteger() console.log(Number.isSafeInteger(3)); // true console.log(Number.isSafeInteger(3.0)); // true console.log(Number.isSafeInteger("3")); // false console.log(Number.isSafeInteger(3.1)); // false //Math.trunc() console.log(Math.trunc(13.71)); // 13 console.log(Math.trunc(0)); // 0 console.log(Math.trunc(true)); // 1 console.log(Math.trunc(false)); // 0 //Math.sign() console.log(Math.sign(3)); // 1 console.log(Math.sign(-3)); // -1 console.log(Math.sign(0)); // 0 console.log(Math.sign(-0)); // -0 console.log(Math.sign(NaN)); // NaN console.log(Math.sign(true)); // 1 console.log(Math.sign(false)); // 0 //Math.abrt() console.log(Math.cbrt(8)); // 2 //Number.parseInt() console.log(Number.parseInt("6.71")); // 6 console.log(parseInt("6.71")); // 6 //Number.parseFloat() console.log(Number.parseFloat("6.71@")); // 6.71 console.log(parseFloat("6.71@")); // 6.71
函數參數尾逗號:允許函數最后一個參數有尾逗號
參數默認賦值具體的數值
//參數默認賦值具體的數值 let x = 1 function fun(x, y = x){ console.log(x, y) } function fun1(c, y = x){ console.log(c, x, y) } fun(2); //2 2 fun1(1); //1 1 1
function fun(...arg){ console.log(arg) // [1, 2, 3, 4] } fun(1, 2, 3, 4)
以 => 定義函數
let arrow = (v) => v + 2 console.log(arrow(1)) // 3
箭頭函數與普通函數的區別
箭頭函數和普通函數的樣式不同,箭頭函數語法更加簡潔、清晰,箭頭函數是 =>定義函數,普通函數是 function定義函數。
Set 沒有鍵只有值,可以認為 鍵和值 都一樣
箭頭函數其實是沒有 this 的,箭頭函數中的 this 只取決包裹箭頭函數的第一個普通函數的 this。
箭頭函數沒有自己的arguments。在箭頭函數中訪問arguments實際上獲得的是外層局部(函數)執行環境中的值。
call、apply、bind 并不會影響其 this 的指向。
箭頭函數的this指向上下文 ,而 普通函數的this并非指向上下文,需要時加入 bind(this)
Set 是ES6中新的數據結構,是類似數組,但成員的值是唯一的,沒有重復的值
聲明:const set = new Set()
屬性:
size:返回 Set 對象中值的個數
方法:
add(): 在Set對象尾部添加一個元素。返回該Set對象
delete(): 移除Set的中與這個值相等的元素,有則返回true,無則返回false
clear(): 清楚Set的所有元素
has(): 是否存在這個值,如果存在為 true,否則為false
keys():以屬性值遍歷器的對象
values():以屬性值遍歷器的對象
entries():以屬性值和屬性值遍歷器的對象
forEach():遍歷每個元素
特別注意:
遍歷器的為iterator
對象,按插入順序,為 [Key, Value] 形式
加入 Set 的值不會發生類型轉化,所以1和”1“是兩個不同的值
在Set內部是通過 === 來判斷,也就是說,兩個對象永遠不可能相同,原因是地址不同
唯一的區別是 NaN
let list = new Set() //add() list.add("1") list.add(1) console(list) // Set(2) {1, "1"} //size console(list.size) // 2 //delete() list.delete("1") console(list) // Set(1) {1} //has() list.has(1) // true list.has(3) // false //clear() list.clear() console(list) // Set(0) {} let arr = [{id: 1}, {id: 2}, {id: 3}] let list = new Set(arr) // keys() for (let key of list.keys()) { console.log(key); // 以此打印:{id: 1} {id: 2} {id: 3} } //values() for (let key of list.values()) { console.log(key); // 以此打印:{id: 1} {id: 2} {id: 3} } //entries() for (let data of list.entries()) { console.log(data); // 以此打印:[{id: 1},{id: 1}] [{id: 2},{id: 2}] [{id: 3},{id: 3}] } //forEach list.forEach((item) => { console.log(item)// 以此打印:{id: 1} {id: 2} {id: 3} });
應用:
需要注意一點的是 new Set
無法去除對象
let arr = [1,1,'true','true',true,true,15,15,false,false, undefined,undefined, null,null, NaN, NaN,'NaN', 0, 0, 'a', 'a']; console.log([...new Set(arr)]) //或 console.log(Array.from(new Set(arr))) // [1, 'true', true, 15, false, undefined, null, NaN, 'NaN', 0, 'a']
let a = new Set([1, 2, 3]) let b = new Set([2, 3, 4]) //并集 console.log(new Set([...a, ...b])) // Set(4) {1, 2, 3, 4} //交集 console.log(new Set([...a].filter(v => b.has(v)))) // Set(2) {2, 3} //差集 new Set([...a].filter(v => !b.has(v))) // Set(1) {1}
let set = new Set([1,2,3]) console.log(new Set([...set].map(v => v * 2))) // Set(3) {2, 4, 6}
定義: 和Set的結構,但成員值只能為對象
聲明: const set = new WeakSet()
方法:
add(): 在WeakSet對象尾部添加一個元素。返回該實例
delete(): 移除WeakSet的中與這個值相等的元素,
has(): 是否存在這個值,如果存在為 true,否則為false
注意:
WeakSet 成員的對象都是弱引用,即垃圾回收機制不考慮該對象的應用。簡單地說WebSet 的對象無法遍歷
好處是,再刪除實例的時候,不會出現內存泄露
推薦指數: ????
Map 是ES6中新的數據結構,是類似對象,成員鍵是任何類型的值
聲明:const map = new Map()
屬性:
constructor: 構造函數,返回Map
size:返回 Map 實例中值的個數
方法:
set(): 添加Map后的一個鍵值對,返回實例
get(): 返回鍵值對
delete(): 移除Map的中與這個值相等的元素,有則返回true,無則返回false
clear(): 清楚Map的所有元素
has(): 是否存在這個值,如果存在為 true,否則為false
keys():以屬性鍵遍歷器的對象
values():以屬性值遍歷器的對象
entries():以屬性鍵和屬性值遍歷器的對象
forEach():遍歷每個元素
特別注意:
對同一個對象的引用,被視為一個鍵
相同的鍵,會進行覆蓋
let map = new Map() //set() map.set('a', 1) map.set('b', 2) console.log(map) // Map(2) {'a' => 1, 'b' => 2} //get map.get("a") // 1 //size console.log(map.size) // 2 //delete() map.delete("a") // true console.log(map) // Map(1) {'b' => 2} //has() map.has('b') // true map.has(1) // false //clear() map.clear() console.log(map) // Map(0) {} let arr = [["a", 1], ["b", 2], ["c", 3]] let map = new Map(arr) // keys() for (let key of map.keys()) { console.log(key); // 以此打印:a b c } //values() for (let value of map.values()) { console.log(value); // 以此打印:1 2 3 } //entries() for (let data of map.entries()) { console.log(data); // 以此打印:["a", 1] ["b", 2] ["c", 3] } //forEach map.forEach((item) => { console.log(item)// 以此打印:1 2 3 });
定義: 和Map的結構,但成員值只能為對象
聲明: const set = new WeakMap()
方法:
set(): 添加鍵值對,返回實例
get(): 返回鍵值對
delete(): 刪除鍵值對,如果存在為 true,否則為false
has(): 是否存在這個值,如果存在為 true,否則為false
Symbol 是ES6中引入的原始數據類型,代表著獨一無二
的
聲明:const sy = Stmbol()
參數: string(可選)
方法:
Symbol.for(): 創建以參數作為描述的Symbol值
,如存在此參數則返回原有的Symbol值
(先搜索后創建,登記在全局環境)
Symbol.keyFor():返回已登記的Symbol值
的描述(只能返回Symbol.for()
的key
)
Object.getOwnPropertySymbols() :返回對象中所有用作屬性名的Symbol值
的數組
// 聲明 let a = Symbol(); let b = Symbol(); console.log(a === b); // false //Symbol.for() let c = Symbol.for("domesy"); let d = Symbol.for("domesy"); console.log(c === d); // true //Symbol.keyFor() const e = Symbol.for("1"); console.log(Symbol.keyFor(e)); // 1 //Symbol.description let symbol = Symbol("es"); console.log(symbol.description); // es console.log(Symbol("es") === Symbol("es")); // false console.log(symbol === symbol); // true console.log(symbol.description === "es"); // true
Proxy用于修改某些操作的默認行為,等同于在語言層面做出修改,所以屬于一種“元編程”(meta programming),即對編程語言進行編程
可以這樣理解,Proxy就是在目標對象之前設置的一層攔截
,外界想要訪問都要經過這層攔截,因此提供了一種機制,可以對外界的訪問進行過濾和改寫。
Proxy 在這里可以理解為代理器
聲明: const proxy = new Proxy(target, handler)
target: 攔截的對象
handler: 定義攔截的方法
方法:
get(): 攔截對象屬性的讀取
set(): 攔截對象設置屬性,返回一個布爾值
has(): 攔截 propKey in proxy 的操作,返回一個布爾值
ownKeys(): 攔截對象屬性遍歷,返回一個數組
deleteProperty():攔截 delete proxy[propKey] 的操作,返回一個布爾值()
apply():攔截函數的調用,call 和 apply 操作
construct():攔截 new 命令,返回一個對象: 攔截 new 命令,返回一個對象
let obj = { name: 'domesy', time: '2022-01-27', value: 1 } let data = new Proxy(obj, { //get() get(target, key){ return target[key].replace("2022", '2015') }, //set() set(target, key, value) { if (key === "name") { return (target[key] = value); } else { return target[key]; } }, // has() has(target, key) { if (key === "name") { return target[key]; } else { return false; } }, // deleteProperty() deleteProperty(target, key) { if (key.indexOf("_") > -1) { delete target[key]; return true; } else { return target[key]; } }, // ownKeys() ownKeys(target) { return Object.keys(target).filter((item) => item != "time"); }, }) console.log(data.time) // 2015-01-27 data.time = '2020' data.name = 'React' console.log(data) //Proxy {name: 'React', time: '2022-01-27', value: 1} // 攔截has() console.log("name" in data) // true console.log("time" in data) // false // 刪除deleteProperty() delete data.time; // true // 遍歷 ownKeys() console.log(Object.keys(data)); //['name', 'value'] //apply() let sum = (...args) => { let num = 0; args.forEach((item) => { num += item; }); return num; }; sum = new Proxy(sum, { apply(target, ctx, args) { return target(...args) * 2; }, }); console.log(sum(1, 2)); // 6 console.log(sum.call(null, 1, 2, 3)); // 12 console.log(sum.apply(null, [1, 2, 3])); // 12 //constructor() let User = class { constructor(name) { this.name = name; } } User = new Proxy(User, { construct(target, args, newTarget) { return new target(...args); }, }); console.log(new User("domesy")); // User {name: 'domesy'}
Reflect 與 Proxy 類似,只是保持Object
的默認行為
將 Object 對象的一些明顯屬于語言內部的方法(比如 Object.defineProperty),放到 Reflect 對象上。
現階段,某些方法同時在 Object 和 Reflect 對象上部署,未來的新方法將只部署在 Reflect 對象上
修改某些 Object 方法的返回結果,讓其變得更合理。比如,Object.defineProperty(obj, name, desc)在無法定義屬性時,會拋出一個錯誤,而 Reflect.defineProperty(obj, name, desc)則會返回 false
讓Object 操作變成函數行為
Reflect 的方法與 Proxy 的方法一一對應,這里就不進行介紹了
Class: 對一類具有共同特征的事物的抽象(構造函數語法糖)
class Parent { constructor(name = 'es6'){ this.name = name } } let data = new Parent('domesy') console.log(data) // Parent { name: 'domesy'}
class Parent { constructor(name = 'es6'){ this.name = name } } // 普通繼承 class Child extends Parent {} console.log(new Child()) // Child { name: 'es6'} // 傳遞參數 class Child extends Parent { constructor(name = "child") { super(name); this.type = "child"; } } console.log(new Child('domesy')) // Child { name: 'domesy', type: 'child'}
這個兩個方法比較重要,常常用來封裝API
get 和 set 是屬性,而不是方法
class Parent { constructor(name = 'es6'){ this.name = name } // getter get getName() { return 'sy' + this.name } // setter set setName(value){ this.name = value } } let data = new Parent() console.log(data.getName) // syes6 data.setName = 'domesy' console.log(data.getName) // domesy
靜態方法,不能在類的實例上調用靜態方法,而應該通過類本身調用
class Parent { static getName = (name) => { return `你好!${name}` } } console.log(Parent.getName('domesy')) // 你好!domesy
class Parent {} Parent.type = "test"; console.log(Parent.type); //test
Promise
就是為了解決“回調地獄”問題的,它可以將異步操作的處理變得很優雅。
Promise
可以支持多個并發的請求,獲取并發請求中的數據這個 Promise
可以解決異步的問題,本身不能說 Promise
是異步的
定義: 包含異步操作結果的對象
狀態:
pending:[待定]初始狀態
fulfilled:[實現]操作成功
rejected: [被否決]操作失敗
注意:
Promise 會根據狀態來確定執行哪個方法
Promise 實例化時狀態默認為 pending 的,如異步狀態異常rejected,反之fulfilled
狀態轉化是單向的,不可逆轉,已經確定的狀態(fulfilled/rejected)無法轉回初始狀態(pending),而且只能是從 pending 到 fulfilled 或者 rejected
//普通定義 let ajax = (callback) => { console.log('≈') setTimeout(() => { callback && callback.call(); }, 1000) } ajax(() => { console.log('timeout') }) // 先會打出 開始執行,1s 后打出 timeout //Promise let ajax = () => { console.log("開始執行"); return new Promise((resolve, reject) => { setTimeout(() => { resolve(); }, 1000); }); }; ajax().then(() => { console.log("timeout"); }); // 先會打出 開始執行,1s 后打出 timeout // then() let ajax = () => { console.log("開始執行"); return new Promise((resolve, reject) => { setTimeout(() => { resolve(); }, 1000); }); }; ajax() .then(() => { return new Promise((resolve, reject) => { setTimeout(() => { resolve(); }, 2000); }); }) .then(() => { console.log("timeout") }) // 先會打出 開始執行,3s(1+2) 后打出 timeout // catch() let ajax = (num) => { console.log("開始執行"); return new Promise((resolve, reject) => { if (num > 5) { resolve(); } else { throw new Error("出錯了"); } }); }; ajax(6) .then(function () { console.log("timeout"); // 先會打出 開始執行,1s 后打出 timeout }) .catch(function (err) { console.log("catch", err); }); ajax(3) .then(function () { console.log("timeout"); }) .catch(function (err) { console.log("catch"); // 先會打出 開始執行,1s 后打出 catch });
Promise.all(arr)用于將多個promise實例,包裝成一個新的Promise實例,返回的實例就是普通的promise
它接收一個數組作為參數
數組里可以是Promise對象,也可以是別的值,只有Promise會等待狀態改變
當所有的子Promise都完成,該Promise完成,返回值是全部值得數組
有任何一個失敗,該Promise失敗,返回值是第一個失敗的子Promise結果
//所有圖片加載完成后添加到頁面 const loadImg = (src) => { return new Promise(resolve, reject) => { let img = document.createElement("img"); img.src = src; img.onload = function () { resolve(img); }; img.onerror = function (err) { reject(err); }; }); } const showImgs = (imgs) => { imgs.forEach((img) => { document.body.appendChild(img); }) } Promise.all([ loadImg("https://ss0.baidu.com/7Po3dSag_xI4khGko9WTAnF6hhy/zhidao/pic/item/71cf3bc79f3df8dcc6551159cd11728b46102889.jpg"), loadImg("https://ss0.baidu.com/7Po3dSag_xI4khGko9WTAnF6hhy/zhidao/pic/item/71cf3bc79f3df8dcc6551159cd11728b46102889.jpg"), loadImg("https://ss0.baidu.com/7Po3dSag_xI4khGko9WTAnF6hhy/zhidao/pic/item/71cf3bc79f3df8dcc6551159cd11728b46102889.jpg"), ]).then(showImgs);
race 與 all相似,只不過只要有一個執行完就會執行
//有一個執行完就回加載到頁面 const loadImg = (src) => { return new Promise(resolve, reject) => { let img = document.createElement("img"); img.src = src; img.onload = function () { resolve(img); }; img.onerror = function (err) { reject(err); }; }); } const showImgs = (imgs) => { let p = document.createElement("p"); p.appendChild(img); document.body.appendChild(p); } Promise.race([ loadImg("https://ss0.baidu.com/7Po3dSag_xI4khGko9WTAnF6hhy/zhidao/pic/item/71cf3bc79f3df8dcc6551159cd11728b46102889.jpg"), loadImg("https://ss0.baidu.com/7Po3dSag_xI4khGko9WTAnF6hhy/zhidao/pic/item/71cf3bc79f3df8dcc6551159cd11728b46102889.jpg"), loadImg("https://ss0.baidu.com/7Po3dSag_xI4khGko9WTAnF6hhy/zhidao/pic/item/71cf3bc79f3df8dcc6551159cd11728b46102889.jpg"), ]).then(showImgs);
一旦執行,無法中途取消,鏈式調用多個then中間不能隨便跳出來
錯誤無法在外部被捕捉到,只能在內部進行預判處理,如果不設置回調函數,Promise內部拋出的錯誤,不會反應到外部
Promise內部如何執行,監測起來很難,當處于pending狀態時,無法得知目前進展到哪一個階段(剛剛開始還是即將完成)
Generator: 是可以用來控制迭代器的函數,也是封裝多個內部狀態的異步編程解決方案,也叫生成器函數
參數說明
yield 來控制程序內部的執行的 "暫停",并返回一個對象,這個對象包括兩個屬性:value
和 done
其中 value
代表值, done
返回布爾(如果為false,代表后續還有,為true則已完成)
next 來恢復
程序執行
Generator 函數的定義不能使用箭頭函數,否則會觸發 SyntaxError 錯誤
let data = function* (){ yield "a"; yield "b"; return "c" } let generator = data(); console.log(generator.next()) //{value: 'a', done: false} console.log(generator.next()) //{value: 'b', done: false} console.log(generator.next()) //{value: 'c', done: true} console.log(generator.next()) //{value: undefined, done: true}
Iterator是一種接口,為各種不同的數據結構提供統一的訪問機制。任何數據結構只要部署Iterator接口,就可以完成遍歷操作(即依次處理該數據結構的所有成員)。
Iterator的作用:
一是為各種數據結構,提供一個統一的、簡便的訪問接口
使得數據結構的成員能夠按某種次序排列
ES6創造了一種新的遍歷命令for...of循環,Iterator接口主要供for...of消費
for-in遍歷順序:不同的引擎已就如何迭代屬性達成一致,從而使行為標準化 ES11
注意:
在ES6中,有些數據結構原生具備Iterator接口(比如數組),即不用任何處理,就可以被for...of循環遍歷,有些就不行(比如對象)
在ES6中,有三類數據結構原生具備Iterator接口:數組
、某些類似數組的對象
、Set
和Map結構
。
一個為對象添加Iterator接口的例子。
// 基本使用 let arr = ["hello", "world"]; let map = arr[Symbol.iterator](); console.log(map.next()); // {value: 'hello', done: false} console.log(map.next()); // {value: 'world', done: false} console.log(map.next()); // {value: undefined, done: true} // for of 循環 let arr = ["hello", "world"]; for (let value of arr) { console.log(value); // hello world } // 對象處理 let obj = { start: [1, 5, 2], end: [7, 9, 6], [Symbol.iterator](){ let index = 0; let arr = this.start.concat(this.end) return { next(){ if(index < arr.length){ return { value: arr[index++], done: false } }else{ return { value: arr[index++], done: true } } } } } } for (let key of obj) { console.log(key); // 1 5 2 7 9 6 }
使用@
符號,用來擴展,修改類的行為
使用的時候需要引入第三方庫 如: core-decorators
const name = (target) => { target.name = "domesy" } @name class Test{} console.log(Test.name) //domesy
在早期,使用立即執行函數實現模塊化是常見的手段,通過函數作用域解決了命名沖突、污染全局作用域的問題
使用模塊化的好處:
解決命名沖突
提供復用性
提高代碼可維護性
方案:
CommonJS:用于服務器(動態化依賴)
AMD:用于瀏覽器(動態化依賴,使用的很少)
CMD:用于瀏覽器(動態化依賴,使用的很少)
UMD:用于瀏覽器和服務器(動態化依賴)
ESM:用于瀏覽器和服務器(靜態化依賴)
默認導出: export default Index
單獨導出: `export const name = 'domesy'
按需導出(推薦): `export { name, value, id }'
改名導出:export { name as newName }
默認導入(推薦): import Index from './Index'
整體導入: import * as Index from './Index'
按需導入(推薦): import { name, value, id } from './Index'
改名導入: import { name as newName } from './Index'
自執導入: import './Index'
符合導入(推薦): import Index, { name, value, id } from './Index'
export命令
和import命令
結合在一起寫成一行,變量實質沒有被導入當前模塊,相當于對外轉發接口,導致當前模塊無法直接使用其導入變量,適用于 全部子模塊導出
默認導入導出: `export { default } from './Index'
整體導入導出: `export * from './Index'
按需導入導出: `export { name, value, id } from './Index'
默認改具名導入導出: `export { default as name } from './Index'
includes(): 在ES6 的基礎上增加了一個索引,代表是從哪尋找ES7
let arr = [1, 2, 3, 4] //includes() ES6 console.log(arr.includes(3)) // true console.log([1, 2, NaN].includes(NaN)); // true // includes() ES7 console.log(arr.includes(1, 0)) // true console.log(arr.includes(1, 1)) // false
冪運算符:用 **
代表 Math.pow()
// 冪運算符 ES7 console.log(Math.pow(2, 3)) // 8 console.log(2 ** 8) // 256
padStart():用于頭部補全
padEnd():用于尾部補全。
let str = 'Domesy' //padStart(): 會以空格的形式補位嗎,這里用0代替,第二個參數會定義一個模板形式,會以模板進行替換 console.log("1".padStart(2, "0")); // 01 console.log("8-27".padStart(10, "YYYY-0M-0D")); // YYYY-08-27 // padEnd():與padStart()用法相同 console.log("1".padEnd(2, "0")); // 10
Object.values():返回屬性值
Object.entries():返回屬性名和屬性值的數組
let obj = { name: 'Domesy', value: 'React' } //Object.values() console.log(Object.values(obj)) // ['React', 'React'] //Object.entries() console.log(Object.entries(obj)) // [['name', 'value'], ['React', 'React']]
作用: 將異步函數改為同步函數,(Generator的語法糖)
const func = async () => { let promise = new Promise((resolve, reject) => { setTimeout(() => { resolve("執行"); }, 1000); }); console.log(await promise); console.log(await 0); console.log(await Promise.resolve(1)); console.log(2); return Promise.resolve(3); } func().then(val => { console.log(val); // 依次執行: 執行 0 1 2 3 });
特別注意:
Async 函數 返回 Promise
對象,因此可以使用 then
awit 命令, 只能用在 async 函數下,否則會報錯
數組的 forEach()
執行 async/await
會失效,可以使用 for-of
和 Promise.all()
代替
無法處理 promise 返回的 reject
對象,需要使用 try catch
來捕捉
這里分為兩種情況: 是否為 promise 對象
如果不是promise , await會阻塞后面的代碼,先執行async外面的同步代碼,同步代碼執行完,再回到async內部,把這個非promise的東西,作為 await表達式的結果。
如果它等到的是一個 promise 對象,await 也會暫停async后面的代碼,先執行async外面的同步代碼,等著 Promise 對象 fulfilled,然后把 resolve 的參數作為 await 表達式的運算結果。
優點:
它做到了真正的串行的同步寫法,代碼閱讀相對容易
對于條件語句和其他流程語句比較友好,可以直接寫到判斷條件里面
處理復雜流程時,在代碼清晰度方面有優勢
缺點:
用 await 可能會導致性能問題,因為 await 會阻塞代碼,也許之后的異步代碼并不依賴于前者,但仍然需要等待前者完成,導致代碼失去了并發性。
放松對標簽模板里字符串轉義的限制:遇到不合法的字符串轉義返回undefined
,并且從raw
上可獲取原字符串。
// 放松字符串的限制 const test = (value) => { console.log(value) } test `domesy` // ['domesy', raw: ["domesy"]]
Promise.finally()
不管最后狀態如何都會執行的回調函數
let func = time => { return new Promise((res, rej) => { setTimeout(() => { if(time < 500){ res(time) }else{ rej(time) } }, time) }) } func(300) .then((val) => console.log('res', val)) .catch((erro) => console.log('rej', erro)) .finally(() => console.log('完成')) // 執行結果: res 300 完成 func(700) .then((val) => console.log('res', val)) .catch((erro) => console.log('rej', erro)) .finally(() => console.log('完成')) // 執行結果: rej 700 完成
for-await-of: 異步迭代器,循環等待每個Promise對象
變為resolved狀態
才進入下一步
let getTime = (seconds) => { return new Promise(res => { setTimeout(() => { res(seconds) }, seconds) }) } async function test(){ let arr = [getTime(2000),getTime(500),getTime(1000)] for await (let x of arr){ console.log(x); } } test() //以此執行 2000 500 1000
JSON.stringify(): 可返回不符合UTF-8標準的字符串(直接輸入U+2028和U+2029可輸入)
//JSON.stringify() 升級 console.log(JSON.stringify("\uD83D\uDE0E")); console.log(JSON.stringify("\u{D800}")); // \ud800
flatMap(): 方法首先使用映射函數映射每個元素,然后將結果壓縮成一個新數組。(注:它與 map 連著深度值為1的 flat 幾乎相同,但 flatMap 通常在合并成一種方法的效率稍微高一些。)
flat: 方法會按照一個可指定的深度遞歸遍歷數組,并將所有元素與遍歷到的子數組中的元素合并為一個新數組返回。默認為1.(應用:數組扁平化(當輸入 Infinity
自動解到最底層))
let arr = [1, 2, 3, 4] // flatMap() console.log(arr.map((x) => [x * 2])); // [ [ 2 ], [ 4 ], [ 6 ], [ 8 ] ] console.log(arr.flatMap((x) => [x * 2])); // [ 2, 4, 6, 8 ] console.log(arr.flatMap((x) => [[x * 2]])); // [ [ 2 ], [ 4 ], [ 6 ], [ 8 ] ] const arr1 = [0, 1, 2, [3, 4]]; const arr2 = [0, 1, 2, [[[3, 4]]]]; console.log(arr1.flat()); // [ 0, 1, 2, 3, 4 ] console.log(arr2.flat(2)); // [ 0, 1, 2, [ 3, 4 ] ] console.log(arr2.flat(Infinity)); // [ 0, 1, 2, 3, 4 ]
返回鍵和值組成的對象,相當于Object.entries()
的逆操作
可以做一些數據類型的轉化
let map = new Map([ ["a", 1], ["b", 2], ]); let obj = Object.fromEntries(map); console.log(obj); // {a: 1, b: 2}
// 注意數組的形式 let arr = [ ["a", 1], ["b", 2], ] let obj = Object.fromEntries(arr); console.log(obj); // {a: 1, b: 2}
let obj = { a: 1, b: 2, c: 3 } let res = Object.fromEntries( Object.entries(obj).filter(([key, val]) => value !== 3) ) console.log(res) //{a: 1, b: 2}
toString()改造:返回函數原始代碼(與編碼一致)
//toString() function test () { consople.log('domesy') } console.log(test.toString()); // function test () { // consople.log('domesy') // }
在 ES10 中,try catch 可忽略 catch的參數
let func = (name) => { try { return JSON.parse(name) } catch { return false } } console.log(func(1)) // 1 console.log(func({a: '1'})) // false
新的原始數據類型:BigInt,表示一個任意精度的整數,可以表示超長數據,可以超出2的53次方
js 中 Number類型只能安全的表示-(2^53-1)至 2^53-1 范的值
特別注意:
Number類型的數字有精度限制,數值的精度只能到 53 個二進制位(相當于 16 個十進制位, 正負9007199254740992),大于這個范圍的整數,就無法精確表示了。
Bigint沒有位數的限制,任何位數的整數都可以精確表示。但是其只能用于表示整數,且為了與Number進行區分,BigInt 類型的數據必須添加后綴n。
BigInt 可以使用負號,但是不能使用正號
number類型的數字和Bigint類型的數字不能混合計算
// Number console.log(2 ** 53) // 9007199254740992 console.log(Number.MAX_SAFE_INTEGER) // 9007199254740991 //BigInt const bigInt = 9007199254740993n console.log(bigInt) // 9007199254740993n console.log(typeof bigInt) // bigint console.log(1n == 1) // true console.log(1n === 1) // false const bigIntNum = BigInt(9007199254740993n) console.log(bigIntNum) // 9007199254740993n
在ES6中一共有7種,分別是:srting
、number
、boolean
、object
、null
、undefined
、symbol
其中 object
包含: Array
、Function
、Date
、RegExp
而在ES11后新增一中,為 8中 分別是:srting
、number
、boolean
、object
、null
、undefined
、symbol
、BigInt
Promise.allSettled():
將多個實例包裝成一個新實例,返回全部實例狀態變更后的狀態數組(齊變更再返回)
無論結果是 fulfilled 還是 rejected, 無需 catch
相當于增強了 Promise.all()
Promise.allSettled([ Promise.reject({ code: 500, msg: "服務異常", }), Promise.resolve({ code: 200, data: ["1", "2", "3"], }), Promise.resolve({ code: 200, data: ["4", "5", "6"], }), ]).then((res) =>{ console.log(res) // [{ reason: {code: 500, msg: '服務異常'}, status: "rejected" }, // { reason: {code: 200, data: ["1", "2", "3"]}, status: "rejected" }, // { reason: {code: 200, data: ["4", "5", "6"]}, status: "rejected" }] const data = res.filter((item) => item.status === "fulfilled"); console.log(data); // [{ reason: {code: 200, data: ["1", "2", "3"]}, status: "rejected" }, // { reason: {code: 200, data: ["4", "5", "6"]}, status: "rejected" }] })
按需獲取的動態 import. 該類函數格式(并非繼承 Function.prototype)返回 promise 函數
與require
的區別是:require()
是同步加載,import()
是異步加載
// then() let modulePage = "index.js"; import(modulePage).then((module) => { module.init(); }); // 結合 async await (async () => { const modulePage = 'index.js' const module = await import(modulePage); console.log(module) })
全局this,無論是什么環境(瀏覽器,node等),始終指向全局對象
// 瀏覽器環境 console.log(globalThis) // window // node console.log(globalThis) // global
符號 ?代表是否存在
TypeScript 在 3.7 版本已實現了此功能
const user = { name: 'domesy' } //ES11之前 let a = user && user.name //現在 let b = user?.name
處理默認值的便捷運算符
與 || 相比,空值合并運算符 ?? 只會在左邊的值嚴格等于 null 或 undefined 時起作用。
"" || "default value"; // default value "" ?? "default value"; // "" const b = 0; const a = b || 5; console.log(a); // 5 const b = null // undefined const a = b ?? 123; console.log(a); // 123
replaceAll()
replace() 方法僅替換一個字符串中某模式(pattern)的首個實例
replaceAll() 會返回一個新字符串,該字符串中用一個替換項替換了原字符串中所有匹配了某模式的部分。
模式可以是一個字符串或一個正則表達式,而替換項可以是一個字符串或一個應用于每個匹配項的函數。
replaceAll() 相當于增強了 replace() 的特性,全量替換
let str = "Hi!,這是ES6~ES12的新特性,目前為ES12" console.log(str.replace("ES", "SY")); // Hi!,這是SY6~ES12的新特性,目前為ES12 console.log(str.replace(/ES/g, "Sy")); // Hi!,這是Sy6~Sy12的新特性,目前為Sy12 console.log(str.replaceAll("ES", "Sy")); // Hi!,這是Sy6~Sy12的新特性,目前為Sy12 console.log(str.replaceAll(/ES/g, "Sy")); // Hi!,這是Sy6~Sy12的新特性,目前為Sy12
Promise.any()
其區別于 Promise.race(), 盡管某個 promise 的 reject 早于另一個 promise 的 resolve,Promise.any() 仍將返回那個首先 resolve 的 promise。
Promise.any([ Promise.reject("Third"), Promise.resolve("Second"), Promise.resolve("First"), ]) .then((res) => console.log(res)) // Second .catch((err) => console.error(err)); Promise.any([ Promise.reject("Error 1"), Promise.reject("Error 2"), Promise.reject("Error 3"), ]) .then((res) => console.log(res)) .catch((err) => console.error(err)); // AggregateError: All promises were rejected Promise.any([ Promise.resolve("Third"), Promise.resolve("Second"), Promise.resolve("First"), ]) .then((res) => console.log(res)) // Third .catch((err) => console.error(err));
允許創建對象的弱引用。這樣就能夠在跟蹤現有對象時不會阻止對其進行垃圾回收。對于緩存和對象映射非常有用
必須用 new關鍵字創建新的 WeakRef
deref() 讀取引用的對象
正確使用 WeakRef 對象需要仔細的考慮,最好盡量避免使用。避免依賴于規范沒有保證的任何特定行為也是十分重要的。何時、如何以及是否發生垃圾回收取決于任何給定 JavaScript 引擎的實現。
let weakref = new WeakRef({name: 'domesy', year: 24}) weakref.deref() // {name: 'domesy', year: 24} weakref.deref().year // 24
let num1 = 5; let num2 = 10; num1 &&= num2; console.log(num1); // 10 // 等價于 num1 && (num1 = num2); if (num1) { num1 = num2; }
let num1; let num2 = 10; num1 ||= num2; console.log(num1); // 10 // 等價于 num1 || (num1 = num2); if (!num1) { num1 = num2; }
空值合并運算符 ?? 只會在左邊的值嚴格等于 null 或 undefined 時起作用
let num1; let num2 = 10; let num3 = null; // undefined num1 ??= num2; console.log(num1); // 10 num1 = false; num1 ??= num2; console.log(num1); // false num3 ??= 123; console.log(num3); // 123 // 等價于 // num1 ?? (num1 = num2);
let num1 = 100000; let num2 = 100_000; console.log(num1); // 100000 console.log(num2); // 100000 const num3 = 10.12_34_56 console.log(num3); // 10.123456
感謝各位的閱讀,以上就是“ES6~ES12的特性有哪些”的內容了,經過本文的學習后,相信大家對ES6~ES12的特性有哪些這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。