這篇文章中描述的大多數功能已被暫停使用(甚至不推薦使用)。 它們仍然在許多圖書中很常見,所以值得學習。javascript
,
是用於分隔表達式並返回鏈中最後一個表達式的運算符。前端
let oo = (1, 2, 3) console.log(oo) // 3 複製代碼
這裏有三個主要表達式 1
、 2
和 3
。全部這些表達式均被求值,最後一個賦給 oo。java
咱們在 for 循環中看到這個:c++
for(let i = 0, ii = 1; i< 10; i++, ii--) { ... } 複製代碼
當咱們要編寫短的 lambda 函數時,這會派上用場:git
const lb = (a, b, arr) => (arr.push(a*b), a*b) 複製代碼
這裏有兩個語句,第一個將乘法結果推入數組arr,第二個將乘數a和b推入數組。 第二個結果就是返回給調用者的內容。github
對於三元運算符,它也頗有用,由於與短lambda語法相同,它僅接受表達式而不是語句。編程
in 是用於檢查對象中屬性是否存在的關鍵字。 咱們在 for..in
循環中使用了它,但沒有意識到,其實 in
也是一個關鍵字:)數組
若是對象上存在屬性,則 in
將返回 true
,不然將返回 false
。安全
const o = { prop: 1 } console.log("prop" in o) // true 複製代碼
看,in
能夠獨立使用,而不是在 for..in
中。markdown
它將檢查 "prop"
是否可做爲 o
對象中的屬性使用。 它返回 true
,由於咱們在 o
中定義了 "prop"
屬性。
若是咱們檢查未定義的屬性:
const o = { prop: 1 } console.log("prop1" in o) // false 複製代碼
它返回 false
,由於 "prop1"
在 o
中未定義。
你知道咱們能夠不使用傳統方法定義數組嗎?
const arr = [1, 2, 3] 複製代碼
怎麼樣?
咱們也可使用 Array
:
const arr = new Array(1, 2, 3) 複製代碼
傳遞給 Array
構造函數的參數的排列將構成其索引的基礎。
1
是第一個參數,其索引爲 0; 2
是第二個參數,其索引爲 1; 3
是第三個參數,其索引爲 2。
arr[0] // 1 arr[1] // 2 arr[2] // 3 複製代碼
因此,
const arr = new Array(1, 2, 3) 複製代碼
和
const arr = [1, 2, 3] 複製代碼
表達的是一個意思。
但使用 new Array()
有一個問題,例如:
var a = new Array(10, 20); a[0] // 返回 10 a.length // 返回 2 複製代碼
但:
var a = new Array(10); a[0] // 返回 undefined a.length // 返回 10 複製代碼
當你僅給 Array
構造函數一個整數(大於等於 0 的整數,不然將會報錯)時,纔會發生這種狀況。 這是爲何喃?
其實,新的 Array
構造函數正在從某些編程語言中提取思想,在這些語言中,你須要爲數組指定內存,這樣就不會出現 ArrayIndexOutOfBounds
異常。
int *a = (int *) malloc( 10*sizeof(int) ); // ya ol' c int *a = new int[10]; // c++ int[] a = new int[10]; // java 複製代碼
是的,它其實是在建立一個長度爲 10
的數組。咱們在 Javascript
中沒有 sizeof
函數,可是 toString
足以證實這一點。
a.toString() // 返回 ",,,,,,,,," 它至關於 [,,,,,,,,,] a // [empty × 10] 複製代碼
因此,當將一個參數傳遞給的 new Array
,將致使 JS 引擎爲傳遞的參數大小的數組分配空間。
而且這也在 EcmaScript 規範中:
看,這不是矛盾的。 規格中都有全部描述。 在得出任何結論以前,咱們應該始終先閱讀任何語言的規範。
你是否知道咱們可使用 Function
構造函數定義 Function
。
你不明白吧? 讓我更清楚。 在 JavaScript 中,咱們定義以下函數:
const mul = (a, b) => a * b // 或 function mul(a, b) { return a * b } // 或 const mul = function(a, b) { return a * b } 複製代碼
咱們也能夠這樣作,來實現相同的功能:
const mul = new Function("a", "b", "return a * b") 複製代碼
傳遞給 Function
的參數造成函數的參數和主體。 變量 mul
成爲函數名稱。
而且,最後一個參數將是函數的主體,而最後一個參數以前的參數將成爲函數的參數。
在在 mul
中。 "a"
和 "b"
是函數將接收的參數,"return a * b"
是函數的主體。 它實現將 "a"
和 "b"
相乘並返回結果。
咱們使用 mul(…)
調用該函數,並傳入參數:
const mul = new Function("a", "b", "return a * b") console.log(mul(7, 8)) // 56 複製代碼
根據 MDN:
Function 構造函數建立一個新的
Function
對象。直接調用此構造函數可用動態建立函數,但會遭遇來自eval
的安全問題和相對較小的性能問題。然而,與 eval 不一樣的是,Function 構造函數只在全局做用域中運行。
咱們能夠經過使用元素的索引號來分解數組中的元素。
const arr = [1, 2, 3] 複製代碼
元素 1
、2
、3
的索引分別爲 0、一、2,即:
arr[0] // 1 複製代碼
在平常開發中,咱們最常使用的是對象解構:
let o = { prop: 1 } o["prop"] // 1 // 解構 const {prop} = o prop // 1 複製代碼
因此,咱們將解構用於數組上:
const arr = [1, 2, 3] const { 0: firstA, 1: secA, 2: thirdA } = arr firstA // 1 secA // 2 thirdA // 3 複製代碼
因此咱們可使用索引號來提取元素。索引是定義數組中元素位置的屬性。
const arr = [1, 2, 3] 複製代碼
至關於:
const arr = { 0: 1, 1: 2, 2: 3, length: 3 } 複製代碼
數組也是對象,這就是爲何要對其進行對象分解的緣由,可是還有一種特殊的數組分解語法:
const [first, second, third] = arr first // 1 second // 2 third // 3 複製代碼
注意:應儘量避免知道數組中的特定位置信息(開始、結束索引是什麼)。
數組中的 length
屬性表示數組中元素的數目。
const arr = [1, 2, 3] arr.length // 3 複製代碼
減少 length
屬性值,會使 JS
引擎將數組元素個數減小到與 length
屬性的值相等。
const arr = [1, 2, 3] arr.length // 3 arr.length = 1 arr // [1] 複製代碼
arr
的 length
屬性值更改成 1
,所以 arr
減小了元素個數,使其等於 length
屬性值。
若是增長 length
屬性,則 JS
引擎將添加元素(未定義的元素)以使數組中的元素數量達到 length
屬性的值。
const arr = [1, 2, 3] arr.length // 3 arr.length = 1 arr // [1] arr.length = 5 arr // [1, empty × 4] 複製代碼
arr
中的元素只有一個,而後咱們將長度增長到 5 ,所以又增長了 4 個元素長度,使元素數達到 5。
咱們可使用 arguments
對象獲取傳遞給函數的參數,而無需在函數中明肯定義 arguments
變量:
function myFunc() { console.log(arguments[0]) // 34 console.log(arguments[1]) // 89 } myFunc(34,89) 複製代碼
arguments
對象是數組索引的。 也就是說,屬性是數字,所以能夠經過鍵引用進行訪問。
arguments
對象是從 Arguments
類實例化的,該類具備一些很酷的屬性。
arguments.callee.name
指當前正在調用的函數的名稱。
function myFunc() { console.log(arguments.callee.name) // myFunc } myFunc(34, 89) 複製代碼
arguments.callee.caller.name
是指調用當前執行函數的函數的名稱。
function myFunc() { console.log(arguments.callee.name) // myFunc console.log(arguments.callee.caller.name) // myFuncCallee } (function myFuncCallee() { myFunc(34, 89) })() 複製代碼
這在可變參數功能中特別有用。
你是否知道實例化對象時能夠跳過方括號 ()
?
例如:
class D { logger() { console.log("D") } } // 通常狀況下,咱們這麼作: (new D()).logger(); // D // 其實,咱們能夠跳過 (): (new D).logger(); // D // 而且它能夠正常運行 複製代碼
即便在內置類中,括號也是可選的:
(new Date).getDay(); (new Date).getMonth(); (new Date).getYear(); 複製代碼
void
是 JS 中的關鍵字,用於評估語句並返回未定義。
例如:
class D { logger() { return 89 } } const d = new D console.log(void d.logger()) // undefined 複製代碼
logger
方法應該返回 89
,可是 void
關鍵字將使其無效並返回 undefined
。
我曾經讀到過 undefined
以前可能會被賦予另外一個值,而這會僞造其語義。 所以,使用 void
運算符可確保你獲得一個真正的 undefined
。 也用於最小化目的。
__proto__
繼承_proto_
是從 JavaScript
中的對象繼承屬性的方法。 __proto__
是 Object.prototype
的訪問器屬性,它公開訪問對象的 [[Prototype]]
。
此 __proto__
將其 [[Prototype]]
中設置的對象的全部屬性設置爲目標對象。
讓咱們看一個例子:
const l = console.log const obj = { method: function() { l("method in obj") } } const obj2 = {} obj2.__proto__ = obj obj2.method() // method in obj 複製代碼
咱們有兩個對象常量: obj
和 obj2
。 obj
具備 method
屬性。 obj2
是一個空的對象常量,即它沒有屬性。
咱們訪問 obj2
的 __proto__
並將其設置爲 obj
。 這會將經過 Object.prototype
可訪問的 obj
的全部屬性複製到 obj2
。 這就是爲何咱們能夠在 obj2
上調用方法而不會在沒有定義的狀況下獲得錯誤的緣由。
obj2
繼承了 obj
的屬性,所以 method
方法屬性將在其屬性中可用。
原型可用於對象,例如對象常量、對象、數組、函數、日期、RegEx、數字、布爾值、字符串。
一元 +
運算符將其操做數轉換爲數字類型。
+"23" // 23 +{} // NaN +null // 0 +undefined // NaN +{ valueOf: () => 67 } // 67 +"nnamdi45" // NaN 複製代碼
當咱們但願將變量快速轉換爲 Number
時,這很是方便。
一元運算符 -
將其操做數轉換爲 Number
類型,而後取反。
該運算符將一元 +
運算符的結果取反。 首先,它將操做數轉換爲其 Number
值,而後取反該值。
-"23" // -23 複製代碼
此處發生的是,字符串 "23"
將轉換爲其數字類型,從而獲得 23
。而後,此正數將轉換爲其負數形式 -23
。
-{} // NaN -null // -0 -undefined // NaN -{ valueOf: () => 67 } // -67 -"nnamdi45" // NaN 複製代碼
若是轉換爲數值的結果爲 NaN
,則不會應用取反。
取負 +0
產生 -0
,取負 -0
產生 +0
。
- +0 // -0 - -0 // 0 複製代碼
該運算符用於指定數字的指數。
在數學中, 2^3^ 意味着將 2 乘以三次:
2 * 2 * 2 複製代碼
咱們可使用 **
運算符在 JS 中進行相同的操做:
2 ** 3 // 8 9 ** 3 // 729 複製代碼
本文翻譯自 11+ JavaScript Features You’ve Probably Never Used
想看往期更過系列文章,點擊前往 github 博客主頁
❤️玩得開心,不斷學習,並始終保持編碼。👨💻
若有任何問題或更獨特的看法,歡迎評論或直接聯繫瓶子君(公衆號回覆 123 便可)!👀👇
👇歡迎關注:前端瓶子君,每日更新!👇