在工做中咱們會經常使用到的一些es6-es10的一些特性還記得多少,今天就讓咱們從新複習一遍html
ES6語法es6
1.let聲明的變量具備塊級做用域,正則表達式
{ let a = 1 } console.log(a); //undefined 變量是在代碼塊中使用 let 定義的,它的做用域是這個代碼塊內部,外部沒法訪問。a{}
2.let聲明的全局變量不是全局對象的屬性express
var a = 1 console.log(window.a); //1
let a = 1 console.log(window.a); // undefined
3.用let重定義變量會拋出一個語法錯誤編程
var a = 1 var a = 2 console.log(a) //2 若是是 let ,則會報錯 let a = 1 let a = 2 // VM131:1 Uncaught SyntaxError: Identifier 'a' has already been declared // at <anonymous>:1:1
2.Constapi
const
除了具備let
的塊級做用域和不會變量提高外,還有就是它定義的是常量,在用const
定義變量後,咱們就不能修改它了,對變量的修改會拋出異常。數組
const A= 123; console.log(A); A = 1; console.log(A); // Uncaught TypeError: Assignment to constant variable.
在 ES6 中新增了不少實用的原生 API,方便開發者對 Array 的操控性更強,如 for…of、from、of、fill、find、findIndex等。promise
3.for…of數據結構
在es5以前遍歷數組app
for (var i = 0; i < array.length; i++) { console.log(array[i]); }
在es6以前遍歷數組
for (let val of [1,2,3]) { console.log(val); } // 1,2,3
4.Array.prototype.from()
數組是開發中常常用到的數據結構,它很是好用。在 JavaScript 的世界裏有些對象被理解爲數組,然而缺不能使用數組的原生 API,好比函數中的 arguments、DOM中的 NodeList等。固然,還有一些可遍歷的對象,看上去都像數組卻不能直接使用數組的 API,由於它們是僞數組(Array-Like)。要想對這些對象使用數組的 API 就要想辦法把它們轉化爲數組,傳統的作法是這樣的:
let args = [].slice.call(arguments); let imgs = [].slice.call(document.querySelectorAll('img'));
基本原理是使用 call 將數組的 api 應用在新的對象上,換句話說是利用改變函數的上下文來間接使用數組的 api。在 ES6 中提供了新的 api 來解決這個問題,就是 Array.from,代碼以下:
let args = Array.from(arguments); let imgs = Array.from(document.querySelectorAll('img'));
5.Array.prototype.of()
Array.of() 方法建立一個具備可變數量參數的新數組實例,而不考慮參數的數量或類型。
Array.of() 和 Array 構造函數之間的區別在於處理整數參數:Array.of(7) 建立一個具備單個元素 7 的數組,而 Array(7) 建立一個長度爲7的空數組(注意:這是指一個有7個空位(empty)的數組,而不是由7個undefined組成的數組)。
Array.of(7); // [7] Array.of(1, 2, 3); // [1, 2, 3] Array(7); // [ , , , , , , ] Array(1, 2, 3); // [1, 2, 3]
6.Array.prototype.fill()
fill() 方法用一個固定值填充一個數組中從起始索引到終止索引內的所有元素。不包括終止索引。
let array = [1, 2, 3, 4] array.fill(0, 1, 2) // [1,0,3,4]
7.Array.prototype.find()
find() 方法返回數組中知足提供的測試函數的第一個元素的值,不然返回 undefined。
let array = [5, 12, 8, 130, 44]; let found = array.find(function(element) { return element > 10; }); console.log(found); // 12
8.Array.prototype.findIndex()
findIndex()方法返回數組中知足提供的測試函數的第一個元素的索引。不然返回-1。其實這個和 find() 是成對的,不一樣的是它返回的是索引而不是值。
let array = [5, 12, 8, 130, 44]; let found = array.findIndex(function(element) { return element > 10; }); console.log(found); // 1
對於面向對象編程而言,更關注類的聲明、屬性、方法、靜態方法、繼承、多態、私有屬性。
首先咱們要先來講明在 JavaScript 世界裏如何聲明一個 「類」。在 ES6 以前你們都是這麼作的:
let Animal = function (type) { this.type = type this.walk = function () { console.log(`I am walking`) } } let dog = new Animal('dog') let monkey = new Animal('monkey')
在 ES6 中把類的聲明專業化了,不在用 function 的方式了,請看:
class Animal { constructor (type) { this.type = type } walk () { console.log(`I am walking`) } } let dog = new Animal('dog') let monkey = new Animal('monkey')
10.Setters & Getters
對於類中的屬性,能夠直接在 constructor 中經過 this 直接定義,還能夠直接在類的頂層來定義:
class Animal { constructor (type, age) { this.type = type this._age = age } get age () { return this._age } set age (val) { this._age = val } }
11.靜態方法
靜態方法是面向對象最經常使用的功能,在 ES5 中利用 function 實現的類是這樣實現一個靜態方法的。
let Animal = function (type) { this.type = type this.walk = function () { console.log(`I am walking`) } } Animal.eat = function (food) { console.log(`I am eating`); }
在 ES6 中使用 static 的標記是否是靜態方法,代碼以下:
class Animal { constructor (type) { this.type = type } walk () { console.log(`I am walking`) } static eat () { console.log(`I am eating`) } }
12.繼承
面向對象只因此能夠應對複雜的項目實現,很大程度上要歸功於繼承。若是對繼承概念不熟悉的同窗,能夠自行查詢。在 ES5 中怎麼實現繼承呢?
// 定義父類 let Animal = function (type) { this.type = type } // 定義方法 Animal.prototype.walk = function () { console.log(`I am walking`) } // 定義靜態方法 Animal.eat = function (food) { console.log(`I am eating`) } // 定義子類 let Dog = function () { // 初始化父類 Animal.call(this, 'dog') this.run = function () { console.log('I can run') } } // 繼承 Dog.prototype = Animal.prototype
從代碼上看,是否是很繁瑣?並且閱讀性也較差。再看看 ES6 是怎麼解決這些問題的:
class Animal { constructor (type) { this.type = type } walk () { console.log(`I am walking`) } static eat () { console.log(`I am eating`) } } class Dog extends Animal { constructor () { super('dog') } run () { console.log('I can run') } }
對於函數而言,常常會用到參數,關於參數的默認值一般都是寫在函數體中,如在 ES5 的時候你們都會這麼寫:
function f (x, y, z) { if (y === undefined) y = 7; if (z === undefined) z = 42; return x + y + z; }; f(1) === 50;
當一個函數有不少參數涉及初始化的時候,這樣寫代碼極其醜陋,因此在 ES6 中改變了對這種知識的寫法:
function f (x, y = 7, z = 42) { return x + y + z } f(1) === 50
14.Rest Parameter
在寫函數的時候,部分狀況咱們不是很肯定參數有多少個,好比求和運算,以前都是這麼作的:
function sum () { let num = 0 Array.prototype.forEach.call(arguments, function (item) { num += item * 1 }) return num } console.log(sum(1, 2, 3))// 6 console.log(sum(1, 2, 3, 4))// 10
其實在上面說過,這個代碼在 ES5 中能夠這麼寫,在 ES6 就不能這麼寫了,由於 arguments 的問題。如今須要這樣寫:
function sum (...nums) { let num = 0 nums.forEach(function (item) { num += item * 1 }) return num } console.log(sum(1, 2, 3))// 6 console.log(sum(1, 2, 3, 4))// 10
固然,Rest Parameter 也能夠和其餘參數一塊兒來用,好比:
function sum (base, ...nums) { let num = base nums.forEach(function (item) { num += item * 1 }) return num } console.log(sum(30, 1, 2, 3))// 36 console.log(sum(30, 1, 2, 3, 4))// 40
15.箭頭函數
箭頭函數能夠說是 ES6 很大的福利了,無論你是函數式愛好者仍是面向對象開發者,函數是必需要用到的東西。以前聲明函數須要使用 function,以下:
function hello () { console.log('say hello') } // 或 let hello = function () { console.log('say hello') }
如今能夠這樣作了:
let hello = () => { console.log('say hello') }
若是帶參數該怎麼作呢?
let hello = (name) => { console.log('say hello', name) } // 或者 let hello = name => { console.log('say hello', name) }
16.Enhanced Object Properties(加強對象屬性)
在 ES6 以前 Object 的屬性必須是 key-value 形式,以下:
var x = 0, y = 0; obj = { x: x, y: y };
在 ES6 以後是能夠用簡寫的形式來表達:
var x = 0, y = 0 obj = { x, y }
17.Object.assign()
Object.assign() 方法用於將全部可枚舉屬性的值從一個或多個源對象複製到目標對象,它將返回目標對象。
const target = { a: 1, b: 2 } const source = { b: 4, c: 5 } const returnedTarget = Object.assign(target, source) console.log(target) // expected output: Object { a: 1, b: 4, c: 5 } console.log(returnedTarget) // expected output: Object { a: 1, b: 4, c: 5 }
從語法上能夠看出源對象的個數是不限制的(零個或多個),若是是零個直接返回目的對象,若是是多個相同屬性的會被後邊的源對象的屬相覆蓋。
let s = Object.assign({ a: 1 }) // {a: 1}
18.RegExp
Sticky
除了u修飾符,ES6還爲正則表達式添加了y修飾符,叫作「粘連」(sticky)修飾符。
y修飾符的做用與g修飾符相似,也是全局匹配,後一次匹配都從上一次匹配成功的下一個位置開始。不一樣之處在於,g修飾符只要剩餘位置中存在匹配就可,而y修飾符確保匹配必須從剩餘的第一個位置開始,這也就是「粘連」的涵義。
const s = 'aaa_aa_a' const r1 = /a+/g const r2 = /a+/y r1.exec(s) // ["aaa"] r2.exec(s) // ["aaa"] r1.exec(s) // ["aa"] r2.exec(s) // null
19.Unicode
ES6對正則表達式添加了u修飾符,含義爲「Unicode模式」,用來正確處理大於 \uFFFF
的Unicode字符。也就是說,會正確處理四個字節的UTF-16編碼。
/^\uD83D/u.test('\uD83D\uDC2A') // false /^\uD83D/.test('\uD83D\uDC2A') // true
上面代碼中,\uD83D\uDC2A
是一個四個字節的UTF-16編碼,表明一個字符 「?」。可是,ES5不支持四個字節的UTF-16編碼,會將其識別爲兩個字符,致使第二行代碼結果爲true。加了u修飾符之後,ES6就會識別其爲一個字符,因此第一行代碼結果爲false。
(1)電字符
點(.)字符在正則表達式中,含義是除了換行符之外的任意單個字符。對於碼點大於 0xFFFF 的 Unicode 字符,點字符不能識別,必須加上u修飾符。
let s = '?'; // /^.$/.test(s) // false /^.$/u.test(s) // true
(2).Unicode字符表示法
ES6新增了使用大括號表示Unicode字符,這種表示法在正則表達式中必須加上u修飾符,才能識別。
/\u{61}/.test('a') // false /\u{61}/u.test('a') // true /\u{20BB7}/u.test('?') // true
(3)量詞
使用u修飾符後,全部量詞都會正確識別碼點大於0xFFFF的Unicode字符。
/a{2}/.test('aa') // true /a{2}/u.test('aa') // true /?{2}/.test('??') // false /?{2}/u.test('??') // true
(4) 預約義模式
u修飾符也影響到預約義模式,可否正確識別碼點大於0xFFFF的Unicode字符。
/^\S$/.test('?') // false /^\S$/u.test('?') // true
上面代碼的\S是預約義模式,匹配全部不是空格的字符。只有加了u修飾符,它才能正確匹配碼點大於0xFFFF的Unicode字符。
利用這一點,能夠寫出一個正確返回字符串長度的函數。
function codePointLength(text) { const result = text.match(/[\s\S]/gu); return result ? result.length : 0; } const s = '??'; s.length // 4 codePointLength(s) // 2
(5) i修飾符
有些Unicode字符的編碼不一樣,可是字型很相近,好比,\u004B與\u212A都是大寫的K。
/[a-z]/i.test('\u212A') // false /[a-z]/iu.test('\u212A') // true
在 ES6 以前對字符串的處理是至關的麻煩,看以下場景:
1. 字符串很長要換行
字符串很長包括幾種情形一個是開發時輸入的文本內容,一個是接口數據返回的文本內容。若是對換行符處理不當,就會帶來異常。
2. 字符串中有變量或者表達式
若是字符串不是靜態內容,每每是須要加載變量或者表達式,這個也是很常見的需求。以前的作法是字符串拼接:
var a = 20 var b = 10 var c = 'JavaScript' var str = 'My age is ' + (a + b) + ' and I love ' + c console.log(str)
從 ES6 開始能夠這樣定義字符串了。
`string text` `string text line 1 string text line 2` `string text ${expression} string text` 在這裏你能夠任意插入變量或者表達式,只要用 ${} 包起來就好。
21解構賦值
在 ES6 中新增了變量賦值的方式:解構賦值。若是對這個概念不瞭解,咱們能夠快速展現一個小示例一睹風采:
let arr = ['Ilya', 'Kantor'] let firstName = arr[0] let surname = arr[1]
想從數組中找出有意義的項要單獨賦值給變量(一一的寫),在 ES6 中就能夠這樣寫了:
let [firstName, surname] = ['Ilya', 'Kantor'] console.log(firstName) // Ilya console.log(surname) // Kantor
22.Promise
首先要說明 Promise 就是爲了解決「回調地獄」問題的,它能夠將異步操做的處理變得很優雅。若是咱們使用 Promise 來解決上面那個問題該怎麼作呢?
function loadScript (src) { return new Promise((resolve, reject) => { let script = document.createElement('script') script.src = src script.onload = () => resolve(script) script.onerror = (err) => reject(err) document.head.append(script) }) } loadScript('1.js') .then(loadScript('2.js'), (err) => { console.log(err) }) .then(loadScript('3.js'), (err) => { console.log(err) })
經過建立 Promise 對象開啓一個異步操做的過程,通常用幾步完成屢次異步操做:
1.Promise.prototype.then()
var promise = new Promise(function (resolve, reject) { resolve('傳遞給then的值') }) promise.then(function (value) { console.log(value) }, function (error) { console.error(error) })
這段代碼建立一個 Promise 對象,定義了處理 onFulfilled 和 onRejected 的函數(handler),而後返回這個 Promise 對象。
這個 Promise 對象會在變爲 resolve 或者 reject 的時候分別調用相應註冊的回調函數。
當 handler 返回一個正常值的時候,這個值會傳遞給 Promise 對象的 onFulfilled 方法。
定義的 handler 中產生異常的時候,這個值則會傳遞給 Promise 對象的 onRejected 方法
2.Promise.resolve()
通常狀況下咱們都會使用 new Promise()
來建立 Promise 對象,可是除此以外咱們也可使用其餘方法。
Promise.resolve(42).then(function (value) { console.log(value) })
在這段代碼中的 resolve(42) 會讓這個 Promise 對象當即進入肯定(即resolved)狀態,並將 42 傳遞給後面 then 裏所指定的 onFulfilled 函數。
3.Promise.reject()
Promise.reject(error) 是和 Promise.resolve(value) 相似的靜態方法,是 new Promise() 方法的快捷方式。
new Promise(function (resolve, reject) { reject(new Error('出錯了')) })
4.Promise.prototype.catch()
捕獲異常是程序質量保障最基本的要求,可使用 Promise 對象的 catch 方法來捕獲異步操做過程當中出現的任何異常。
function test () { return new Promise((resolve, reject) => { reject(new Error('es')) }) } test().catch((e) => { console.log(e.message) // es })
5.Promise.all()
var p1 = Promise.resolve(1) var p2 = Promise.resolve(2) var p3 = Promise.resolve(3) Promise.all([p1, p2, p3]).then(function (results) { console.log(results) // [1, 2, 3] })
Promise.all 生成並返回一個新的 Promise 對象,因此它可使用 Promise 實例的全部方法。參數傳遞promise數組中全部的 Promise 對象都變爲resolve的時候,該方法纔會返回, 新建立的 Promise 則會使用這些 promise 的值。
若是參數中的任何一個promise爲reject的話,則整個Promise.all調用會當即終止,並返回一個reject的新的 Promise 對象。
因爲參數數組中的每一個元素都是由 Promise.resolve 包裝(wrap)的,因此Paomise.all 能夠處理不一樣類型的 promose對
6.Promise.race()
var p1 = Promise.resolve(1) var p2 = Promise.resolve(2) var p3 = Promise.resolve(3) Promise.race([p1, p2, p3]).then(function (value) { console.log(value) // 1 })
Promise.race 生成並返回一個新的 Promise 對象。
參數 promise 數組中的任何一個 Promise 對象若是變爲 resolve 或者 reject 的話, 該函數就會返回,並使用這個 Promise 對象的值進行 resolve 或者 reject。
23.Reflect
Reflect 是一個內置的對象,它提供攔截 JavaScript 操做的方法,這些方法與處理器對象的方法相同。Reflect不是一個函數對象,所以它是不可構造的。
Reflect.apply(Math.floor, undefined, [1.75]) // 1; Reflect.apply(String.fromCharCode, undefined, [104, 101, 108, 108, 111]) // "hello" Reflect.apply(RegExp.prototype.exec, /ab/, ['confabulation']).index // 4 Reflect.apply(''.charAt, 'ponies', [3]) // "i"
該方法與ES5中Function.prototype.apply()方法相似:調用一個方法而且顯式地指定this變量和參數列表(arguments) ,參數列表能夠是數組,或相似數組的對象。
Function.prototype.apply.call(Math.floor, undefined, [1.75]);
2.Reflect.construct()
Reflect.construct() 方法的行爲有點像 new 操做符 構造函數 , 至關於運行 new target(…args).
var d = Reflect.construct(Date, [1776, 6, 4]) d instanceof Date // true d.getFullYear() // 1776
3.Reflect.defineProperty()
靜態方法 Reflect.defineProperty() 基本等同於 Object.defineProperty() 方法,惟一不一樣是返回 Boolean 值。
const student = {} Reflect.defineProperty(student, 'name', { value: 'Mike' }) // true student.name // "Mike"
4.Deflect.deleteProperty()
Reflect.deleteProperty 容許你刪除一個對象上的屬性。返回一個 Boolean 值表示該屬性是否被成功刪除。它幾乎與非嚴格的 delete operator 相同。
var obj = { x: 1, y: 2 }; Reflect.deleteProperty(obj, "x"); // true obj; // { y: 2 } var arr = [1, 2, 3, 4, 5]; Reflect.deleteProperty(arr, "3"); // true arr; // [1, 2, 3, , 5] // 若是屬性不存在,返回 true Reflect.deleteProperty({}, "foo"); // true // 若是屬性不可配置,返回 false Reflect.deleteProperty(Object.freeze({foo: 1}), "foo"); // false
5.Reflect.get()
Reflect.get() 方法的工做方式,就像從 object (target[propertyKey]) 中獲取屬性,但它是做爲一個函數執行的。
// Object var obj = { x: 1, y: 2 } Reflect.get(obj, 'x') // 1 // Array Reflect.get(['zero', 'one'], 1) // "one" // Proxy with a get handler var x = { p: 1 } var obj = new Proxy(x, { get (t, k, r) { return k + 'bar' } }) Reflect.get(obj, 'foo') // "foobar"
6.Reflect.getOwnPropertyDescriptor()
靜態方法 Reflect.getOwnPropertyDescriptor() 與 Object.getOwnPropertyDescriptor() 方法類似。若是在對象中存在,則返回給定的屬性的屬性描述符,不然返回 undefined。
Reflect.getOwnPropertyDescriptor({ x: 'hello' }, 'x') // {value: "hello", writable: true, enumerable: true, configurable: true} Reflect.getOwnPropertyDescriptor({ x: 'hello' }, 'y') // undefined Reflect.getOwnPropertyDescriptor([], 'length') // {value: 0, writable: true, enumerable: false, configurable: false}
7.Reflect.getPrototypeOf()
靜態方法 Reflect.getPrototypeOf() 與 Object.getPrototypeOf() 方法是同樣的。都是返回指定對象的原型(即,內部的 [[Prototype]] 屬性的值)。
8.Reflect.has()
Reflect.has 用於檢查一個對象是否擁有某個屬性, 至關於in 操做符
9.Reflect.set()
Reflect.set 方法容許你在對象上設置屬性。它的做用是給屬性賦值而且就像 property accessor 語法同樣,可是它是以函數的方式。
// Object var obj = {}; Reflect.set(obj, "prop", "value"); // true obj.prop; // "value" // Array var arr = ["duck", "duck", "duck"]; Reflect.set(arr, 2, "goose"); // true arr[2]; // "goose" // It can truncate an array. Reflect.set(arr, "length", 1); // true arr; // ["duck"]; // With just one argument, propertyKey and value are "undefined". var obj = {}; Reflect.set(obj); // true Reflect.getOwnPropertyDescriptor(obj, "undefined"); // { value: undefined, writable: true, enumerable: true, configurable: true }
10.Reflect.setPrototypeOf()
Reflect.setPrototypeOf 方法改變指定對象的原型 (即,內部的 [[Prototype]] 屬性值)
Reflect.setPrototypeOf({}, Object.prototype); // true // It can change an object's [[Prototype]] to null. Reflect.setPrototypeOf({}, null); // true // Returns false if target is not extensible. Reflect.setPrototypeOf(Object.freeze({}), null); // false // Returns false if it cause a prototype chain cycle. var target = {}; var proto = Object.create(target); Reflect.setPrototypeOf(target, proto); // false
24.Proxy
let p = new Proxy(target, handler)
從服務端獲取的數據但願是隻讀,不容許在任何一個環節被修改。
// response.data 是 JSON 格式的數據,來自服務端的響應 // 在 ES5 中只能經過遍歷把全部的屬性設置爲只讀 for (let [key] of Object.entries(response.data)) { Object.defineProperty(response.data, key, { writable: false }) }
若是咱們使用 Proxy 就簡單不少了:
let data = new Proxy(response.data, { set(obj, key, value) { return false } })
25.Generator
什麼是 JavaScript Generators 呢?通俗的講 Generators 是能夠用來控制迭代器的函數。它們能夠暫停,而後在任什麼時候候恢復。若是這句話很差理解,能夠看下接下來的示例。
ES5以前作法
for (let i = 0; i < 5; i += 1) { console.log(i) } // this will return immediately 0 -> 1 -> 2 -> 3 -> 4
用 Generator
function * generatorForLoop () { for (let i = 0; i < 5; i += 1) { yield console.log(i) } } const genForLoop = generatorForLoop() console.log(genForLoop.next()) // first console.log - 0 console.log(genForLoop.next()) // 1 console.log(genForLoop.next()) // 2 console.log(genForLoop.next()) // 3
對比下代碼,常規的循環只能一次遍歷完全部值,Generator 能夠經過調用 next 方法拿到依次遍歷的值,讓遍歷的執行變得「可控」。
function * gen () { yield 1 yield 2 yield 3 } let g = gen() // "Generator { }"
這個是 Generator 的定義方法,有幾個點值得注意:
yield 表達式的返回值是 undefined,可是遍歷器對象的 next 方法能夠修改這個默認值
function * gen () { let val val = yield 1 console.log(`1:${val}`) // 1:undefined val = yield 2 console.log(`2:${val}`) // 2:undefined val = yield 3 console.log(`3:${val}`) // 3:undefined } var g = gen() console.log(g.next()) // {value: 1, done: false} console.log(g.next()) // {value: 2, done: false} console.log(g.next()) // {value: 3, done: false} console.log(g.next()) // {value: undefined, done: true}
yeild * 是委託給另外一個遍歷器對象或者可遍歷對象
function * gen () { let val val = yield 1 console.log(`1:${val}`) // 1:undefined val = yield 2 console.log(`2:${val}`) // 2:undefined val = yield [3, 4, 5] console.log(`3:${val}`) // 3:undefined }
enerator 對象的 next 方法,遇到 yield 就暫停,並返回一個對象,這個對象包括兩個屬性:value 和 done。
26.module
在 ES6 以前,JS 文件之間的導入、導出是須要藉助 require.js、sea.js。如今,你們可使用 import、export 來實現原生 JavaScript 的導入、導出了。
導出變量或者常量
export const name = 'hello' export let addr = 'BeiJing City' export var list = [1, 2 , 3]
const name = 'hello' let addr = 'BeiJing City' var list = [1, 2 , 3] export { name as cname, addr as caddr } export default list
ES7語法
1.Array.prototype.includes
Array.prototype.includes() 方法用來判斷一個數組是否包含一個指定的值,根據狀況,若是包含則返回 true,不然返回false。
let array1 = [1, 2, 3] console.log(array1.includes(2)) // expected output: true var pets = ['cat', 'dog', 'bat'] console.log(pets.includes('cat')) // expected output: true console.log(pets.includes('at')) // expected output: false
在 ES7 以前想判斷數組中是否包含一個元素,基本能夠這樣寫:
console.log(array1.find(function (item) { return item === 2 }))
2.Math.pow
咱們一直都是這樣用的:
console.log(Math.pow(2, 3)) // 8(2的三次方)
在 ES7 能夠這樣寫了:
console.log(2 ** 3)
ES8語法
1.Async/Await
async 和 await 是 Promise 的拓展,若是對 Promise 還不瞭解的話,請移步 Promise 章節進行學習。
async function firstAsync () { return 27 } firstAsync().then(console.log) // 27
也就是說上面的代碼等同於:
async function firstAsync () { return Promise.resolve(27) }
async 的做用咱們清楚了,await呢?話很少說:
async function firstAsync () { let promise = new Promise((resolve, reject) => { setTimeout(() => resolve("Now it's done!"), 1000) }) // wait until the promise returns us a value let result = await promise // "Now it's done!" return result } firstAsync().then(console.log)
這段代碼使用了 await,從這個字面的意思看就是「等待」,它等什麼呢?很簡單,它等 Promise 返回結果。上面代碼的意思是 async 開啓了一個 Promise 對象,這個函數內部嵌套了一個 Promise 操做,這個操做須要等 1 秒才返回 「Now it’s done!」 這個結果。也就是說 await 在拿到這個結果以前不會繼續執行,一直等到結果才日後繼續執行,也就是 async function 聲明的 Promise 纔會響應(console.log才執行)。
常規
async function firstAsync () { let result = await 27 return result } firstAsync().then(console.log) // 27
對象
async function firstAsync () { let result = await { a: 1 } return result } firstAsync().then(console.log) // { a: 1 }
非 Promise 對象將用 Promise.resolve 來包裝,而 await 後邊的值做爲 resolve 的參數。
2. await 不能夠脫離 async 單獨使用
function firstAsync() { let promise = Promise.resolve(10); let result = await promise; // Syntax error }
2.Object.values()
Object.values() 返回一個數組,其元素是在對象上找到的可枚舉屬性值。屬性的順序與經過手動循環對象的屬性值所給出的順序相同(for…in,可是for…in還會遍歷原型上的屬性值)。
let grade = { 'lilei': 98, 'hanmei': 87 } console.log(Object.values(grade)) // [98, 87]
3.Object.entries
Object.entries()方法返回一個給定對象自身可枚舉屬性的鍵值對數組,其排列與使用 for…in 循環遍歷該對象時返回的順序一致。(區別在於 for-in 循環也枚舉原型鏈中的屬性)
let grade = { 'lilei': 98, 'hanmei': 87 } for (let [key, value] of grade) { console.log(key, value) // Uncaught TypeError: grade is not iterable }
咱們知道 Object 是不可直接遍歷的,上述代碼足以說明直接遍歷觸發了錯誤。若是使用 Object.entries() 則能夠完成遍歷任務。
let grade = { 'lilei': 98, 'hanmei': 87 } for (let [k, v] of Object.entries(grade)) { console.log(k, v) // lilei 98 // hanmei 87 }
在 ES8 中 String 新增了兩個實例函數 String.prototype.padStart 和 String.prototype.padEnd,容許將空字符串或其餘字符串添加到原始字符串的開頭或結尾。
這兩個方法有什麼用武之地呢?回憶下咱們處理日期的時候常常要格式化,好比 0一、0二、10等。
for (let i = 1; i < 31; i++) { if (i < 10) { console.log(`0${i}`) } else { console.log(i) } }
以前輸出1號到31號,須要手動判斷是否小於10號,小於的在前面增長 0。如今能夠這樣作了:
for (let i = 1; i < 31; i++) { console.log(i.toString().padStart(2, '0')) }
String.prototype.padStart 和 String.prototype.padEnd 用法是相同的,只是一個在開頭補白一個在結尾。
5.Object.getOwnPropertyDescriptors()
想理解 Object.getOwnPropertyDescriptors 這個方法以前,首先要弄懂什麼是描述符(descriptor)?
const data = { Portland: '78/50', Dublin: '88/52', Lima: '58/40' }
仍是上述那個對象,這裏有 key 和 value,上邊的代碼把全部的 key、value 遍歷出來,若是咱們不想讓 Lima 這個屬性和值被枚舉怎麼辦?
Object.defineProperty(data, 'Lima', { enumerable: false }) Object.entries(data).map(([city, temp]) => { console.log(`City: ${city.padEnd(16)} Weather: ${temp}`) // City: Portland Weather: 78/50 // City: Dublin Weather: 88/52 })
很成功,Lima 沒有被遍歷出來,那麼 defineProperty 的第三個參數就是描述符(descriptor)。這個描述符包括幾個屬性:
ES9語法
1.for await of
咱們知道 for…of 是同步運行的,有時候一些任務集合是異步的,那這種遍歷怎麼辦呢?
function Gen (time) { return new Promise(function (resolve, reject) { setTimeout(function () { resolve(time) }, time) }) } async function test () { let arr = [Gen(2000), Gen(100), Gen(3000)] for (let item of arr) { console.log(Date.now(), item.then(console.log)) } } test() // 1560090138232 Promise {<pending>} // 1560090138234 Promise {<pending>} // 1560090138235 Promise {<pending>} // 100 // 2000 // 3000
await 的做用,它能夠中斷程序的執行直到這個 Promise 對象的狀態發生改變,
function Gen (time) { return new Promise(function (resolve, reject) { setTimeout(function () { resolve(time) }, time) }) } async function test () { let arr = [Gen(2000), Gen(100), Gen(3000)] for (let item of arr) { console.log(Date.now(), await item.then(console.log)) } } test() // 2000 // 1560091834772 undefined // 100 // 1560091836774 undefined // 3000 // 1560091836775 undefined
從返回值看確實是按照任務的前後順序進行的,其中原理也有說明是利用了 await 中斷程序的功能。不過,在 ES9 中也能夠用 for…await…of 的語法來操做:
function Gen (time) { return new Promise(function (resolve, reject) { setTimeout(function () { resolve(time) }, time) }) } async function test () { let arr = [Gen(2000), Gen(100), Gen(3000)] for await (let item of arr) { console.log(Date.now(), item) } } test() // 1560092345730 2000 // 1560092345730 100 // 1560092346336 3000
2.Promise.prototype.finally()
Promise.prototype.finally() 方法返回一個Promise,在promise執行結束時,不管結果是fulfilled或者是rejected,在執行then()和catch()後,都會執行finally指定的回調函數。這爲指定執行完promise後,不管結果是fulfilled仍是rejected都須要執行的代碼提供了一種方式,避免一樣的語句須要在then()和catch()中各寫一次的狀況。
let connection; db.open() .then(conn => { connection = conn; return connection.select({ name: 'Jane' }); }) .then(result => { // Process result // Use `connection` to make more queries }) ··· .catch(error => { // handle errors }) .finally(() => { connection.close(); });
3.Object Rest Spread
前面在講 function 的 Rest & Spread 方法,忘卻的同窗能夠去複習下。在 ES9 新增 Object 的 Rest & Spread 方法,直接看下示例:
const input = { a: 1, b: 2 } const output = { ...input, c: 3 } console.log(output) // {a: 1, b: 2, c: 3}
ES10語法
JSON.stringify 在 ES10 修復了對於一些超出範圍的 Unicode 展現錯誤的問題。由於 JSON 都是被編碼成 UTF-8,因此遇到 0xD800–0xDFFF 以內的字符會由於沒法編碼成 UTF-8 進而致使顯示錯誤。在 ES10 它會用轉義字符的方式來處理這部分字符而非編碼的方式,這樣就會正常顯示了。
JSON.stringify('\u{D800}') === '"\\ud800"' // true
2.Array.prototype.flat()
flat() 方法會按照一個可指定的深度遞歸遍歷數組,並將全部元素與遍歷到的子數組中的元素合併爲一個新數組返回。
const newArray = arr.flat(depth) 語法
const numbers = [1, 2, [3, 4, [5, 6]]] console.log(numbers.flat()) // [1, 2, 3, 4, [5, 6]]
此時 flat 的參數沒有設置,取默認值 1,也就是說只扁平化向下一級,遇到 [3, 4, [5, 6]] 這個數組會扁平會處理,不會再繼續遍歷內部的元素是否還有數組
const numbers = [1, 2, [3, 4, [5, 6]]] console.log(numbers.flat(2)) // [1, 2, 3, 4, 5, 6]
3.Array.prototype.flatMap()
flatMap() 方法首先使用映射函數映射每一個元素,而後將結果壓縮成一個新數組。從方法的名字上也能夠看出來它包含兩部分功能一個是 map,一個是 flat(深度爲1)。
const new_array = arr.flatMap(function callback(currentValue[, index[, array]]) { // 返回新數組的元素 }[, thisArg])
參數 | 含義 | 必選 |
callback | 能夠生產一個新數組中的元素的函數,能夠傳三個參數,currentValue,index,array | y |
thisArg | 遍歷函數this的指向 | N |
const numbers = [1, 2, 3] numbers.map(x => [x * 2]) // [[2], [4], [6]] numbers.flatMap(x => [x * 2]) // [2, 4, 6]
這個小示例能夠簡單對比下 map 和 flatMap 的區別。固然還能夠看下 MDN 的示例:
let arr = ['今每天氣不錯', '', '早上好'] arr.map(s => s.split('')) // [["今", "天", "天", "氣", "不", "錯"],[""],["早", "上", "好"]] arr.flatMap(s => s.split('')) // ["今", "天", "天", "氣", "不", "錯", "", "早", "上", "好"]
4.String.prototype.trimStart()
trimStart() 方法從字符串的開頭刪除空格,trimLeft()是此方法的別名。
let str = ' foo ' console.log(str.length) // 8 str = str.trimStart() console.log(str.length) // 5
5.String.prototype.trimEnd()
trimEnd() 方法從一個字符串的右端移除空白字符,trimRight 是 trimEnd 的別名。
let str = ' foo ' console.log(str.length) // 8 str = str.trimEnd() console.log(str.length) // 6
6.String.prototype.matchAll()
matchAll() 方法返回一個包含全部匹配正則表達式及分組捕獲結果的迭代器
在瞭解 matchAll 以前,咱們回顧下 ES10 以前一共有多少種正則所有遍歷的方法。
1. RegExp.prototype.exec() with /g
function collectGroup1 (regExp, str) { const matches = [] while (true) { const match = regExp.exec(str) if (match === null) break // Add capture of group 1 to `matches` matches.push(match[1]) } return matches } collectGroup1(/"([^"]*)"/g, `"foo" and "bar" and "baz"`) // [ 'foo', 'bar', 'baz' ]
2. String.prototype.match() with /g
若是用 .match 方法結合 /g 的正則模式,將會把全部的匹配打包成一個數組返回,換句話說全部的捕獲被忽略。 'abeabd'.match(/(a)b(?=e)/g) // ["ab"]
不過若是沒有使用 /g 的正則模式,.match 的效果和 RegExp.prototype.exec() 是一致的。
3. String.prototype.replace()
function collectGroup1 (regExp, str) { const matches = [] function replacementFunc (all, first) { matches.push(first) } str.replace(regExp, replacementFunc) return matches } collectGroup1(/"([^"]*)"/ug, `"foo" and "bar" and "baz"`) // ["foo", "bar", "baz"]
如今看下 .matchAll 方法,能夠這樣作:
function collectGroup1 (regExp, str) { let results = [] for (const match of str.matchAll(regExp)) { results.push(match[1]) } return results } collectGroup1(/"([^"]*)"/g, `"foo" and "bar" and "baz"`) // ["foo", "bar", "baz"]
7.Object.fromEntries()
方法 Object.fromEntries() 把鍵值對列表轉換爲一個對象,這個方法是和 Object.entries() 相對的。
Object.fromEntries([['foo', 1], ['bar', 2]]) // {foo: 1, bar: 2}
示例
let obj = { abc: 1, def: 2, ghij: 3 } let res = Object.fromEntries( Object.entries(obj) .filter(([ key, val ]) => key.length === 3) .map(([ key, val ]) => [ key, val * 2 ]) ) console.log(res) // res is { 'abc': 2, 'def': 4 }
8.Symbol.prototype.description
咱們知道,Symbol 的描述只被存儲在內部的 [[Description]],沒有直接對外暴露,咱們只有調用 Symbol 的 toString() 時才能夠讀取這個屬性:
const name = Symbol('My name is axuebin') console.log(name.toString()) // Symbol(My name is axuebin) console.log(name) // Symbol(My name is axuebin) console.log(name === 'Symbol(My name is axuebin)') // false console.log(name.toString() === 'Symbol(My name is axuebin)') // true
toString() 方法返回一個表示當前函數源代碼的字符串
function hello (msg) { console.log('hello') } console.log(hello.toString()) // function hello (msg) { // console.log('hello') // }
10.try…catch
在 ES10 以前咱們都是這樣捕獲異常的:
try { // tryCode } catch (err) { // catchCode }
在這裏 err 是必須的參數,在 ES10 能夠省略這個參數:
try { console.log('Foobar') } catch { console.error('Bar') }
在 ES10 增長了一個數據類型:BigInt,用於處理超過 2^53 的數字。
const aBigInt = 11n; const aNumber = 156; const aBigInt = BigInt(aNumber); aBigInt === 156n // true typeof aBigInt === bigint // true
以上就是在工做中比較經常使用的es6-es10語法知識點
原文出處:https://www.cnblogs.com/zhoulifeng/p/12259809.html