jses6 新特性,以及es7/8/9 或,常用特性
1、es6
1.1 class類
1.1.1 類的基本使用
class Person {// 注意: 一個類只能有一個構造函數// 當我們通過 new 關鍵字操作類的時候,會調用這個 constructor 函數,并且執行如下操作// 1.在內存中創建一個對象 moni = {}// 2.將類的原型prototype賦值給創建出來的對象 moni.__proto__ = Person.prototype// 3.將對象賦值給函數的this: new綁定 this = moni// 4.執行函數體中的代碼// 5.自動返回創建出來的對象constructor(name, age) {this.name = name;this.age = age;} } var p1 = new Person("呆呆狗", 20); console.log(p1);1.1.2 類的方法
var names = ["abc", "cba", "nba"]; class Person {constructor(name, age) {this.name = name;this.age = age;this._address = "山東";}// 其實這個方法,會被放到 Person的原型身上eating() {console.log(this.name + " eating·~");}// 類的訪問器方法get address() {console.log("攔截訪問操作");return this._address;}set address(newAddress) {console.log("攔截設置操作");this._address = newAddress;}// 類的靜態方法,也稱為 類方法, 直接通過類名. d// Person.randomPerson 可以直接這樣訪問static randomPerson() {var nameIndex = Math.floor(Math.random() * names.length);var name = names[nameIndex];var age = Math.floor(Math.random() * 100);return new Person(name, age);} } var p1 = new Person("呆呆狗", 20); console.log(p1); p1.eating(); p1.address = "青島"; console.log("p1修改address后的", p1); // console.log(p1.randomPerson()); //這樣調用是錯誤的 console.log(Person.randomPerson());1.2 字面量的增強
var name = "ddg" var age = 18 var obj = {// 屬性的簡寫name,age,// 方法的簡寫foo() {},[name + '134']: "哈哈哈哈嗝" } console.log(obj);1.3 解構
數組的解構
var names = ["abc", "cba", "nba"] // var item1 = names[0] // var item2 = names[1] // var item3 = names[2]// 對數組的解構: [] var [item1, item2, item3] = names console.log(item1, item2, item3)// 解構后面的元素 var [, , itemz] = names console.log(itemz)// 解構出一個元素,后面的元素放到一個新數組中 var [itemx, ...newNames] = names console.log(itemx, newNames)// 解構的默認值 var [itema, itemb, itemc, itemd = "aaa"] = names console.log(itemd)對象的解構
var obj = {name: "why",age: 18,height: 1.88 }// 對象的解構: {} var { name, age, height } = obj console.log(name, age, height)var { age } = obj console.log(age)var { name: newName } = obj console.log(newName)var { address: newAddress = "廣州市" } = obj console.log(newAddress) // 廣州市function foo(info) {console.log(info.name, info.age) }foo(obj)function bar({ name, age }) {console.log(name, age) }bar(obj)1.4 let const
- const本質上傳遞的值 是不可以修改的,(引用類型除外)
- let 、const 不可以重復定義相同名字的變量
- let/const他們是沒有作用域提升
1.5 es5的作用域
// 聲明對象的字面量 // var obj = { // name: "why" // }// ES5中沒有塊級作用域 // 塊代碼(block code) // { // // 聲明一個變量 ,在es5 的時候,這個大括號,沒有意義 // var foo = "foo" // }// console.log(foo)// 在ES5中只有兩個東西會形成作用域 // 1.全局作用域 // 2.函數作用域 // function foo() { // var bar = "bar" // }// console.log(bar) // 訪問不到function foo() {function demo() {} }1.6 es6的作用域
// ES6的代碼塊級作用域 // 對let/const/function/class聲明的類型是有效 {let foo = "why"function demo() {console.log("demo function")}class Person { } }// console.log(foo) // foo is not defined // 不同的瀏覽器有不同實現的(大部分瀏覽器為了兼容以前的代碼, 讓function是沒有塊級作用域) // demo() // 可以調用 var p = new Person() // Person is not defined {}// if語句的代碼就是塊級作用域 // if (true) { // var foo = "foo" // let bar = "bar" // }// console.log(foo) // 可以訪問 // console.log(bar) // 不可以訪問// switch語句的代碼也是塊級作用域 // var color = "red"// switch (color) { // case "red": // var foo = "foo" // let bar = "bar" // }// console.log(foo) // 可以訪問 // console.log(bar) // 不可以訪問// for語句的代碼也是塊級作用域 // for (var i = 0; i < 10; i++) { // // console.log("Hello World" + i) // }// console.log(i) //可以訪問for (let i = 0; i < 10; i++) { }console.log(i) // 不可以訪問1.7 塊級作用域的應用場景
const btns = document.getElementsByTagName('button')// for (var i = 0; i < btns.length; i++) { // (function(n) { // btns[i].onclick = function() { // console.log("第" + n + "個按鈕被點擊") // } // })(i) // }// console.log(i)for (var i = 0; i < btns.length; i++) {btns[i].onclick = function () {console.log("第" + i + "個按鈕被點擊")// 點擊的時候 輸出的 永遠是 第4個按鈕被點擊} }console.log(i)1.8 模板字符串
// ES6之前拼接字符串和其他標識符 const name = "why" const age = 18 const height = 1.88// console.log("my name is " + name + ", age is " + age + ", height is " + height)// ES6提供模板字符串 `` const message = `my name is ${name}, age is ${age}, height is ${height}` console.log(message)const info = `age double is ${age * 2}` console.log(info)function doubleAge() {return age * 2 }const info2 = `double age is ${doubleAge()}` console.log(info2)1.9 模板字符串調用函數
// 第一個參數依然是模塊字符串中整個字符串, 只是被切成多塊,放到了一個數組中 // 第二個參數是模塊字符串中, 第一個 ${} function foo(m, n, x) {console.log(m, n, x, "---------");// 如果是 模板字符串調用的方式// 輸出結果是: ['Hello', 'Wo', 'rld', raw: Array(3)] 'why' 18 '---------' }// foo("Hello", "World")// 另外調用函數的方式: 標簽模塊字符串 // foo``// foo`Hello World` const name = "why"; const age = 18; // ['Hello', 'Wo', 'rld'] foo`Hello${name}Wo${age}rld`;1.10 函數的默認參數
// ES5以及之前給參數默認值 /*** 缺點:* 1.寫起來很麻煩, 并且代碼的閱讀性是比較差* 2.這種寫法是有bug*/ // function foo(m, n) { // m = m || "aaa" // n = n || "bbb"// console.log(m, n) // }// 1.ES6可以給函數參數提供默認值 function foo(m = "aaa", n = "bbb") {console.log(m, n) }// foo() foo(0, "")// 2.對象參數和默認值以及解構 // 給它一個 有 name 和 age 的對象 function printInfo({ name, age } = { name: "why", age: 18 }) {console.log(name, age) }printInfo({ name: "kobe", age: 40 })// 另外一種寫法 // 給它一個空對象,然后 添加默認值 function printInfo1({ name = "why", age = 18 } = {}) {console.log(name, age) }printInfo1()// 3.有默認值的形參最好放到最后 function bar(x, y, z = 30) {console.log(x, y, z) }// bar(10, 20) bar(undefined, 10, 20)// 4.有默認值的函數的length屬性 function baz(x, y, z, m, n = 30) {console.log(x, y, z, m, n) }console.log(baz.length) // 有默認值的參數開始往后都不算在length里面 ,有默認值的參數,不算在 length1.11 函數的剩余參數
// 函數的剩余參數 function foo(first, ...arr) {console.log(first, arr); //1 , [2, 3, 4, 5, 6] } foo(1, 2, 3, 4, 5, 6);1.12 箭頭函數
1.13 展開運算符
- 展開語法(Spread syntax)
- 可以在函數調用/數組構造時,將數組表達式或者string在語法層面展開
- 還可以在構造字面量對象時,將對象表達式按key-value的方式展開
- 展開語法的場景
- 在函數調用時
- 在數組構造時
- 在構造對象字面量時,也可以使用展開運算符,(ES9,es2018增加的)
1.14 Symbol
// 2.ES6中Symbol的基本使用 const s1 = Symbol() const s2 = Symbol()console.log(s1 === s2)// ES2019(ES10)中, Symbol還有一個描述(description) const s3 = Symbol("s3的描述") console.log(s3.description)// 's3的描述'// 3.Symbol值作為key // 3.1.在定義對象字面量時使用 const obj = {[s1]: "abc",[s2]: "cba" }// 3.2.新增屬性 obj[s3] = "nba" console.log('obj', obj); // 3.3.Object.defineProperty方式 const s4 = Symbol() Object.defineProperty(obj, s4, {enumerable: true, // 是否可枚舉configurable: true, // 是否可刪除writable: true, // 是否可重寫value: "mba" })console.log(obj[s1], obj[s2], obj[s3], obj[s4]) // 注意: 不能通過.語法獲取 // console.log(obj.s1)// 4.使用Symbol作為key的屬性名,在遍歷/Object.keys等中是獲取不到這些Symbol值 // 需要Object.getOwnPropertySymbols來獲取所有Symbol的key console.log(Object.keys(obj)) console.log(Object.getOwnPropertyNames(obj)) console.log(Object.getOwnPropertySymbols(obj)) const sKeys = Object.getOwnPropertySymbols(obj) for (const sKey of sKeys) {console.log(obj[sKey]) }// 5.Symbol.for(key)/Symbol.keyFor(symbol) const sa = Symbol.for("aaa") const sb = Symbol.for("aaa") console.log(sa === sb) // 在key 相同的情況下,他倆是一樣的const key = Symbol.keyFor(sa) console.log(key) // 返回 sa 的 key const sc = Symbol.for(key) console.log(sa === sc)console.log('~~~~~~~~~~~~~'); const ddg1 = Symbol('呆呆狗') const ddg2 = Symbol('呆呆狗') console.log(ddg1 === ddg2); // 不相等1.15 Set
// 10, 20, 40, 333 // 1.創建Set結構 const set = new Set() set.add(10) set.add(20) set.add(40) set.add(333)set.add(10)// 2.添加對象時特別注意: 會創建出來兩個對象,他們兩個指向的是不同的地址 set.add({}) set.add({})const obj = {} set.add(obj) // 這個時候存放的就是同一個對象,添加的地址都是同一個 set.add(obj)// console.log(set)// 3.對數組去重(去除重復的元素) const arr = [33, 10, 26, 30, 33, 26] // const newArr = [] // for (const item of arr) { // if (newArr.indexOf(item) !== -1) { // newArr.push(item) // } // }const arrSet = new Set(arr) // const newArr = Array.from(arrSet) // const newArr = [...arrSet] // console.log(newArr)// 4.size屬性 console.log(arrSet.size)// 5.Set的方法 // add arrSet.add(100) console.log(arrSet)// delete arrSet.delete(33) console.log(arrSet)// has console.log(arrSet.has(100))// clear // arrSet.clear() console.log(arrSet)// 6.對Set進行遍歷 1.forEach or for of arrSet.forEach(item => {console.log(item) })for (const item of arrSet) {console.log(item) }1.16 WeakSet
和Set 類似,也是內部元素不能重復的數據結構
其實它的應用場景很少
- WeakSet 中只能存放 對象類型 ,不能存放基本數據類型
- WeakSet 對元素的引用是弱引用,如果沒有其他引用對某個對象進行引用,那么GC可以對該對象進行回收
常見方法
- WeakSet 常見的方法
- add(value):添加某個元素,返回WeakSet對象本身
- delete(value):從WeakSet中刪除和這個值相等的元素,返回Boolean類型
- has(value):判斷WeakSet中是否存在某個元素,返回布爾類型
- 注意:WeakSet 不能遍歷
- 因為WeakSet 只是對對象的弱引用,如果我們遍歷獲取到其中的元素,那么有可能造成對象不能正常的銷毀
- 所以存儲到WeakSet 的對象,是沒辦法獲取的
假設,是Set 結構,把 obj = null 以后, 0x100也不會銷毀,因為Set里面 還有一個元素在引用著 0x100
如果是 WeakSet 結構,obj=null 以后,0x100 會被回收的。因為如果沒有其他引用對 0x100 進行引用,所以0x100 會被回收
1.17 Map
map數據結構,用于存儲映射關系
之前,對象只能用字符串/Symbol來作為 key,
1.18 WeakMap
在vue3的響應式原理,就用到了
-
區別一:WeakMap的key只能使用對象,不接受其他的類型作為key;
-
區別二:WeakMap的key對對象想的引用是弱引用,如果沒有其他引用引用這個對象,那么GC可以回收該對象;
WeakMap常見方法
-
set(key, value):在Map中添加key、value,并且返回整個Map對象;
-
get(key):根據key獲取Map中的value;
-
has(key):判斷是否包括某一個key,返回Boolean類型;
-
delete(key):根據key刪除一個鍵值對,返回Boolean類型;
假設,是Map 結構,把 obj = null 以后, 0x100也不會銷毀,因為map里面 還有一個key 在引用著 0x100
如果是 WeakMap 結構,obj=null 以后,0x100 會被回收的。因為如果沒有其他引用對 0x100 進行引用,所以0x100 會被回收
1.19 promise
1.19.1 Promise.resolve
/*** resolve(參數)* 1> 普通的值或者對象 pending -> fulfilled* 2> 傳入一個Promise* 那么當前的Promise的狀態會由傳入的Promise來決定* 相當于狀態進行了移交* 3> 傳入一個對象, 并且這個對象有實現then方法(并且這個對象是實現了thenable接口)* 那么也會執行該then方法, 并且又該then方法決定后續狀態*/// 1.傳入Promise的特殊情況 // const newPromise = new Promise((resolve, reject) => { // // resolve("aaaaaa") // reject("err message") // })// new Promise((resolve, reject) => { // // pending -> fulfilled // resolve(newPromise) // }).then(res => { // console.log("res:", res) // }, err => { // console.log("err:", err) // })// 2.傳入一個對象, 這個兌現有then方法 new Promise((resolve, reject) => {// pending -> fulfilledconst obj = {then: function (resolve, reject) {// resolve("resolve message")reject("reject message")}}resolve(obj) }).then(res => {console.log("res:", res) // 這里的res 或者err 并不是 obj 這個對象,而是obj.then 這個方法里面的 傳遞過來的值,因為這個obj 對象 有 then 方法,所以會默認執行這個方法 }, err => {console.log("err:", err) })// eatable/runable const obj = {eat: function () {},run: function () {} }1.19.2 Promise.then
- 同一個promise,可以被多次調用 then 方法
- then 方法傳入的回調函數,也是擁有返回值的
- 如果我們返回的是一個普通值(數值/字符串/普通對象/undefined), 那么這個普通的值被作為一個新的Promise的resolve值(就是說可以鏈式調用)
- 如果我們返回的是一個Promise,繼續鏈式調用
- 如果返回的是一個對象, 并且該對象實現了thenable,相當于返回了一個新的promise
1.19.3 Promise.catch
事實上catch方法也是會返回一個Promise對象的,所以catch方法后面我們可以繼續調用then方法或者catch方法
// catch 也可以多次調用 const promise = new Promise((resolve, reject) => {reject("111111") }) promise.then(() => { }, (err) => {// 如果 new Promise 參數的回調,執行 reject() ,那么 這里就會捕捉到,而不會執行.catchconsole.log('then里面失敗的回調');throw new Error('222') }).catch(err => {console.log('catch失敗的回調'); })promise.catch(() => {console.log('第二個catch'); })1.19.4 Promise.finally
finally是在ES9(ES2018)中新增的一個特性:表示無論Promise對象無論變成fulfilled還是reject狀態,最終都會被執行的代碼。
finally方法是不接收參數的,因為無論前面是fulfilled狀態,還是reject狀態,它都會執行。
const promise = new Promise((resolve, reject) => {// resolve("resolve message")reject("reject message") })promise.then(res => {console.log("res:", res) }).catch(err => {console.log("err:", err) }).finally(() => {console.log("finally code execute") })1.19.5 Promise.resolve
Promise.resolve的用法相當于new Promise,并且執行resolve操作,它的返回值是一個promise
resolve參數的形態
- 情況一:參數是一個普通的值或者對象
- 情況二:參數本身是promise
- 情況三:參數是一個thenable
1.19.6 Promise.reject
reject方法類似于resolve方法,只是會將Promise對象的狀態設置為reject狀態
Promise.reject的用法相當于new Promise,只是會調用reject
const promise1 = Promise.reject(new Promise(() => { }))promise1.then(res => {console.log("res1:", res) }).catch(err => {console.log("err1:", err)// 這個時候,以 new Primise 的狀態為準,但是這個promise 現在的狀態是 pending }) const promise2 = Promise.reject(new Promise((resolve, reject) => {resolve('promise2 成功') }))promise2.then(res => {console.log("res2:", res) }).catch(err => {// 因為 Promise.reject // 還是會走這個 錯誤的回調,console.log("err2:", err)return err }).then(res => {// 如果 .catch 里面沒有 return err ,那么在then 里面則會輸出 undefined// 這里會輸出 promise2 成功console.log('Promise.reject里面的成功回調的監聽: ', res); })1.19.7 Promise.all
// 創建多個Promise const p1 = new Promise((resolve, reject) => {setTimeout(() => {resolve(11111)}, 1000); })const p2 = new Promise((resolve, reject) => {setTimeout(() => {reject(22222)// resolve(222)}, 2000); })const p3 = new Promise((resolve, reject) => {setTimeout(() => {resolve(33333)}, 3000); })// 需求: 所有的Promise都變成fulfilled時, 再拿到結果 // 意外: 在拿到所有結果之前, 有一個promise變成了rejected, 那么整個promise是rejected /*** Promise.all 返回值是一個數組。和 參數 順序相同的一個數組* 它的參數如果不是 promise,也會轉成promise* 它是等所有的promise都成功,以后在執行* 如果有一個promise 調用了 reject 那么 會直接走 catch * */Promise.all([p2, p1, p3, "aaaa"]).then(res => {console.log(res) }).catch(err => {console.log("err:", err) })1.19.8 Promise.allSettled
- all方法有一個缺陷:當有其中一個Promise變成reject狀態時,新Promise就會立即變成對應的reject狀態
- 那么對于resolved的,以及依然處于pending狀態的Promise,我們是獲取不到對應的結果的
- 在ES11(ES2020)中,添加了新的API Promise.allSettled
- 該方法會在所有的Promise都有結果(settled),無論是fulfilled,還是reject時,才會有最終的狀態
- 并且這個Promise的結果一定是fulfilled的
1.19.9 Promise.race
race是競技、競賽的意思,表示多個Promise相互競爭,誰先有結果,那么就使用誰的結果
// 創建多個Promise const p1 = new Promise((resolve, reject) => {setTimeout(() => {resolve(11111)}, 3000); })const p2 = new Promise((resolve, reject) => {setTimeout(() => {reject(22222)}, 500); })const p3 = new Promise((resolve, reject) => {setTimeout(() => {resolve(33333)}, 1000); })// race: 競技/競賽 // 只要有一個Promise變成fulfilled(完成狀態)狀態, 那么就結束 // 意外: Promise.race([p1, p2, p3]).then(res => {console.log("res:", res) }).catch(err => {console.log("err:", err) })1.19.10 Promise.any
any方法是ES12中新增的方法,和race方法是類似的
- any方法會等到一個fulfilled狀態,才會決定新Promise的狀態
- 如果所有的Promise都是reject的,那么也會等到所有的Promise都變成rejected狀態
- 如果所有的Promise都是reject的,那么會報一個AggregateError的錯誤
2、es7
2.1 includes
const names = ["abc", "cba", "nba", "mba", NaN]if (names.indexOf("cba") !== -1) {console.log("包含abc元素") }// ES7 ES2016 // 第二個參數,從 索引值2 開始 if (names.includes("cba", 2)) {console.log('從2查找包含 cba'); }if (names.indexOf(NaN) !== -1) {// 不可以判斷是否有 NaNconsole.log("包含NaN") }if (names.includes(NaN)) {// 可以正確判斷 是否有 NaNconsole.log("包含NaN,includes") }2.2 指數運算
const result1 = Math.pow(3, 3) // ES7: ** const result2 = 3 ** 3 console.log(result1, result2)3、es8
3.1 Object.keys
const obj = {name: "呆呆狗",age: 20 }console.log(Object.keys(obj)); // [ 'name', 'age' ] console.log(Object.values(obj));// [ '呆呆狗', 20 ] // Object.values如果傳入數組,那么返回的就是數組本身 // Object.values如果傳入字符串,那么返回值,是把 字符串分割成數組3.2 Object.entries
const obj = {name: "呆呆狗",age: 20 }console.log(Object.entries(obj)); // [ [ 'name', '呆呆狗' ], [ 'age', 20 ] ] const objEntries = Object.entries(obj) objEntries.forEach(item => {console.log(item[0], item[1]); })console.log(Object.entries(['a', 'b', 'c'])); // [ [ '0', 'a' ], [ '1', 'b' ], [ '2', 'c' ] ] console.log(Object.entries('abc')); // [ [ '0', 'a' ], [ '1', 'b' ], [ '2', 'c' ] ]3.3 padStart padEnd
const message = "Hello World" // 第一個參數,是字符串填充完的長度,第二個參數默認是空格 const newMessage = message.padStart(15, "*").padEnd(20, "-") console.log(newMessage) // ****Hello World-----// 案例 const cardNumber = "321324234242342342341312" const lastFourCard = cardNumber.slice(-4)//截取最后四位 const finalCard = lastFourCard.padStart(cardNumber.length, "*") console.log(finalCard) // ********************13123.4 Trailing-Commas
function foo(m, n,) {}foo(20, 30,) // 最后多加一個逗號 是沒事的3.5 async await
先空著
3.6 Object.getOwnPropertyDescriptors
這個方法主要的作用是返回屬性的描述對象(descriptor)
// name 和age 雖然沒有使用屬性描述符來定義,但是他們也具備對應的特性的 // value: 賦值的 value // configurable: true // enumerable:true // writable:true var obj = {name: "why",age: 18 } // 數據屬性描述符 // 用了屬性描述符,value 默認是 undefined,其他默認是 false Object.defineProperty(obj, "address", {value: "北京市",// configurable:false 表示 這個屬性不可刪除/不可以重新定義屬性描述符configurable: false,// enumerable 配置 該屬性是否是可以枚舉的,false 不可枚舉的// 用 for in 遍歷對象,會找不到 address,如果 是true 那就會找到addressenumerable: false,// writable表示 該屬性是否可以被修改,false 表示 不可以修改,true 表示可以修改writable: false, }) console.log(Object.getOwnPropertyDescriptors(obj));4、es9
4.1 迭代器
后續補充
4.2 對象展開運算符
總結
以上是生活随笔為你收集整理的jses6 新特性,以及es7/8/9 或,常用特性的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【T6】打印总账的时候提示:打印机缺纸(
- 下一篇: 找到自身管理创新支点 振兴物流业