在以前咱們比較一個數組中是否包含某個元素的經常使用作法是:javascript
if (arr.indexOf(el) !== -1) { ... }
或者java
if (~arr.indexOf(el)) { ... } //此處~ 爲取反,即-1取反結果爲0,0取反爲-1,1取反會-2,2取反爲-3
indexOf 結果返回是個數字,咱們必需要和其餘數字進行比較,才能見到獲得是否"存在",即-1 表示不存在,大於-1 表示存在。node
因爲 indexOf 在查找元素的比對過程當中,使用的是嚴格相等"===",好比webpack
[1,2,3].indexOf('1') //就會找不到。由於1和'1'並不相等。
一樣在當數組中含有 NaN 是,也找不到,即git
[NaN].indexOf(NaN) //找不到,由於NaN===NaN爲false。
因而可知 indexOf 並不能完美的找出是否包含某個元素值。github
因此咱們便有了下面的方式web
arr.includes(el);
includes 結果直接返回 boolean,true 表示存在,false 表示不存在,很是直觀。includes 是經過,類型和值是否「一致」,而不是「嚴格相等」正則表達式
[1,2,3].includes('1') //false [1,2,3].includes(1) //true [1,2,NaN].includes(NaN) //true
因此再之後的使用中,
indexOf 應傾向於尋找 元素的位置,可能後續還要經過這個位置進行其餘計算的場景,而 includes 應傾向於尋找 元素是否存在,只須要知道存在或者不存在,其餘沒必要知道chrome
既然數組有 indexOf,字符串也有 indexOf,那麼一樣
數組有 includes,字符串也有 includesjson
"1234567".includes("12") //true
在之前,js 要求取 m 的 n 次方,得這麼寫
Math.pow(m,n)
好比 2 的 3 次方
Math.pow(2,3) //8
而如今只須要 指數操做符"**",即兩個星號便可
2 ** 3 //表示2的3次方 3 ** 2 //表示3的2次方
因爲- + _ /,都有 -=,+=, _=, /=
一樣 也有 "="
let a = 2; a **= 2; // a = a ** 2
將 object 的 key 或者 value 轉成一個能夠遍歷的數組。
Object.values({id:1,name:2}); // [1,2] Object.keys({id:1,name:2}); // ["id", "name"] Object.entries({id:1,name:2}); // [["id", 1], ["name", 2]]
//padStart "abc".padStart(10); // " abc" 在原字符串"abc"的頭部填充空白,以使整個字符串的長度變爲10 "abc".padStart(10, "foo"); // "foofoofabc" 在原字符串"abc"的頭部填充"foo",以使整個字符串的長度變爲10 "abc".padStart(6, "123465"); // "123abc" 在原字符串"abc"的頭部填充"123465",以使整個字符串的長度變爲10,若是中途夠了,就不進行填充了 "abc".padStart(8, "0"); // "00000abc" "abc".padStart(1); // "abc"
//padEnd "abc".padEnd(10); // "abc " 同padStart,只不過填充到末尾 "abc".padEnd(10, "foo"); // "abcfoofoof" 同padStart,只不過填充到末尾 "abc".padEnd(6, "123456"); // "abc123" 同padStart,只不過填充到末尾 "abc".padEnd(1); // "abc" 同padStart,只不過填充到末尾
//trimStart " abc ".trimStart(); // "abc " " abc ".trimEnd(); // " abc" " abc ".trim(); // "abc"
獲取對象的全部自身屬性的描述符。包括 configurable(可配置),enumerable(可枚舉),writable(可寫)
Object.getOwnPropertyDescriptors({ id: 1, name: 2 }); /* { "id": { "value": 1, "writable": true, "enumerable": true, "configurable": true }, "name": { "value": 2, "writable": true, "enumerable": true, "configurable": true } } */
在以前的函數是這樣的
function clownPuppiesEverywhere(param1, param2) {} //或者這樣 function clownPuppiesEverywhere(param1, param2) {}
param2 後面若是加逗號會報錯,而如今不會報錯,它是被容許的
function clownPuppiesEverywhere(param1, param2) {} //或者這樣 function clownPuppiesEverywhere(param1, param2) {}
這樣若是咱們有新參數,只須要日後加就好了,沒必要往上一行末尾加逗號(真懶,加個逗號又不費事,雞肋特性)
將異步變爲同步神器。不再須要像 promise 那樣回調了
async function getList(){ //用async指明當前方法中有異步,可是當作同步執行 await getId(); //若是getId是個promise,則只有狀態爲resolve時,才進入下一行。若是是普通函數,則默認是resolved let result = await getName(); //還能夠有返回值。其值爲resolved(xx)中的參數 }
await 的並行處理
//由於多個await都是依次日後臺發送。若是這幾個請求以前沒有前後關聯順序,則徹底不必。能夠作成並行發送 async getName() { let str = ""; await Promise.all([this.getPromise(),this.getPromise(),this.getPromise()]); return str; }
太複雜,我也沒看懂
若是你想查看,這是詳細
文檔
在正則表達式中,「.」 點,表明 匹配除換行符以外的任何單個字符。
以下:
/.n/.test('an'); //. 匹配到了a /.n/.test('1n'); //. 匹配到了1 /.n/.test('nn'); //. 匹配到了n /.n/.test('\nn'); //.不會匹配 \n 返回false
假若有個需求,須要匹配任何字符。那怎麼辦.....
有個騷操做。
/foo[^]bar/.test('foo\nbar'); //返回true
用 [^] 替換掉. 它表示匹配包含n 在內的任意字符。
可這也太秀了,正常人都想不到這麼寫。這麼寫出來,別人也看不懂。
因此便有了下面的寫法:
/foo.bar/s.test('foo\nbar'); //返回true
正則的後面加個 s 標誌,你能夠將 s 理解爲 stop,終止的意思,即表示除了其餘的,還能匹配終止符 n,換句話說如今這個. 啥都能匹配到
咱們能夠總結下,到此爲止,正則表達式標誌符有:
g 全局搜索。 i 不區分大小寫搜索。 m 多行搜索。 s 容許 . 匹配換行符。 u 使用unicode碼的模式進行匹配。 y 執行「粘性」搜索,匹配從目標字符串的當前位置開始,可使用y標誌。
let { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 }; x; // 1 y; // 2 z; // { a: 3, b: 4 } let n = { x, y, ...z }; n; // { x: 1, y: 2, a: 3, b: 4 }
或者
let [x,y,...z] = [ 1,2,3,4 ]; x; // 1 y; // 2 z; // [3, 4] let n = [ x, y, ...z ]; n; // [1, 2, 3, 4]
...x 始終表明這是個展開式,而 x 表明原式(對象,或者數組),
相似於高數中的泰勒展開式, ...x 就是那個展開式,x 就是那個原式。
好比:
function getName({a,b,...others}){ console.log(others) } getName({a:1,b:2,c:3,d:4})
因爲...others 是展開式 c:3,d:4,那麼 others 天然就是原式{c: 3, d: 4}
在 promise 結束時,不管結果是 resovled 或者是 rejected,finally 都會執行指定的回調函數。
這避免了一樣的語句須要在 then()和 catch()中各寫一次的狀況。
因此 finally 中最適合須要進行"清空"的操做。好比 request 請求完成或失敗後,都要將 loading 設置爲 false。或者關閉打開的文件流對象,或者進行日誌記錄等。
finally()方法和 then()同樣,執行後,也返回一個 Promise。
因此通常流程是
new Promise((resolved, rejected)=>{ //... //return resolved(res); 若是執行成功 //return rejected(); 若是執行失敗 //... }).then(res=>{ //resolved的回調, res的值爲resolved傳入的參數 }).catch(err=>{ //rejected的回調。err爲rejected傳入的失敗的緣由 }).finally(()=>{ //因爲不關注resolved仍是rejected。因此沒有參數。 })
咱們常常會經過 for....of 進行迭代,以下:
let arr = [1,2,3]; for(let num of arr) { console.log(num); }
輸出 1,2,3
咱們能夠想象下,加入 arr 中的每一項不是普通類型的對象,而是 promise 呢?
//分別建立三個promise對象 let p1 = new Promise((resolved,rejected)=>{ setTimeout(()=>{ resolved(1) },1000) }); let p2 = new Promise((resolved,rejected)=>{ setTimeout(()=>{ resolved(2) },1000) }); let p3 = new Promise((resolved,rejected)=>{ setTimeout(()=>{ resolved(3) },1000) }); let arr = [p1,p2,p3]; for(let num of arr) { console.log(num); }
那執行結果會怎麼樣呢?
你將會在控制檯直接看到下面三個結果。
> Promise {<pending>} > Promise {<pending>} > Promise {<pending>}
也就是說 arr 在迭代時,分別將 p1,p2,p3 輸出控制檯了,而 p1,p2,p3 是誰,固然是 promise 啊,只不過還沒執行 resolved 而已,處於 pending 狀態。
若是咱們想在 arr 迭代時,依次輸出 p1,p2,p3 的 resolved 或者 rejected 結果呢?
咱們可使用下面的方式
//分別建立三個promise對象 let p1 = new Promise((resolved,rejected)=>{ setTimeout(()=>{ resolved(1) },1000) }); let p2 = new Promise((resolved,rejected)=>{ setTimeout(()=>{ resolved(2) },1000) }); let p3 = new Promise((resolved,rejected)=>{ setTimeout(()=>{ resolved(3) },1000) }); let arr = [p1,p2,p3]; for await(let num of arr) { console.log(num); }
在 for 後面,左圓括號前面,加個 await。
這樣在每次 arr 迭代時,等待 num 的結果爲 resolved 或者 rejected 時,才進入 for 的語句塊。
結果輸出爲: 1 2 3
咱們能夠想一想在沒有 for-await-of 以前,是怎麼用的?
let num = null; let arr = [p1,p2,p3]; num = await arr[0]; console.log(num); let num = await arr[1]; console.log(num); let num = await arr[2]; console.log(num);
是否是?可是若是 arr 中幾個這麼寫還行,可若是多了呢,顯然不如 for await of 方便。
try { throw new Error("出錯了") } catch (err) { console.log(err.message); }
咱們一般會在 catch 中經過 err 來獲取或者打印錯誤信息。
可是有些場景下咱們不須要 catch 中的 err,信息,只是捕獲錯誤,而後作些其餘的事。此時 err 參數被閒置,unused,未被使用。
針對這種狀況,es 規範容許你省略 err 參數。
try { throw new Error("出錯了") } catch () { console.log('321'); }
==Uncaught SyntaxError: Unexpected token ')'==
報錯了,納尼?
注意不是上面這種省略,而應該是下面的省略。
try { throw new Error("出錯了") } catch{ console.log('321'); }
catch 後面直接跟{便可。
坑我給大家填上了,別在掉進去了。
因爲 json 能夠支持 "u2028"(行分隔符)和 "u2029"(段落分隔符)兩個特殊字符。
咱們能夠看看這兩個字符長什麼樣
方方正正的,一個寫着 LSEP,一個寫着 PSEP.
建立個 json,包含 u2028.
沒問題,能夠解析。
可是這兩個字符以前在 js 中是不能寫的。因此 ECMA 在標準中實現了他們,以便在 js 中也能正常使用。
symbol 是一種基本數據類型。 每一個從 Symbol()返回的 symbol 值都是惟一的。一個 symbol 值能做爲對象屬性的標識符;這是該數據類型僅有的目的。
咱們能夠經過下面方式獲取 symbol 的描述。
Symbol('desc').description //desc
之前因爲 function 繼承了從 object 來的 toString 方法;因此 toString 爲"[object Object]"
function getName(){ return "hello"; }; getName.toString() // "[object Object]"
而修訂後的 function toString 覆蓋了從 object 繼承來的 toString 方法。返回一個包含定義函數的源文本段。
let obj = { id: 1, name: "hello", }; let entries = Object.entries(obj); // [["id",1],["name","hello"]]
一樣咱們可使用 fromEntries 還原 obj
let obj = Object.fromEntries([ ["id", 1], ["name", "hello"], ]); // {id: 1, name: "hello"}
具體可參考 mdn 連接
let regexp = /te/; let str = 'test1test2'; str.match(regexp) // ['te'] 匹配到第一個位置就中止,並返回匹配到的字符串
加個 g 標誌
let regexp = /te/g; let str = 'test1test2'; str.match(regexp) //["te", "te"] 返回全部匹配到的字符串
matchAll 會返回一個包含全部匹配正則表達式的結果及分組捕獲組的迭代器。且正則表達式必須含有標誌 g,不然報錯
let regexp = /te/g; let str = 'test1test2'; str.matchAll(regexp) // RegExpStringIterator{} 但會迭代器。
能夠經過解構方式取出迭代器。
let regexp = /te/g; let str = 'test1test2'; let arr = [...str.matchAll(regexp) ] // arr[0] // {0: "te", groups: undefined, index: 0, input: "test1test2", length: 1} arr[1] // {0: "te", groups: undefined, index: 5, input: "test1test2", length: 1}
這樣咱們不只能獲取到 匹配的字符串,仍是經過 index 知道匹配的位置。
在 js 中,引入模塊的方式一般是:
import _ from "lodash"
在代碼運行以前,在編譯階段,就已經綁定引入本地做用域。
可是若是咱們想在運行階段動態的引入呢?
答案是沒有辦法。
若是你使用的是 webpack,則可使用 webpack 的 require("xxx") 動態的將模塊引入。
因此 ECMA 直接在 js 核心庫中,實現了這個 api。即便不適用 webpack,也能直接在瀏覽器上運行 import().
在 chrome 控制檯咱們能夠直接使用。
同時發現,import()返回的是個 promise 對象,
因此咱們能夠這麼用
import("/static/js/app.js").then(res=>{ //xxx }) 或者 await import("/static/js/app.js"); //後續代碼
在 javascript 中,interget 的最大數爲 2^53
Math.pow(2,53) // 9007199254740992
若是加 1,發現沒變。
Math.pow(2,53)+1 // 9007199254740992
假如要表示 比 Math.pow(2,53) 還要大的數值怎麼辦?
可使用 BigInt 類型來表示
const theBiggestInt = 9007199254740991n; //後面追加 n,表示這是個bigInt類型 const alsoHuge = BigInt(9007199254740991); //直接經過構造器建立。
在 bigInt 中,最小的 1,用 1n 來表示,以下面的運算
1n+1n==2n 2n-1n == 1n 2n * 2n == 4n 4n / 2n == 2n 9007199254740992n +1n==9007199254740993n // //2^53加1 結果爲
特殊狀況
1n+1n==2 //true 0n == 0 //true //可是下面爲false 1n+1n==2 //false 0n === 0 //false
特別的
1n+1 會直接報錯 Uncaught TypeError: Cannot mix BigInt and other types, use explicit conversions
在 promise 中的組合器有下面幾種:
const promise1 = new Promise((resolve, reject) => { setTimeout(resolve, 3000, "1oo"); }); const promise2 = new Promise((resolve, reject) => { setTimeout(reject, 1000, "foo"); }); const promises = [promise1, promise2]; Promise.allSettled(promises).then((results) => { //results [{"status":"fulfilled","value":"1oo"},{"status":"rejected","reason":"foo"}] });
在之前,從不一樣的 JavaScript 環境中獲取全局對象須要不一樣的語句。在 Web 中,能夠經過 window、self 或者 frames 取到全局對象,可是在 Web Workers 中,只有 self 能夠。在 Node.js 中,它們都沒法獲取,必須使用 global。
globalThis 提供了一個標準的方式來獲取不一樣環境下的全局 this 對象(也就是全局對象自身)
這樣在瀏覽器中, globalThis 就是 window 或者 self,
在 Web Workers 中, globalThis 就是 self,
在 nodejs 中,globalThis 就是 global。
快去把你項目中的 window,self,global 等替換成 globalThis 吧
for...in 語句以任意順序遍歷一個對象的除 Symbol 之外的可枚舉屬性。
在對象中使用 for....in 並無什麼問題
for(let item in {id:1,name:'123'}){ console.log(item) //依次輸出 id, name }
不建議 for....in 和數組搭配一塊兒使用。爲何呢,請看下面的例子:
for(let item in ['a','b','c']){ console.log("-===",item) //依次輸出 '0' '1' '2', //注意 '0' '1' '2'並不是下標,而是枚舉位置 }
咱們再給數組添對象添加個可枚舉屬性
let arr = [1,2,3]; Object.defineProperty(arr, "getName", { value: "hello", enumerable: true }); //等同於 let arr = [1,2,3]; Array.prototype.getName = "hello"; //緊接着咱們執行下面 for(let item in arr){ console.log(item) //依次輸出 '0' '1' '2' 'getName' }
發現沒?? 是不出錯了,若是咱們項目中,在 util 的模塊中,給 Array.prototype 上增長了一些 polyfill,那麼咱們使用 for....in 遍歷數組,就必然出錯。
固然咱們能夠經過其餘方式避免。
好比
for(let i=0;i<arr.length;i++){ // } //或者 arr.forEach((value,index)=>{ // })
在之前咱們進行條件判斷時:
let obj = { "circle": { "x": 0, "y": 0 }, "radius": 50 }; if(obj && obj.circle && obj.circle.x){ //而後纔敢拿着 obj.circle.x 進行操做。不然假如obj爲null,obj.circle 就會直接報錯。 }
而如今不用這麼麻煩
let obj = { "radius": 50 }; if(obj?.circle?.x){ // obj.circle.x 進行操做 }
?.表示是否有這個屬性,若是沒有(undifined),或者有,但值爲 null。則直接短路不會再繼續向下。從而保護了代碼不被出錯。
let obj = { "circle": { "y": 0 }, "radius": 50 }; if(obj?.circle?.x){ }else{ //不會報錯。在執行到 ?.circle時獲得undefiend,直接短路。返回undefiend, 進入 else }
一樣,數組也能夠
let arr = ['a','b']; arr?.[1] // 'b'
最後注意,可選鏈不能用於賦值操做
let arr = ['a','b']; arr?.[1] = 'c' //報錯 Uncaught SyntaxError: Invalid left-hand side in assignment
它是個邏輯操做符,相似於 ||
|| 操做符,只有當左側爲假值(0, '', NaN, false, null,undefined)是才返回右側的值.
0 || 'A' //A '' || 'A' //A NaN || 'A' //A false || 'A' //A null || 'A' //A undefined || 'A' //A
而 ??只有左側爲空值(只有 null 和 undefined)時才
0 ?? 'A'; // 0 '' ?? 'A' // '' NaN ?? 'A' //NaN false ?? 'A' //false null ?? 'A' //A undefined ?? 'A' //A
具體查看
文檔
參考 ECMA 規範:
https://github.com/tc39/proposals/blob/master/finished-proposals.md