你應該知道的 6 個 JavaScript 特性

已發表: 2020-09-24

一年多以前,我們討論了在 Gutenberg 中舒適地開發的 5 個“新” JavaScript 特性。 在那裡,我們了解了對象和數組解構是什麼,如何創建箭頭函數,展開和休息運算符是什麼等等。 幸運的是,JavaScript 仍然有很多特性,一旦你熟悉了它們,它們將幫助你編寫更易懂和簡潔的代碼。

今天我將向你展示六個非常酷的 JavaScript 特性。 運算符、變量作用域、promise、異步函數……你準備好學習它們了嗎?

#1 JavaScript 中帶有運算符的可選鏈接?.

當有可能是undefinednull時,可選的鏈接運算符允許簡化對對象屬性的訪問。 例如,假設您有一個如下對象:

 const toni = { name: 'Antonio', details: { age: 35, }, };

要訪問toniage ,您首先可以訪問details屬性,然後是age

 function getAge( person ) { return person.details.age; }

我們在前面的函數中遇到的問題,我相信這對你來說並不新鮮,我們期望這個person擁有的屬性並不總是存在。 也就是說,如果personperson.detailsundefined ,上述函數將觸發類型錯誤:

 getAge( toni ); // 35 getAge( {} ); // Uncaught TypeError: person.details is undefined

通常,我們通過添加一些安全防護來克服這個問題:

 function getAge( person ) { if ( ! person ) { return; } if ( ! person.details ) { return; } return person.details.age; } getAge( toni ); // 35 getAge( {} ); // undefined

這清楚地解決了它。 不幸的是,生成的函數更複雜,並且有很多嘈雜的代碼,使我們的注意力從真正重要的事情上轉移開。 為了回到正軌並以更簡單的方式修復解決方案,我們所要做的就是使用可選的鏈接運算符?.

 function getAge( person ) { return person?.details?.age; } getAge( toni ); // 35 getAge( {} ); // undefined

本質上,這個運算符讓我們訪問每個屬性,只要它不是undefinednull 。 一旦它檢測到我們嘗試訪問不存在對象的屬性,它就會返回undefined

# 2 Nullish 合併運算符 ( ?? )

在 JavaScript 中,使用此運算符為變量設置默認值非常容易: || , 正確的? 錯誤的! 我們都這樣做了,但如果你不小心,它可能會導致意想不到的副作用......

例如,假設我們的 Redux 存儲中有一個選擇器,它允許我們檢索用戶設置的值。 如果用戶還沒有指定一個值(也就是說,該值是undefined ),我們使用||返回一個默認值。 :

 function getValue( state ) { return state.value || 5; }

現在,讓我們看看在用戶設置了一個或另一個值後我們使用前一個函數得到的幾個例子:

 // No setValue( x )... getValue(); // 5 setValue( 2 ); getValue(); // 2 setValue( 1 ); getValue(); // 1 setValue( 0 ); getValue(); // 5

哎呀! 在我們到達最後一個案例之前,一切都很好! 顯然,如果用戶將值設置為0 ,則函數的結果變為5 。 為什麼? 好吧,基本原理非常明顯: x||y當且僅當x是“假”值時才返回y 。 這通常工作正常,因為undefined是一個錯誤的值。 但是例如false0也是如此。

實際上,我們只想在沒有默認值時設置default值。 所以我們可以添加一個安全衛士來檢查是否有值:

 function getValue( state ) { if ( undefined === state.value ) return 5; return state.value; }

如果我們喜歡的話,我們甚至可以使用三元運算符來編寫它:

 function getValue( state ) { return undefined === state.value ? 5 : state.value; }

但是,再一次,這兩種解決方案都不必要地使代碼複雜化。 要為變量分配默認值,我們必須使用 nullish 合併運算符?? ,當且僅當左側部分為nullundefined時才返回右側部分:

 function getValue( state ) { return state.value ?? 5; }

而且,驚喜 - 驚喜!結果正是我們想要的:

 // No setValue( x )... getValue(); // 5 setValue( 2 ); getValue(); // 2 setValue( 1 ); getValue(); // 1 setValue( 0 ); getValue(); // 0

哦,順便說一句,您可以將此運算符與賦值結合使用。 例如,這個:

 value = value ?? 5;

相當於:

 value ??= 5;

#3 Promise 和異步函數

Promise 是一種在 JavaScript 中實現的機制,它允許我們在處理異步操作時簡化我們的源代碼,即,結果不是立即可用的操作。 例如,如果我們想從我們的服務器檢索數據,很明顯響應不會是即時的,因為我們必須等待服務器接收到請求,處理它,然後將響應發回給我們。

在較舊的 JavaScript 版本和庫(例如,jQuery)中,我們曾經使用回調來實現這一點。 這個想法很簡單:連同請求本身,定義響應可用時應該調用的函數(回調)。 這樣,當異步操作(即從服務器檢索數據)完成時,庫將調用該函數,我們的邏輯將恢復:

 jQuery.ajax( { url: 'https://server.com/wp-json/wp/users/1', success: ( user ) => { console.log( user ); }, } );

如果我們只觸發一個單獨的、孤立的請求,這個解決方案非常優雅和方便。 但是,一旦我們需要執行更多請求,事情就會很快變髒。 例如,如果我們想請求兩個不同的用戶,我們必須嵌套回調:

 jQuery.ajax( { url: 'https://server.com/wp-json/wp/v2/users/1', success: ( user1 ) => { jQuery.ajax( { url: 'https://server.com/wp-json/wp/v2/users/2', success: ( user2 ) => { console.log( user1, user2 ); }, } ); }, } );

Promise 是這個問題的解決方案:如果不是立即獲得某個結果(例如,當我們從服務器檢索某些東西時),我們可以立即返回一個 JavaScript Promise。 該對像是實際值的包裝器,表示“承諾”該值將在將來的某個時間可用。

例如,如果我們要使用 Promise 重寫我們的第一個代碼段,它看起來像這樣:

 const promise = wp.apiFetch( { url: 'https://server.com/wp-json/wp/v2/users/1', } ); promise.then( ( user ) => console.log( user ) );

如您所見, wp.apiFetch必須從服務器獲取用戶 1,但它會立即給出結果。 然而,結果不是用戶自己,而是一個承諾,一旦請求完成,就會解決給用戶。 因此,我們所要做的就是編寫一個回調來處理 promise 的響應,當它被解決時。

您現在可能會認為這與我們以前的相比並不難,對吧? 畢竟,我們仍在使用回調......但是一旦我們開始合併多個請求,您就會看到它的用處:

 const promise1 = wp.apiFetch( { url: 'https://server.com/wp-json/wp/v2/users/1', } ); const promise2 = wp.apiFetch( { url: 'https://server.com/wp-json/wp/v2/users/2', } ); Promise.all( [ promise1, promise2 ] ).then( ( [ user1, user2 ] ) => console.log( user1, user2 ); );

使用 Promise,我們能夠啟動兩個並行請求來檢索用戶 1 和 2,並使用Promise.all等待兩個 Promise 解決。 沒有涉及嵌套回調的意大利麵條代碼。

好吧,關於 promises 的偉大之處還沒有到來。 我們可以使用一些語法糖來處理 JavaScript Promise 並編寫看起來同步的異步代碼。 您所要做的就是使用async關鍵字定義一個異步函數,然後事情就變得簡單多了:

 async function logTwoUsers( id1, id2 ) { const user1 = await wp.apiFetch( { url: '…' + id1 } ); const user2 = await wp.apiFetch( { url: '…' + id2 } ); console.log( user1, user2 ); }

每當您在異步函數中調用異步操作時,都可以使用await關鍵字等待其結果。 你唯一應該記住的是,當你定義一個async函數時,它的結果將永遠是一個承諾:

 async function getNumberFive() { return 5; } const p = getNumberFive(); // a promise p.then( console.log ); // prints "5"

#4 使用letconst時的變量範圍

您可能已經知道,您現在可以使用letconst關鍵字聲明變量。 前者定義一個變量,後者定義一個常量:

 let x = 1; console.log( x ); // 1 x = 2; console.log( x ); // 2 const y = 1; console.log( y ); // 1 y = 2; // Uncaught TypeError: invalid assignment to const 'y' console.log( y ); // 1

你可能會認為letvar是同一個東西,因為這兩個關鍵字都允許我們聲明一個非常量變量。 但它們之間有一個實質性的區別:它們的範圍。 使用letconst ,變量的範圍是定義它的塊。 在var中,它是整個函數。

 function fn() { if ( true ) { var x = 1; let y = 2; const z = 3; }//end if console.log( x ); // 1 console.log( y ); // Uncaught ReferenceError: y is not defined console.log( z ); // Uncaught ReferenceError: z is not defined }

# 5 使用JSON.parse時的數據轉換

JSON.parse函數解析 JSON 字符串並構建 JavaScript 對象。 例如:

 const x = JSON.parse( '{"x":1,"a":[1,2,3]}' ); // Object { x: 1, a: [ 1, 2, 3 ] }

大多數人不知道的是它支持第二個參數,稱為reviver 。 該參數是一個函數,將為每個正在解析的元素執行,允許您隨意操作該值。 例如,想像一個 JSON 字符串,如下所示:

 const json = '{"name":"David","birthday":"1985-12-01T10:00:00.000Z"}';

如果我們按原樣使用JSON.parse ,它將生成一個具有兩個字符串屬性的對象: namebirthday 。 但是如果我們為JSON.parse提供一個reviver函數,我們可以確保birthday被解析為Date

 const user = JSON.parse( json, ( key, value ) => 'birthday' === key ? new Date( value ) : value )

# 6 源代碼中使用 Undesrcore 字符 ( _ ) 的數字分隔符

我們今天的最後一個技巧是數字分隔符。 有一個提案(目前處於第 4 階段),它可以以一種更易於人類理解的方式編寫數字。 例如,你真的能說出以下數字有多大嗎?

 10000000000 2189719.25

如果我們可以使用千位分隔符,它會更容易解釋! 這正是我們使用下劃線_可以做到的:

 10_000_000_000 2_189_719.25

概括

如果您習慣了 JavaScript 中包含的所有新工具和功能,則可以編寫更好的 JavaScript 代碼。 今天我們已經看到了幾個例子來說明這種編程語言的可能性。 我希望你學到了一些新東西,如果你喜歡它,別忘了與你的同事分享。 再見!

Sam Dan Truong 在 Unsplash 上的特色圖片。