1. 程式人生 > 程式設計 >你可能從未使用過的11+個JavaScript特性(小結)

你可能從未使用過的11+個JavaScript特性(小結)

重要

這篇文章中描述的大多數功能已被暫停使用(甚至不推薦使用)。 它們仍然在許多圖書中很常見,因此值得學習。

一、逗號運算子

,是用於分隔表示式並返回鏈中最後一個表示式的運算子。

let oo = (1,2,3)
console.log(oo) // 3

這裡有三個主要表示式 1 、 2 和 3。所有這些表示式均被求值,最後一個賦給 oo。

我們在 for 迴圈中看到這個:

for(let i = 0,ii = 1; i< 10; i++,ii--) { ... }

當我們要編寫短的 lambda 函式時,這會派上用場:

const lb = (a,b,arr) => (arr.push(a*b),a*b)

這裡有兩個語句,第一個將乘法結果推入陣列arr,第二個將乘數a和b推入陣列。 第二個結果就是返回給呼叫者的內容。

對於三元運算子,它也很有用,因為與短lambda語法相同,它僅接受表示式而不是語句。

二、in

in 是用於檢查物件中屬性是否存在的關鍵字。 我們在 for..in 迴圈中使用了它,但沒有意識到,其實 in 也是一個關鍵字:)
如果物件上存在屬性,則 in 將返回 true ,否則將返回 false。

const o = {
  prop: 1
}
console.log("prop" in o) // true

看,in 可以獨立使用,而不是在 for..in 中。

它將檢查 "prop" 是否可作為 o 物件中的屬性使用。 它返回 true ,因為我們在 o 中定義了 "prop" 屬性。

如果我們檢查未定義的屬性:

const o = {
  prop: 1
}
console.log("prop1" in o) // false

它返回 false ,因為 "prop1" 在 o 中未定義。

三、Array 建構函式

你知道我們可以不使用傳統方法定義陣列嗎?

const arr = [1,3]

怎麼樣?

我們也可以使用 Array :

const arr = new Array(1,3)

傳遞給 Array 建構函式的引數的排列將構成其索引的基礎。

1 是第一個引數,其索引為 0; 2 是第二個引數,其索引為 1; 3 是第三個引數,其索引為 2。

arr[0] // 1
arr[1] // 2
arr[2] // 3

所以,

const arr = new Array(1,3)


const arr = [1,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 建構函式定義 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","return a * b")

console.log(mul(7,8)) // 56

根據 MDN:

Function建構函式建立一個新的Function物件。直接呼叫此建構函式可用動態建立函式,但會遭遇來自eval的安全問題和相對較小的效能問題。然而,與 eval 不同的是,Function 建構函式只在全域性作用域中執行。

五、陣列解構

我們可以通過使用元素的索引號來分解陣列中的元素。

const arr = [1,3]

元素 1 、2 、3 的索引分別為 0、1、2,即:

arr[0] // 1

在日常開發中,我們最常使用的是物件解構:

let o = {
  prop: 1
}
o["prop"] // 1

// 解構
const {prop} = o
prop // 1

所以,我們將解構用於陣列上:

const arr = [1,3]
const { 0: firstA,1: secA,2: thirdA } = arr

firstA // 1
secA // 2
thirdA // 3

所以我們可以使用索引號來提取元素。索引是定義陣列中元素位置的屬性。

const arr = [1,3]

相當於:

const arr = {
  0: 1,1: 2,2: 3,length: 3
}

陣列也是物件,這就是為什麼要對其進行物件分解的原因,但是還有一種特殊的陣列分解語法:

const [first,second,third] = arr

first // 1
second // 2
third // 3

注意:應儘可能避免知道陣列中的特定位置資訊(開始、結束索引是什麼)。

六、使用 length 屬性減少陣列內容

陣列中的 length 屬性表示陣列中元素的數目。

const arr = [1,3]
arr.length // 3

減小 length 屬性值,會使 JS 引擎將陣列元素個數減少到與 length 屬性的值相等。

const arr = [1,3]
arr.length // 3
arr.length = 1
arr // [1]

arr 的 length 屬性值更改為 1,因此 arr 減少了元素個數,使其等於 length 屬性值。

如果增加 length 屬性,則 JS 引擎將新增元素(未定義的元素)以使陣列中的元素數量達到 length 屬性的值。

const arr = [1,3]
arr.length // 3
arr.length = 1
arr // [1]

arr.length = 5
arr // [1,empty × 4]

arr 中的元素只有一個,然後我們將長度增加到 5 ,因此又增加了 4 個元素長度,使元素數達到 5。

七、Arguments

我們可以使用 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

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

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支援我們。