Array.prototype.slice() - JavaScript

Array.prototype.slice()
=======================

**`slice()`** 方法會回傳一個新陣列物件，為原陣列選擇之 `begin` 至 `end`（不含 `end`）部分的淺拷貝（shallow copy）。而原本的陣列將不會被修改。

嘗試一下
----

語法
--

```js
arr.slice([begin[, end]])
```

### 參數

`begin` 選擇性

自哪一個索引（起始為 0）開始提取拷貝。可使用負數索引，表示由陣列的最末項開始提取。`slice(-2)` 代表拷貝陣列中的最後兩個元素。假如 `begin` 為 undefined，則 `slice` 會從索引 `0` 開始提取。

`end` 選擇性

至哪一個索引（起始為 0）*之前*停止提取。`slice` 提取但不包含至索引 `end`。舉例來說，`slice(1,4)` 提取了陣列中第二個元素至第四個元素前為止（元素索引 1、2 以及 3）來拷貝。可使用負數索引，表示由陣列的最末項開始提取。`slice(2,-1)` 代表拷貝陣列中第三個元素至倒數第二個元素。若省略了 `end`，則 `slice` 會提取至陣列的最後一個元素（`arr.length`）。假如 `end` 大於陣列的長度，`slice` 會提取至陣列的最後一個元素（`arr.length`）。

### 回傳值

一個包含提取之元素的新陣列。

說明
--

`slice` 不會修改原本的陣列，而是回傳由原本的陣列淺層複製的元素。原始陣列的元素會按照下列規則拷貝：

* 如果該元素是個對象引用（不是實際的對象），`slice` 會拷貝這個對象引用到新的陣列內。兩個對象引用都引用了同一個對象。如果被引用的對象發生改變，則新的和原來的陣列中的這個元素也會發生改變。
* 對於字串、數字、布林來說 (不是 `String`、`Number` 或者 `Boolean` 對象), `slice` 會拷貝這些值到新的陣列內。在別的陣列內修改這些字串、數字或是布林，將不會影響另一個陣列。

如果添加了新的元素到另一個陣列內，則另一個不會受到影響。

範例
--

### Return a portion of an existing array

```js
var fruits = ["Banana", "Orange", "Lemon", "Apple", "Mango"];
var citrus = fruits.slice(1, 3);

// fruits contains ['Banana', 'Orange', 'Lemon', 'Apple', 'Mango']
// citrus contains ['Orange','Lemon']
```

### Using `slice`

In the following example, `slice` creates a new array, `newCar`, from `myCar`. Both include a reference to the object `myHonda`. When the color of `myHonda` is changed to purple, both arrays reflect the change.

```js
// Using slice, create newCar from myCar.
var myHonda = { color: "red", wheels: 4, engine: { cylinders: 4, size: 2.2 } };
var myCar = [myHonda, 2, "cherry condition", "purchased 1997"];
var newCar = myCar.slice(0, 2);

// Display the values of myCar, newCar, and the color of myHonda
// referenced from both arrays.
console.log("myCar = " + JSON.stringify(myCar));
console.log("newCar = " + JSON.stringify(newCar));
console.log("myCar[0].color = " + myCar[0].color);
console.log("newCar[0].color = " + newCar[0].color);

// Change the color of myHonda.
myHonda.color = "purple";
console.log("The new color of my Honda is " + myHonda.color);

// Display the color of myHonda referenced from both arrays.
console.log("myCar[0].color = " + myCar[0].color);
console.log("newCar[0].color = " + newCar[0].color);
```

This script writes:

```js
myCar = [{color: 'red', wheels: 4, engine: {cylinders: 4, size: 2.2}}, 2,
         'cherry condition', 'purchased 1997']
newCar = [{color: 'red', wheels: 4, engine: {cylinders: 4, size: 2.2}}, 2]
myCar[0].color = red
newCar[0].color = red
The new color of my Honda is purple
myCar[0].color = purple
newCar[0].color = purple
```

類陣例（Array-like）物件
-----------------

`slice` method can also be called to convert Array-like objects / collections to a new Array. You just bind the method to the object. The `arguments` (en-US) inside a function is an example of an 'array-like object'.

```js
function list() {
  return Array.prototype.slice.call(arguments);
}

var list1 = list(1, 2, 3); // [1, 2, 3]
```

Binding can be done with the .`call` function of `Function.prototype` (en-US) and it can also be reduced using `[].slice.call(arguments)` instead of `Array.prototype.slice.call`. Anyway, it can be simplified using `bind`.

```js
var unboundSlice = Array.prototype.slice;
var slice = Function.prototype.call.bind(unboundSlice);

function list() {
  return slice(arguments);
}

var list1 = list(1, 2, 3); // [1, 2, 3]
```

Streamlining cross-browser behavior
-----------------------------------

Although host objects (such as DOM objects) are not required by spec to follow the Mozilla behavior when converted by `Array.prototype.slice` and IE < 9 does not do so, versions of IE starting with version 9 do allow this. 「Shimming」 it can allow reliable cross-browser behavior. As long as other modern browsers continue to support this ability, as currently do IE, Mozilla, Chrome, Safari, and Opera, developers reading (DOM-supporting) slice code relying on this shim will not be misled by the semantics; they can safely rely on the semantics to provide the now apparently *de facto* standard behavior. (The shim also fixes IE to work with the second argument of `slice()` being an explicit `null` (en-US)/`undefined` (en-US) value as earlier versions of IE also did not allow but all modern browsers, including IE >= 9, now do.)

```js
/\*\*
 \* Shim for "fixing" IE's lack of support (IE < 9) for applying slice
 \* on host objects like NamedNodeMap, NodeList, and HTMLCollection
 \* (technically, since host objects have been implementation-dependent,
 \* at least before ES2015, IE hasn't needed to work this way).
 \* Also works on strings, fixes IE < 9 to allow an explicit undefined
 \* for the 2nd argument (as in Firefox), and prevents errors when
 \* called on other DOM objects.
 \*/
(function () {
  "use strict";
  var _slice = Array.prototype.slice;

  try {
    // Can't be used with DOM elements in IE < 9
    \_slice.call(document.documentElement);
  } catch (e) {
    // Fails in IE < 9
    // This will work for genuine arrays, array-like objects,
    // NamedNodeMap (attributes, entities, notations),
    // NodeList (e.g., getElementsByTagName), HTMLCollection (e.g., childNodes),
    // and will not fail on other DOM objects (as do DOM elements in IE < 9)
    Array.prototype.slice = function (begin, end) {
      // IE < 9 gets unhappy with an undefined end argument
      end = typeof end !== "undefined" ? end : this.length;

      // For native Array objects, we use the native slice function
      if (Object.prototype.toString.call(this) === "[object Array]") {
        return \_slice.call(this, begin, end);
      }

      // For array like object we handle it ourselves.
      var i,
        cloned = [],
        size,
        len = this.length;

      // Handle negative value for "begin"
      var start = begin || 0;
      start = start >= 0 ? start : Math.max(0, len + start);

      // Handle negative value for "end"
      var upTo = typeof end == "number" ? Math.min(end, len) : len;
      if (end < 0) {
        upTo = len + end;
      }

      // Actual expected size of the slice
      size = upTo - start;

      if (size > 0) {
        cloned = new Array(size);
        if (this.charAt) {
          for (i = 0; i < size; i++) {
            cloned[i] = this.charAt(start + i);
          }
        } else {
          for (i = 0; i < size; i++) {
            cloned[i] = this[start + i];
          }
        }
      }

      return cloned;
    };
  }
})();
```

規範
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-array.prototype.slice |

瀏覽器相容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

參見
--

* `Array.prototype.splice()`
* `Function.prototype.call()`
* `Function.prototype.bind()`


Array.of() - JavaScript

Array.of()
==========

**`Array.of()`** 方法會由引數（arguments）的數量來建立一個新的 `Array` 實體，而不管引數的數量或類型為何。

**`Array.of()`** 與 **`Array`** 建構式之間的不同在於如何處理整數引數：**`Array.of(7)`** 會建立一個擁有單個元素—`7`—的陣列，而 **`Array(7)`** 會建立一個 `length` 屬性值為 7 的空陣列（\*\*註：\*\*這意味著這個陣列有 7 個空缺欄位（empty slots），而非 7 個值為 `undefined` 的欄位）。

嘗試一下
----

語法
--

```js
Array.of(element0)
Array.of(element0, element1)
Array.of(element0, element1, /\* … ,\*/ elementN)
```

### 參數

`elementN`

要用來成為新建立之陣列的元素。

### 回傳值

一個新的 `Array` 實體。

描述
--

此函式是 ECMAScript 2015 標準的一部分。更多資訊可參考 `Array.of` and `Array.from` proposal 以及 `Array.of` polyfill。

範例
--

### 使用 Array.of()

```js
Array.of(1); // [1]
Array.of(1, 2, 3); // [1, 2, 3]
Array.of(undefined); // [undefined]
```

### 在非陣列建構中使用 of()

可以在接受表示新陣列長度的單個參數的任何建構式上調用 `of()` 方法。

```js
function NotArray(len) {
  console.log("NotArray called with length", len);
}

console.log(Array.of.call(NotArray, 1, 2, 3));
// NotArray called with length 3
// NotArray { '0': 1, '1': 2, '2': 3, length: 3 }

console.log(Array.of.call(Object)); // [Number: 0] { length: 0 }
```

When the `this` value is not a constructor, a plain `Array` object is returned.

```js
console.log(Array.of.call({}, 1)); // [ 1 ]
```

Polyfill
--------

若所有執行環境沒有原生支援，可以在其他程式之前先執行以下程式碼來建立 `Array.of()`。

```js
if (!Array.of) {
  Array.of = function () {
    return Array.prototype.slice.call(arguments);
  };
}
```

規範
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-array.of |

瀏覽器相容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

參見
--

* Polyfill of `Array.of` in `core-js`
* `Array()` (en-US)
* `Array.from()`
* `TypedArray.of()` (en-US)


Array.prototype.flat() - JavaScript

Array.prototype.flat()
======================

Baseline Widely available
-------------------------

This feature is well established and works across many devices and browser versions. It’s been available across browsers since January 2020.

* Learn more
* See full compatibility
* Report feedback
**實驗性質:** **這是一個實驗中的功能 (en-US)**
此功能在某些瀏覽器尚在開發中，請參考兼容表格以得到不同瀏覽器用的前輟。

**`flat()`** 函數以遞迴方式將特定深度的子陣列重新串接成為一新的陣列

嘗試一下
----

語法
--

```js
var newArray = arr.flat([depth]);
```

### 參數

`depth` 選擇性

指定巢狀陣列展開的深度。預設為 1。

### 回傳值

函數將會回傳一個由原先陣列的子陣列串接而成的新陣列。

範例
--

### 展開巢狀陣列

```js
var arr1 = [1, 2, [3, 4]];
arr1.flat();
// [1, 2, 3, 4]

var arr2 = [1, 2, [3, 4, [5, 6]]];
arr2.flat();
// [1, 2, 3, 4, [5, 6]]

var arr3 = [1, 2, [3, 4, [5, 6]]];
arr3.flat(2);
// [1, 2, 3, 4, 5, 6]
```

### 當遭遇空元素時

`flat()` 函數會自動清除陣列中空的元素

```js
var arr4 = [1, 2, , 4, 5];
arr4.flat();
// [1, 2, 4, 5]
```

替代方案
----

### `reduce` 與 `concat`

```js
var arr1 = [1, 2, [3, 4]];
arr1.flat();

//展開單層陣列
arr1.reduce((acc, val) => acc.concat(val), []); // [1, 2, 3, 4]
```

```js
//欲展開更深層的巢狀結構請使用reduce與concat的遞迴
function flattenDeep(arr1) {
  return arr1.reduce(
    (acc, val) =>
      Array.isArray(val) ? acc.concat(flattenDeep(val)) : acc.concat(val),
    [],
  );
}
flattenDeep(arr1); // [1, 2, 3, 1, 2, 3, 4, 2, 3, 4]
```

```js
//使用stack來實作非遞迴的展開
var arr1 = [1, 2, 3, [1, 2, 3, 4, [2, 3, 4]]];
function flatten(input) {
  const stack = [...input];
  const res = [];
  while (stack.length) {
    // pop value from stack
    const next = stack.pop();
    if (Array.isArray(next)) {
      // push back array items, won't modify the original input
      stack.push(...next);
    } else {
      res.push(next);
    }
  }
  //reverse to restore input order
  return res.reverse();
}
flatten(arr1); // [1, 2, 3, 1, 2, 3, 4, 2, 3, 4]
```

```js
// 递归版本的反嵌套
function flatten(array) {
  var flattend = [];
  (function flat(array) {
    array.forEach(function (el) {
      if (Array.isArray(el)) flat(el);
      else flattend.push(el);
    });
  })(array);
  return flattend;
}
```

規範
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-array.prototype.flat |

瀏覽器相容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

參見
--

* `Array.prototype.flatMap()` (en-US)
* `Array.prototype.map()`
* `Array.prototype.reduce()`
* `Array.prototype.concat()`


Array.length - JavaScript

Array.length
============

**`length`** 為 `Array` 物件的屬性，可供設定或回傳該陣列實體中包含的元素個數。其值必為一大於零、32 位元、且恆大於該陣列最大索引數的正整數。

```js
var items = ["shoes", "shirts", "socks", "sweaters"];
items.length;

// returns 4
```

描述
--

`length` 屬性的值必為一正整數，其值必介於 0 ～ 2^32 (不包含)之間.

```js
var namelistA = new Array(4294967296); //2^32 = 4294967296
var namelistC = new Array(-100); //負數

console.log(namelistA.length); //RangeError: Invalid array length
console.log(namelistC.length); //RangeError: Invalid array length

var namelistB = [];
namelistB.length = Math.pow(2, 32) - 1; //將長度設定介於 0 ~ 2^32 -1
console.log(namelistB.length);

//4294967295
```

你可以透過改變 `length` 屬性來改變陣列的長度。當你透過 `length` 屬性來增加陣列的長度時，陣列中實際的元素也會隨之增加。舉例來說，當你將 array.length 由 2 增加為 3，則改動後該陣列即擁有 3 個元素，該新增的元素則會是一個不可迭代(non-iterable)的空槽(empty slot)。
```

const arr = [1, 2];
console.log(arr);
// [ 1, 2 ]

arr.length = 5; // 將arr的length由2改成5
console.log(arr);
// [ 1, 2, <3 empty items> ]

arr.forEach(element => console.log(element)); // 空元素無法被迭代
// 1
// 2
```

如上所見，`length` 屬性不盡然代表陣列中所有已定義的元素個數。詳見 length 與數值屬性的關係。

| `Array.length` 的屬性特性 |
| --- |
| 可寫 | 是 |
| 可列舉 | 否 |
| 可配置 | 否 |

* `Writable`: 如果此屬性值為`false`，則該屬性的內容值無法被改動。
* `Configurable`: 如果此屬性值為`false`，任何刪除屬性或更改其屬性的操作(`Writable`, `Configurable`, or `Enumerable`)皆會失敗。
* `Enumerable`: 如果此屬性值為`true`，該內容值可倍 for 或 for..in 迴圈迭代處理。
範例
--

### 對陣列進行迭代處理

以下範例中, 陣列 `numbers` 透過 `length` 屬性進行迭代操作，並將其內容值加倍。

```js
var numbers = [1, 2, 3, 4, 5];
var length = numbers.length;
for (var i = 0; i < length; i++) {
  numbers[i] \*= 2;
}
// numbers 內容值變為 [2, 4, 6, 8, 10]
```

### 縮減陣列

以下範例中, 陣列 `numbers` 的長度若大於 3，則將其長度縮減至 3。

```js
var numbers = [1, 2, 3, 4, 5];

if (numbers.length > 3) {
  numbers.length = 3;
}

console.log(numbers); // [1, 2, 3]
console.log(numbers.length); // 3
```

規範
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-properties-of-array-instances-length |

瀏覽器相容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

參見
--

* `Array`


Array.prototype.values() - JavaScript

Array.prototype.values()
========================

**`values()`** 方法會回傳一個包含陣列中的每一個索引之對應值（value）的新 **`Array Iterator`** 物件。

```js
var a = ["w", "y", "k", "o", "p"];
var iterator = a.values();

console.log(iterator.next().value); // w
console.log(iterator.next().value); // y
console.log(iterator.next().value); // k
console.log(iterator.next().value); // o
console.log(iterator.next().value); // p
```

語法
--

```js
arr.values()
```

### 回傳值

一個新的 `Array` 迭代器（iterator）物件。

範例
--

### 使用 for...of 迴圈進行迭代

```js
var arr = ["w", "y", "k", "o", "p"];
var iterator = arr.values();

for (let letter of iterator) {
  console.log(letter);
}
```

規範
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-array.prototype.values |

瀏覽器相容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

參見
--

* `Array.prototype.keys()`
* `Array.prototype.entries()`
* `Array.prototype.forEach()` (en-US)
* `Array.prototype.every()` (en-US)
* `Array.prototype.some()` (en-US)


Array.prototype.filter() - JavaScript

Array.prototype.filter()
========================

**`filter()`** 方法會建立一個經指定之函式運算後，由原陣列中通過該函式檢驗之元素所構成的新陣列。

嘗試一下
----

### ES6 版本

```js
const words = [
  "spray",
  "limit",
  "elite",
  "exuberant",
  "destruction",
  "present",
  "happy",
];

let longWords = words.filter((word) => word.length > 6);

// Filtered array longWords is ["exuberant", "destruction", "present"]
```

語法
--
```

var newArray = arr.filter(callback(element[, index[, array]])[, thisArg])
```

### 參數

`callback`

此函式為一個斷言，用於測試陣列中的每個元素。回傳值為 `true` 時將當前的元素保留至新陣列中，若為 `false` 則不保留。可傳入三個參數：

`element`

原陣列目前所迭代處理中的元素。

`index`選擇性

原陣列目前所迭代處理中的元素之索引。

`array`選擇性

呼叫 `filter` 方法的陣列。

`thisArg` 選擇性

可選的。執行 `callback` 回呼函式的 `this` 值。

### 回傳值

一個元素為通過回呼函式檢驗的新陣列。

描述
--

`filter()` 會將所有陣列中的元素分別傳入一次至 `callback` 函式當中，並將所有傳入此回呼函式並得到回傳值為 Truthy (en-US) 的元素建構成一個新的陣列。`callback` 函式只會於陣列目前迭代之索引有指派值時被呼叫，回呼函式不會在該陣列索引已被刪除或從未被賦值時被調用。原始陣列中沒有通過 `callback` 檢驗的元素會被簡單的跳過，且不會被包含在新建立的陣列中。

`callback` 函式於被調用時會傳入三個參數：

1. 元素值
2. 元素之索引
3. 被迭代的陣列物件

若有提供 `thisArg` 參數予 `filter` 方法，`thisArg` 將會被當作回呼函式的 `this` 值，否則 `this` 會是 `undefined`。`callback` 的最終 `this` 值是依據函式的 `this` 規則來決定。

`filter()` 不會修改呼叫它的原始陣列。

由 `filter()` 方法所回傳之新陣列的範圍，於 `callback` 函式第一次被調用之前就已經被設定。而在呼叫 `filter()` 之後才加至原始陣列中的元素，將不會傳入 `callback` 當中。假如原始陣列中元素的值改變或被刪除了，則 `callback` 得到此元素的值將會是 `filter()` 傳入元素當下的值。而被刪除的原始陣列元素並不會被迭代到。

範例
--

### 過濾所有的小數字

以下範例會用 `filter()` 建立一個把所有小於 10 的元素都移掉的陣列。

```js
function isBigEnough(value) {
  return value >= 10;
}

var filtered = [12, 5, 8, 130, 44].filter(isBigEnough);
// filtered is [12, 130, 44]
```

### 從 JSON 過濾無效的項目

以下範例會用 `filter()` 建立一個把非零 numeric `id` 的元素都過濾掉的的 JSON。

```js
var arr = [
  { id: 15 },
  { id: -1 },
  { id: 0 },
  { id: 3 },
  { id: 12.2 },
  {},
  { id: null },
  { id: NaN },
  { id: "undefined" },
];

var invalidEntries = 0;

function isNumber(obj) {
  return obj !== undefined && typeof obj === "number" && !isNaN(obj);
}

function filterByID(item) {
  if (isNumber(item.id)) {
    return true;
  }
  invalidEntries++;
  return false;
}

var arrByID = arr.filter(filterByID);

console.log("過濾好的陣列\n", arrByID);
// 過濾好的陣列
// [{ id: 15 }, { id: -1 }, { id: 0 }, { id: 3 }, { id: 12.2 }]

console.log("無效的元素數量 = ", invalidEntries);
// 無效的元素數量 = 4
```

### 在陣列中搜尋

下面範例使用 `filter()` 去過濾符合搜尋條件的陣列內容。

```js
var fruits = ["apple", "banana", "grapes", "mango", "orange"];

/\*\*
 \* 陣列透過搜尋條件（查詢）過濾物件
 \*/
function filterItems(query) {
  return fruits.filter(function (el) {
    return el.toLowerCase().indexOf(query.toLowerCase()) > -1;
  });
}

console.log(filterItems("ap")); // ['apple', 'grapes']
console.log(filterItems("an")); // ['banana', 'mango', 'orange']
```

### ES2015 實作方式

```js
const fruits = ["apple", "banana", "grapes", "mango", "orange"];

/\*\*
 \* 陣列透過搜尋條件（查詢）過濾物件
 \*/
const filterItems = (query) => {
  return fruits.filter(
    (el) => el.toLowerCase().indexOf(query.toLowerCase()) > -1,
  );
};

console.log(filterItems("ap")); // ['apple', 'grapes']
console.log(filterItems("an")); // ['banana', 'mango', 'orange']
```

Polyfill
--------

`filter()` 在 ECMA-262 第五版時被納入標準；它也許不會出現在該標準的所有實作引擎之中。你可以在你的腳本最前面加入下面的程式碼作為替代方案，讓不支援 `filter()` 的 ECMA-262 實作引擎能夠使用它。假設 `fn.call` 是採用 `Function.prototype.bind()` 的原始值，這個演算法完全和 ECMA-262 第五版定義的規格相同。

```js
if (!Array.prototype.filter)
  Array.prototype.filter = function (func, thisArg) {
    "use strict";
    if (!(typeof func === "Function" && this)) throw new TypeError();

    var len = this.length >>> 0,
      res = new Array(len), // 預先配置陣列
      c = 0,
      i = -1;
    if (thisArg === undefined)
      while (++i !== len)
        // 確認物件的鍵值i是否有被設置
        if (i in this)
          if (func(t[i], i, t)) res[c++] = t[i];
          else
            while (++i !== len)
              // 確認物件的鍵值i是否有被設置
              if (i in this)
                if (func.call(thisArg, t[i], i, t)) res[c++] = t[i];

    res.length = c; // 將陣列縮至適當大小
    return res;
  };
```

規範
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-array.prototype.filter |

瀏覽器相容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

參見
--

* `Array.prototype.forEach()` (en-US)
* `Array.prototype.every()` (en-US)
* `Array.prototype.some()` (en-US)
* `Array.prototype.reduce()`


Array.prototype.lastIndexOf() - JavaScript

Array.prototype.lastIndexOf()
=============================

**`lastIndexOf()`** 方法會回傳給定元素於陣列中最後一個被找到之索引，若不存在於陣列中則回傳 -1。搜尋的方向為由陣列尾部向後（即向前）尋找，啟始於 `fromIndex`。

嘗試一下
----

語法
--
```

arr.lastIndexOf(searchElement)
arr.lastIndexOf(searchElement, fromIndex)
```

### 參數

`searchElement`

欲在陣列中搜尋的元素。

`fromIndex` 選擇性

要由陣列尾部向後（即向前）搜尋的啟始索引。預設為陣列長度減一（`arr.length - 1`），即會搜尋整個陣列。假如索引大於等於陣列長度，會搜尋整個陣列。如果索引值為負數，會從陣列的最後一個往回算，最後一個的索引值為 -1，以此類推。注意：儘管往回算，但依然會從右往左全部搜尋。如果負數索引值在回頭計算之後仍然小於 0，將會回傳 -1，即不會搜尋陣列。

### 回傳值

在陣列中找到的最後一個元素索引值；沒找到則為 **-1**。

描述
--

`lastIndexOf` compares `searchElement` to elements of the Array using strict equality (en-US) (the same method used by the ===, or triple-equals, operator).

範例
--

### 使用 `lastIndexOf`

The following example uses `lastIndexOf` to locate values in an array.

```js
var numbers = [2, 5, 9, 2];
numbers.lastIndexOf(2); // 3
numbers.lastIndexOf(7); // -1
numbers.lastIndexOf(2, 3); // 3
numbers.lastIndexOf(2, 2); // 0
numbers.lastIndexOf(2, -2); // 0
numbers.lastIndexOf(2, -1); // 3
```

### 尋找該元素所有出現在陣列中的位置

The following example uses `lastIndexOf` to find all the indices of an element in a given array, using `push` to add them to another array as they are found.

```js
var indices = [];
var array = ["a", "b", "a", "c", "a", "d"];
var element = "a";
var idx = array.lastIndexOf(element);
while (idx != -1) {
  indices.push(idx);
  idx = idx > 0 ? array.lastIndexOf(element, idx - 1) : -1;
}

console.log(indices);
// [4, 2, 0]
```

Note that we have to handle the case `idx == 0` separately here because the element will always be found regardless of the `fromIndex` parameter if it is the first element of the array. This is different from the `indexOf` method.

Polyfill
--------

`lastIndexOf` was added to the ECMA-262 standard in the 5th edition; as such it may not be present in other implementations of the standard. You can work around this by inserting the following code at the beginning of your scripts, allowing use of `lastIndexOf` in implementations which do not natively support it. This algorithm is exactly the one specified in ECMA-262, 5th edition, assuming `Object` (en-US), `TypeError` (en-US), `Number`, `Math.floor`, `Math.abs` (en-US), and `Math.min` (en-US) have their original values.

```js
// Production steps of ECMA-262, Edition 5, 15.4.4.15
// Reference: http://es5.github.io/#x15.4.4.15
if (!Array.prototype.lastIndexOf) {
  Array.prototype.lastIndexOf = function (searchElement /\*, fromIndex\*/) {
    "use strict";

    if (this === void 0 || this === null) {
      throw new TypeError();
    }

    var n,
      k,
      t = Object(this),
      len = t.length >>> 0;
    if (len === 0) {
      return -1;
    }

    n = len - 1;
    if (arguments.length > 1) {
      n = Number(arguments[1]);
      if (n != n) {
        n = 0;
      } else if (n != 0 && n != 1 / 0 && n != -(1 / 0)) {
        n = (n > 0 || -1) \* Math.floor(Math.abs(n));
      }
    }

    for (k = n >= 0 ? Math.min(n, len - 1) : len - Math.abs(n); k >= 0; k--) {
      if (k in t && t[k] === searchElement) {
        return k;
      }
    }
    return -1;
  };
}
```

Again, note that this implementation aims for absolute compatibility with `lastIndexOf` in Firefox and the SpiderMonkey JavaScript engine, including in several cases which are arguably edge cases. If you intend to use this in real-world applications, you may be able to calculate `from` with less complicated code if you ignore those cases.

規範
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-array.prototype.lastindexof |

瀏覽器相容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

相容性備註
-----

* Starting with Firefox 47, this method will no longer return `-0`. For example, `[0].lastIndexOf(0, -0)` will now always return `+0` (Firefox bug 1242043).
參見
--

* `Array.prototype.indexOf()`
* `TypedArray.prototype.lastIndexOf()` (en-US)


Array.prototype.copyWithin() - JavaScript

Array.prototype.copyWithin()
============================

**`copyWithin()`** 方法會對陣列的一部分進行淺拷貝至同一陣列的另一位置並回傳此陣列，而不修改其大小。

嘗試一下
----

語法
--
```

arr.copyWithin(target)
arr.copyWithin(target, start)
arr.copyWithin(target, start, end)
```

### 參數

`target`

要複製序列（sequence）至該位置的索引（起始為 0）。若為負數，`target` 將會自陣列末項開始計算。假如 `target` 大於等於 `arr.length`，則沒有項目會被複製。如果 `target` 的索引在 `start` 之後，則拷貝的序列將會被修剪以符合 `arr.length`。

`start` 選擇性

開始拷貝的起始元素索引（起始為 0）。若為負數，`start` 將會自陣列末項開始計算。如果省略 `start`，`copyWithin` 將會自陣列首項開始複製（預設為 0）。

`end` 選擇性

結束拷貝的結尾元素索引（起始為 0）。`copyWithin` 會拷貝至此索引，但不包含 `end`。若為負數，`end` 將會自陣列末項開始計算。如果省略 `end`，`copyWithin` 將會一路拷貝至陣列末項（預設至 `arr.length`）。

### 回傳值

被修改後的陣列。

描述
--

The `copyWithin` works like C and C++'s `memmove`, and is a high-performance method to shift the data of an `Array`. This especially applies to the `TypedArray` (en-US) method of the same name. The sequence is copied and pasted as one operation; pasted sequence will have the copied values even when the copy and paste region overlap.

The `copyWithin` function is intentionally *generic*, it does not require that its this value be an `Array` object.

The `copyWithin` method is a mutable method. It does not alter the length of `this`, but will change its content and create new properties if necessary.

範例
--

```js
[1, 2, 3, 4, 5].copyWithin(-2);
// [1, 2, 3, 1, 2]

[1, 2, 3, 4, 5].copyWithin(0, 3);
// [4, 5, 3, 4, 5]

[1, 2, 3, 4, 5].copyWithin(0, 3, 4);
// [4, 2, 3, 4, 5]

[1, 2, 3, 4, 5].copyWithin(-2, -3, -1);
// [1, 2, 3, 3, 4]

[].copyWithin.call({ length: 5, 3: 1 }, 0, 3);
// {0: 1, 3: 1, length: 5}

// ES2015 Typed Arrays are subclasses of Array
var i32a = new Int32Array([1, 2, 3, 4, 5]);

i32a.copyWithin(0, 2);
// Int32Array [3, 4, 5, 4, 5]

// On platforms that are not yet ES2015 compliant:
[].copyWithin.call(new Int32Array([1, 2, 3, 4, 5]), 0, 3, 4);
// Int32Array [4, 2, 3, 4, 5]
```

Polyfill
--------

```js
if (!Array.prototype.copyWithin) {
  Array.prototype.copyWithin =
    // Array: Number[, Number[, Number]]
    function copyWithin(target, start, stop) {
      var positiveT = target >= 0,
        positiveS = (start = start | 0) >= 0,
        length = this.length,
        zero = 0,
        r = function () {
          return (+new Date() \* Math.random()).toString(36);
        },
        delimiter = "\b" + r() + "-" + r() + "-" + r() + "\b",
        hold;

      stop = stop || this.length;
      hold = this.slice
        .apply(
          this,
          positiveT ? [start, stop] : positiveS ? [start, -target] : [start],
        )
        .join(delimiter);

      return (
        this.splice.apply(
          this,
          positiveT
            ? [target, stop - start, hold]
            : positiveS
              ? [target, stop, hold]
              : [target, start, hold],
        ),
        this.join(delimiter).split(delimiter).slice(zero, length)
      );
    };
}
```

規範
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-array.prototype.copywithin |

瀏覽器相容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

參見
--

* `Array`


Array.prototype.splice() - JavaScript

Array.prototype.splice()
========================

**`splice()`** 方法可以藉由刪除既有元素並／或加入新元素來改變一個陣列的內容。

嘗試一下
----

語法
--

```js
array.splice(start[, deleteCount[, item1[, item2[, ...]]]])
```

### 參數

`start`

陣列中要開始改動的元素索引（起始為 0）。若索引大於陣列長度，則實際開始的索引值會被設為陣列長度。若索引為負，則會從陣列中最後一個元素開始往前改動（起始為 -1）且若其絕對值大於陣列的長度，則會被設為 0。

`deleteCount` 選擇性

一個表示欲刪除的原陣列元素數量的整數。若省略了 `deleteCount`，或假如其值大於 `array.length - start`（也就是 `deleteCount` 大於 `start` 算起的剩餘元素數量），則所有從 `start` 開始到陣列中最後一個元素都會被刪除。若 `deleteCount` 為 0 或是負數，則不會有元素被刪除。 因此，你應該給定至少一個欲加入的新元素（見下方說明）。

`item1, item2, ...` 選擇性

從 `start` 開始，要加入到陣列的元素。 如果你沒有指定任何元素，則 `splice()` 只會依照 `start` 和 `deleteCount` 刪除陣列的元素。

### 回傳值

一個包含被刪除的元素陣列。如果只有一個元素被刪除，依舊是回傳包含一個元素的陣列。 倘若沒有元素被刪除，則會回傳空陣列。

說明
--

如果你插入的元素數量和刪除的數量不同，則回傳的陣列長度也會和原先的不同。

範例
--

### 從索引 2 的位置開始，刪除 0 個元素並插入「drum」

```js
var myFish = ["angel", "clown", "mandarin", "sturgeon"];
var removed = myFish.splice(2, 0, "drum");

// myFish 為 ["angel", "clown", "drum", "mandarin", "sturgeon"]
// removed 為 [], 沒有元素被刪除
```

### 從索引 3 的位置開始，刪除 1 個元素

```js
var myFish = ["angel", "clown", "drum", "mandarin", "sturgeon"];
var removed = myFish.splice(3, 1);

// removed 為 ["mandarin"]
// myFish 為 ["angel", "clown", "drum", "sturgeon"]
```

### 從索引 2 的位置開始，刪除 1 個元素並插入「trumpet」

```js
var myFish = ["angel", "clown", "drum", "sturgeon"];
var removed = myFish.splice(2, 1, "trumpet");

// myFish 為 ["angel", "clown", "trumpet", "sturgeon"]
// removed 為 ["drum"]
```

### 從索引 0 的位置開始，刪除 2 個元素並插入「parrot」、「anemone」和「blue」

```js
var myFish = ["angel", "clown", "trumpet", "sturgeon"];
var removed = myFish.splice(0, 2, "parrot", "anemone", "blue");

// myFish 為 ["parrot", "anemone", "blue", "trumpet", "sturgeon"]
// removed 為 ["angel", "clown"]
```

### 從索引 2 的位置開始，刪除 2 個元素

```js
var myFish = ["parrot", "anemone", "blue", "trumpet", "sturgeon"];
var removed = myFish.splice(myFish.length - 3, 2);

// myFish 為 ["parrot", "anemone", "sturgeon"]
// removed 為 ["blue", "trumpet"]
```

### 從索引 -2 的位置開始，刪除 1 個元素

```js
var myFish = ["angel", "clown", "mandarin", "sturgeon"];
var removed = myFish.splice(-2, 1);

// myFish 為 ["angel", "clown", "sturgeon"]
// removed 為 ["mandarin"]
```

### 從索引 2 的位置開始，刪除所有元素（含索引 2）

```js
var myFish = ["angel", "clown", "mandarin", "sturgeon"];
var removed = myFish.splice(2);

// myFish 為 ["angel", "clown"]
// removed 為 ["mandarin", "sturgeon"]
```

規範
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-array.prototype.splice |

瀏覽器相容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

參見
--

* `push()` / `pop()` — add/remove elements from the end of the array
* `unshift()` / `shift()` — add/remove elements from the beginning of the array
* `concat()` — returns a new array comprised of this array joined with other array(s) and/or value(s)


Promise.prototype.catch() - JavaScript

Promise.prototype.catch()
=========================

**catch()** 方法只處理 Promise 的被拒絕狀態，並回傳一個新的 `Promise` 物件。此方法的行為等同於呼叫 `Promise.prototype.then(undefined, onRejected)`。

語法
--

```js
p.catch(onRejected);

p.catch(function (reason) {
  // rejection
});
```

### 參數

onRejected

一個 `Function` (en-US) ，在 `Promise` 被拒絕時被呼叫。這個函式有一個引數：

`reason`

失敗訊息。

若 onRejected 拋出一個錯誤或回傳一個被拒絕的 Promise，則 catch() 回傳的 Promise 被拒絕；其他情形都是被實現。

### 回傳值

呼叫（`catch` 的 promise）物件，內部呼叫 `Promise.prototype.then`，傳入引數 undefined 及 onRejected；接著以之結果回傳（結果為 `Promise`）。

**內部呼叫演示：**

```js
// overriding original Promise.prototype.then/catch just to add some logs
(function (Promise) {
  var originalThen = Promise.prototype.then;
  var originalCatch = Promise.prototype.catch;

  Promise.prototype.then = function () {
    console.log(
      "> > > > > > called .then on %o with arguments: %o",
      this,
      arguments,
    );
    return originalThen.apply(this, arguments);
  };
  Promise.prototype.catch = function () {
    console.log(
      "> > > > > > called .catch on %o with arguments: %o",
      this,
      arguments,
    );
    return originalCatch.apply(this, arguments);
  };
})(this.Promise);

// calling catch on an already resolved promise
Promise.resolve().catch(function XXX() {});

// logs:
// > > > > > > called .catch on Promise{} with arguments: Arguments{1} [0: function XXX()]
// > > > > > > called .then on Promise{} with arguments: Arguments{2} [0: undefined, 1: function XXX()]
```

描述
--

`catch` 方法在處理 promise 組合的錯誤時很有幫助。

範例
--

### 使用及串接 `catch` 方法

```js
var p1 = new Promise(function (resolve, reject) {
  resolve("Success");
});

p1.then(function (value) {
  console.log(value); // "Success!"
  throw "oh, no!";
})
  .catch(function (e) {
    console.log(e); // "oh, no!"
  })
  .then(
    function () {
      console.log("after a catch the chain is restored");
    },
    function () {
      console.log("Not fired due to the catch");
    },
  );

// The following behaves the same as above
p1.then(function (value) {
  console.log(value); // "Success!"
  return Promise.reject("oh, no!");
})
  .catch(function (e) {
    console.log(e); // "oh, no!"
  })
  .then(
    function () {
      console.log("after a catch the chain is restored");
    },
    function () {
      console.log("Not fired due to the catch");
    },
  );
```

### 拋出例外時的陷阱

```js
// Throwing an error will call the catch method most of the time
var p1 = new Promise(function (resolve, reject) {
  throw "Uh-oh!";
});

p1.catch(function (e) {
  console.log(e); // "Uh-oh!"
});

// Errors thrown inside asynchronous functions will act like uncaught errors
var p2 = new Promise(function (resolve, reject) {
  setTimeout(function () {
    throw "Uncaught Exception!";
  }, 1000);
});

p2.catch(function (e) {
  console.log(e); // This is never called
});

// Errors thrown after resolve is called will be silenced
var p3 = new Promise(function (resolve, reject) {
  resolve();
  throw "Silenced Exception!";
});

p3.catch(function (e) {
  console.log(e); // This is never called
});
```

### 如果 Promise 被實現

```js
//Create a promise which would not call onReject
var p1 = Promise.resolve("calling next");

var p2 = p1.catch(function (reason) {
  //This is never called
  console.log("catch p1!");
  console.log(reason);
});

p2.then(
  function (value) {
    console.log("next promise's onFulfilled"); /\* next promise's onFulfilled \*/
    console.log(value); /\* calling next \*/
  },
  function (reason) {
    console.log("next promise's onRejected");
    console.log(reason);
  },
);
```

規範
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-promise.prototype.catch |

瀏覽器相容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

參見
--

* `Promise`
* `Promise.prototype.then()`


Promise.race() - JavaScript

Promise.race()
==============

**`Promise.race(iterable)`** 方法回傳一個 promise 物件，此 promise 物件會於 iterable 引數中任一個 promise 轉為 resolve 或 rejected 時立即轉變成 resolve 或 rejected，並且接收其成功值或失敗訊息。

語法
--

```js
Promise.race(iterable);
```

### 參數

iterable

一個 iterable 物件，像是 `Array`. 請參考可迭代協議。

### 回傳值

當傳入的 iterable 中有 promise 被實現或拒絕時，立刻回傳被實現或拒絕的 `Promise`。

描述
--

`race` 函式回傳一個與傳入的 iterable 之中第一個被解決（settled）的 promise 相同方式被解決（且以相同值）的 `Promise`。

範例
--

### `Promise.race` 的非同步性質

以下例子演示了 `Promise.race` 的非同步性質：

```js
// we are passing as argument an array of promises that are already resolved,
// to trigger Promise.race as soon as possible
var resolvedPromisesArray = [Promise.resolve(33), Promise.resolve(44)];

var p = Promise.race(resolvedPromisesArray);
// immediately logging the value of p
console.log(p);

// using setTimeout we can execute code after the stack is empty
setTimeout(function () {
  console.log("the stack is now empty");
  console.log(p);
});

// logs, in order:
// Promise { <state>: "pending" }
// the stack is now empty
// Promise { <state>: "fulfilled", <value>: 33 }
```

一個空的 iterable 造成回傳的 promise 永久擱置：

```js
var foreverPendingPromise = Promise.race([]);
console.log(foreverPendingPromise);
setTimeout(function () {
  console.log("the stack is now empty");
  console.log(foreverPendingPromise);
});

// logs, in order:
// Promise { <state>: "pending" }
// the stack is now empty
// Promise { <state>: "pending" }
```

若 iterable 中有一個或多個非 promise 值且／或一個已經被實現／解決的 promise，`Promise.race` 將以陣列中第一個這樣的值解決：

```js
var foreverPendingPromise = Promise.race([]);
var alreadyResolvedProm = Promise.resolve(666);

var arr = [foreverPendingPromise, alreadyResolvedProm, "non-Promise value"];
var arr2 = [foreverPendingPromise, "non-Promise value", Promise.resolve(666)];
var p = Promise.race(arr);
var p2 = Promise.race(arr2);

console.log(p);
console.log(p2);
setTimeout(function () {
  console.log("the stack is now empty");
  console.log(p);
  console.log(p2);
});

// logs, in order:
// Promise { <state>: "pending" }
// Promise { <state>: "pending" }
// the stack is now empty
// Promise { <state>: "fulfilled", <value>: 666 }
// Promise { <state>: "fulfilled", <value>: "non-Promise value" }
```

### 使用 `Promise.race` 及 `setTimeout` 的範例

```js
var p1 = new Promise(function (resolve, reject) {
  setTimeout(resolve, 500, "one");
});
var p2 = new Promise(function (resolve, reject) {
  setTimeout(resolve, 100, "two");
});

Promise.race([p1, p2]).then(function (value) {
  console.log(value); // "two"
  // Both resolve, but p2 is faster
});

var p3 = new Promise(function (resolve, reject) {
  setTimeout(resolve, 100, "three");
});
var p4 = new Promise(function (resolve, reject) {
  setTimeout(reject, 500, "four");
});

Promise.race([p3, p4]).then(
  function (value) {
    console.log(value); // "three"
    // p3 is faster, so it resolves
  },
  function (reason) {
    // Not called
  },
);

var p5 = new Promise(function (resolve, reject) {
  setTimeout(resolve, 500, "five");
});
var p6 = new Promise(function (resolve, reject) {
  setTimeout(reject, 100, "six");
});

Promise.race([p5, p6]).then(
  function (value) {
    // Not called
  },
  function (reason) {
    console.log(reason); // "six"
    // p6 is faster, so it rejects
  },
);
```

規範
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-promise.race |

瀏覽器相容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

參見
--

* `Promise`
* `Promise.all()`


Promise.resolve() - JavaScript

Promise.resolve()
=================

**`Promise.resolve(value)`** 方法回傳一個以 value 判定結果的 `Promise` 物件。若 value 是個 thenable（例如，具有 `then()` 方法，則回傳的 promise 將依其結果採取其最終狀態；若 value 是 promise，則作為呼叫 Promise.resolve 之結果；其他情形都將回傳以 value 實現的 promise。

語法
--

```js
Promise.resolve(value);
Promise.resolve(promise);
Promise.resolve(thenable);
```

### 參數

value

將被 `Promise` 實現的引數（argument）。可以是個 `Promise` 或待解決的 thenable。

### 回傳值

以 value 或作為 value 的 promise 解決的 `Promise`。

描述
--

`靜態函式` `Promise.resolve` 回傳判定後的 `Promise。`

範例
--

### 使用 `Promise.resolve` 靜態方法

```js
Promise.resolve("Success").then(
  function (value) {
    console.log(value); // "Success"
  },
  function (value) {
    // not called
  },
);
```

### 判定陣列

```js
var p = Promise.resolve([1, 2, 3]);
p.then(function (v) {
  console.log(v[0]); // 1
});
```

### 判定另一個 `Promise`

```js
var original = Promise.resolve(33);
var cast = Promise.resolve(original);
cast.then(function (value) {
  console.log("value: " + value);
});
console.log("original === cast ? " + (original === cast));

// logs, in order:
// original === cast ? true
// value: 33
```

由於 handler 是非同步地被調用而導致相反的紀錄順序。經由這篇文章了解 then 如何運作。

### 判定 thenable 及拋出 Error

```js
// Resolving a thenable object
var p1 = Promise.resolve({
  then: function (onFulfill, onReject) {
    onFulfill("fulfilled!");
  },
});
console.log(p1 instanceof Promise); // true, object casted to a Promise

p1.then(
  function (v) {
    console.log(v); // "fulfilled!"
  },
  function (e) {
    // not called
  },
);

// Thenable throws before callback
// Promise rejects
var thenable = {
  then: function (resolve) {
    throw new TypeError("Throwing");
    resolve("Resolving");
  },
};

var p2 = Promise.resolve(thenable);
p2.then(
  function (v) {
    // not called
  },
  function (e) {
    console.log(e); // TypeError: Throwing
  },
);

// Thenable throws after callback
// Promise resolves
var thenable = {
  then: function (resolve) {
    resolve("Resolving");
    throw new TypeError("Throwing");
  },
};

var p3 = Promise.resolve(thenable);
p3.then(
  function (v) {
    console.log(v); // "Resolving"
  },
  function (e) {
    // not called
  },
);
```

規範
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-promise.resolve |

瀏覽器相容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

參見
--

* `Promise`


Promise.prototype.finally() - JavaScript

Promise.prototype.finally()
===========================

**`finally()`** 方法會回傳一個 `Promise`。當 promise 被 settled 後，無論其結果是 fulfilled 還是 rejected ，都會執行指定的回呼函數。它提供了一個讓 `Promise` 在被確認後，無論是 fulfilled 或是 rejected 都會執行某些程式碼的一種手段。

這樣可以避免你在 promise 的 `then()` 和 `catch()` 重複處理相同的程式碼。

Syntax
------

```js
p.finally(onFinally);

p.finally(function () {
  // settled（fulfilled 或 rejected)
});
```

### Parameters

`onFinally`

當 `Promise` settled 後呼叫的 `Function` (en-US)。

### Return value

回傳 `Promise` 當 `finally` 的處理函數 `onFinally` 被指定時。

Description
-----------

當你希望在 promise settled 後且不關心它的結果為何時，執行一些處理或清理的工作， `finally()` 方法會很有幫助。

`finally()` 方法非常類似於 `.then(onFinally, onFinally)` 的呼叫方式，但仍有一些差異：

* 當建立行內的函數時，可以只傳遞一次，從而避免重複宣告或為它宣告變數。
* `finally` 的回呼函數並不會接收到任何引數，因其沒有可靠的方式來確認 promise 是被 fulfilled 還是 rejected 。它的使用情境僅適用於當你*不關心* rejection 的原因或 fulfillment 的值，因此無須提供。範例：
    + 與 `Promise.resolve(2).then(() => {}, () => {})`（將被 resolved 為`undefined`）不同，`Promise.resolve(2).finally(() => {})` 將被 resolved 為`2`。
    + 同樣的，與 `Promise.reject(3).then(() => {}, () => {})`（將 fulfilled 為`undefined`）不同，`Promise.reject(3).finally(() => {})` 將被 rejected 為`3`。

**備註：** 在 finally 回呼中使用 throw（或回傳 rejected promise）會導致新的 promise 被 reject，reject 的原因則是呼叫 throw() 時所指定的值。

範例
--

```js
let isLoading = true;

fetch(myRequest)
  .then(function (response) {
    var contentType = response.headers.get("content-type");
    if (contentType && contentType.includes("application/json")) {
      return response.json();
    }
    throw new TypeError("Oops, we haven't got JSON!");
  })
  .then(function (json) {
    /\* process your JSON further \*/
  })
  .catch(function (error) {
    console.log(error);
  })
  .finally(function () {
    isLoading = false;
  });
```

規範
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-promise.prototype.finally |

瀏覽器相容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

參見
--

* `Promise`
* `Promise.prototype.then()`
* `Promise.prototype.catch()`


Promise.prototype.then() - JavaScript

Promise.prototype.then()
========================

**`then()`** 方法回傳一個 `Promise` (en-US) 物件。它接收兩個引數： `Promise` 在成功及失敗情況時的回呼函式。

**備註：** 如果有一個或兩個引數被省略，或為非函式（non-functions），則 `then` 將處於遺失 handler(s) 的狀態，但不會產生錯誤。若發起 `then` 之 `Promise` 採取了一個狀態（實現（`fulfillment）`或拒絕（`rejection））`而 `then` 沒有處理它的函式，一個不具有額外 handlers 的新 `Promise` 物件將被建立，單純採取原 `Promise` 其最終狀態。

語法
--

```js
p.then(onFulfilled[, onRejected]);

p.then(function(value) {
  // fulfillment
}, function(reason) {
  // rejection
});
```

### 參數

`onFulfilled`

一個 `Function` (en-US)，當 `Promise` 被實現（fulfilled）時被呼叫。此函式接收一個實現值（`fulfillment value`）作為引數。

`onRejected` 選擇性

一個 `Function` (en-US)，當 `Promise` 被拒絕（rejected）時被呼叫。此函式接收一個失敗訊息（`rejection reason`）作為引數。

### 回傳值

一個進入**擱置**（pending）狀態的 `Promise`。（只要堆疊一空）handler 函式**非同步地**（asynchronously）被呼叫。在調用 handler 後，若 handler 函式：

* 回傳一個值，則 `then` 回傳之 promise 以此值被實現（resolved）。
* 拋出一個例外，則 `then` 回傳之 promise 以此例外被否決（rejected）。
* 回傳一個被實現的 promise，則 `then` 回傳之 promise 以此值被實現。
* 回傳一個被否決的 promise，則 `then` 回傳之 promise 以此值被否決。
* 回傳另一個被**擱置**的 promise 物件，則 `then` 回傳之 promise 之實現／拒絕隨後由處理函式之實現/否決決定。並且，`then` 回傳之 promise 將與處理函式回傳之 promise 以相同值被解決。

以下例子展示 `then` 方法的非同步性質（asynchronicity）。

```js
// 使用一個已實現的 promise，'then' 區塊將立即被觸發，但是它的 handlers 將是非同步地被觸發，如同 console.logs 所示
var resolvedProm = Promise.resolve(33);

var thenProm = resolvedProm.then(function (value) {
  console.log("我在 main stack 之後被呼叫。收到及將回傳的值為：" + value);
  return value;
});
// 立即紀錄 thenProm
console.log(thenProm);

// 我們可以使用 setTimeout 以延遲（postpone）函式執行直到堆疊為空
setTimeout(function () {
  console.log(thenProm);
});

// 紀錄結果，依序為:
// Promise {[[PromiseStatus]]: "pending", [[PromiseValue]]: undefined}
// "我在 main stack 之後被呼叫。收到及將回傳的值為：33"
// Promise {[[PromiseStatus]]: "resolved", [[PromiseValue]]: 33}
```

描述
--

因為 `then` 和 `Promise.prototype.catch()` 方法都回傳 promises，它們可以被串接 — 稱為組合（*composition）。*

範例
--

### 運用 `then` 方法

```js
var p1 = new Promise((resolve, reject) => {
  resolve("Success!");
  // or
  // reject ("Error!");
});

p1.then(
  (value) => {
    console.log(value); // Success!
  },
  (reason) => {
    console.log(reason); // Error!
  },
);
```

### 串接

`then` 方法回傳一個 `Promise` 而可以進行方法串接（method chaining）。

如果傳入 `then` 的 handler 函式回傳一個 promise，一個等價的 `Promise` 將被展現給方法串接中的下一個 then 。以下程式碼片段透過 `setTimout` 函式模擬非同步程式碼。

```js
Promise.resolve("foo")
  // 1. Receive "foo" concatenate "bar" to it and resolve that to the next then
  .then(function (string) {
    return new Promise(function (resolve, reject) {
      setTimeout(function () {
        string += "bar";
        resolve(string);
      }, 1);
    });
  })
  // 2. receive "foobar", register a callback function to work on that string
  // and print it to the console, but not before return the unworked on
  // string to the next then
  .then(function (string) {
    setTimeout(function () {
      string += "baz";
      console.log(string);
    }, 1);
    return string;
  })
  // 3. print helpful messages about how the code in this section will be run
  // before string is actually processed by the mocked asynchronous code in the
  // prior then block.
  .then(function (string) {
    console.log(
      "Last Then: oops... didn't bother to instantiate and return " +
        "a promise in the prior then so the sequence may be a bit " +
        "surprising",
    );

    // Note that `string` will not have the 'baz' bit of it at this point. This
    // is because we mocked that to happen asynchronously with a setTimeout function
    console.log(string);
  });
```

當 handler 僅回傳一個值，實際上它將回傳 `Promise.resolve(<value returned by whichever handler was called>)`.

```js
var p2 = new Promise(function (resolve, reject) {
  resolve(1);
});

p2.then(function (value) {
  console.log(value); // 1
  return value + 1;
}).then(function (value) {
  console.log(value + "- This synchronous usage is virtually pointless"); // 2- This synchronous usage is virtually pointless
});

p2.then(function (value) {
  console.log(value); // 1
});
```

若函式拋出一個錯誤或回傳一個被否決的 Promise，`then` 也將回傳一個被否決的 Promise。

```js
Promise.resolve()
  .then(() => {
    // 使 .then() 回傳一個被否決的 Promise
    throw "Oh no!";
  })
  .then(
    () => {
      console.log("Not called.");
    },
    (reason) => {
      console.error("onRejected function called: ", reason);
    },
  );
```

在所有其他情形，實現中的 Promise 被回傳。在以下例子中，第一個 `then()` 將回傳一個實現中包裹 42 的 promise，即使串接中的前一個 Promise 被否決。

```js
Promise.reject()
  .then(
    () => 99,
    () => 42,
  ) // onRejected returns 42 which is wrapped in a resolving Promise
  .then((solution) => console.log("Resolved with " + solution)); // Resolved with 42
```

實務上，使用 `catch` 捕捉被否決的 promise 較理想的，而不建議使用兩個引數 `then` 語法，如下展示。

```js
Promise.resolve()
  .then(() => {
    // Makes .then() return a rejected promise
    throw "Oh no!";
  })
  .catch((reason) => {
    console.error("onRejected function called: ", reason);
  })
  .then(() => {
    console.log("I am always called even if the prior then's promise rejects");
  });
```

你也可以透過串接實作一個 Promise-based API 函式，基於它本身。

```js
function fetch\_current\_data() {
  // The fetch() API returns a Promise. This function
  // exposes a similar API, except the fulfillment
  // value of this function's Promise has had more
  // work done on it.
  return fetch("current-data.json").then((response) => {
    if (response.headers.get("content-type") != "application/json") {
      throw new TypeError();
    }
    var j = response.json();
    // maybe do something with j
    return j; // fulfillment value given to user of
    // fetch\_current\_data().then()
  });
}
```

若 `onFulfilled` 回傳一個 promise，則 `then` 的實現/否決將取決它。

```js
function resolveLater(resolve, reject) {
  setTimeout(function () {
    resolve(10);
  }, 1000);
}
function rejectLater(resolve, reject) {
  setTimeout(function () {
    reject(20);
  }, 1000);
}

var p1 = Promise.resolve("foo");
var p2 = p1.then(function () {
  // Return promise here, that will be resolved to 10 after 1 second
  return new Promise(resolveLater);
});
p2.then(
  function (v) {
    console.log("resolved", v); // "resolved", 10
  },
  function (e) {
    // not called
    console.log("rejected", e);
  },
);

var p3 = p1.then(function () {
  // Return promise here, that will be rejected with 20 after 1 second
  return new Promise(rejectLater);
});
p3.then(
  function (v) {
    // not called
    console.log("resolved", v);
  },
  function (e) {
    console.log("rejected", e); // "rejected", 20
  },
);
```

規範
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-promise.prototype.then |

瀏覽器相容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

參見
--

* `Promise`
* `Promise.prototype.catch()`


Promise.reject() - JavaScript

Promise.reject()
================

**`Promise.reject(reason)`** 方法回傳一個以 `reason` 拒絕的 `Promise` 物件。

語法
--

```js
Promise.reject(reason);
```

### 參數

reason

`Promise` 的失敗訊息。

### 回傳值

一個以 `reason` 拒絕的 `Promise`。

描述
--

靜態函式 `Promise.reject` 回傳一個被拒絕的 `Promise。由於除錯目的及選擇性錯誤捕捉（selective error catching），使`用一個 `instanceof` `Error` (en-US) 作為 reason 是很有幫助的。

範例
--

### 使用靜態方法 Promise.reject()

```js
Promise.reject(new Error("fail")).then(
  function (error) {
    // not called
  },
  function (error) {
    console.log(error); // Stacktrace
  },
);
```

規範
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-promise.reject |

瀏覽器相容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

參見
--

* `Promise`
* Selective error catching using the BlueBird Promise library


Promise.all() - JavaScript

Promise.all()
=============

**`Promise.all()`** 方法回傳一個 `Promise` 物件，當引數 `iterable` 中所有的 promises 都被實現（resolved），或引數 iterable 不含任何 promise 時，被實現。或以第一個被拒絕的 promise 的原因被拒絕。

語法
--

```js
Promise.all(iterable);
```

iterable

一個 iterable 物件像是 `Array` 或 `String`。

### 回傳值

* 一個\*\*已被實現（already resolved）\*\*的 `Promise`，若傳入的 iterable 為空。
* 一個**非同步地被實現（asynchronously resolved）**的 `Promise` 若傳入的 iterable 不含 promise。注意，Google Chrome 58 對此情形回傳一個**已被解決**的 promise。
* 一個**擱置（pending）**的 `Promise`，對所有剩餘情形。此 promise 接著被**非同步地**被 resolved/rejected（只要堆疊為空）當 iterable 中所有的 promises 都被實現，或其中一個被拒絕。參見下方關於"Promise.all 的非同步與同步性質"的例子。
描述
--

此方法在聚集（aggregating）多個 promises 的結果時很有幫助。

 實現（Fulfillment）：
 若傳入空的 iterable，此方法（同步地）回傳一個已被解決的 promise。若所有傳入的 promises 都被實現，或都不是 promise，`Promise.all` 回傳的 promise 被非同步地實現。無論是哪個情形，回傳一個以 iterable 其內**所有**值（包含非 promise 值）作為引數的陣列被實現。

 拒絕（Rejection）：
 若任一個傳入的 promise 被拒絕，Promise.all 非同步地以其值被拒絕，無論其他 promises 是否被解決。

範例
--

### 使用 `Promise.all`

`Promise.all` 等到全部實現（或一個拒絕）。

```js
var p1 = Promise.resolve(3);
var p2 = 1337;
var p3 = new Promise((resolve, reject) => {
  setTimeout(resolve, 100, "foo");
});

Promise.all([p1, p2, p3]).then((values) => {
  console.log(values); // [3, 1337, "foo"]
});
```

若 iterable 含非 promise 值，它們將被忽略，但依然會被記入回傳 promise 陣列值（若被實現）：

```js
// this will be counted as if the iterable passed is empty, so it gets fulfilled
var p = Promise.all([1, 2, 3]);
// this will be counted as if the iterable passed contains only the resolved promise with value "444", so it gets fulfilled
var p2 = Promise.all([1, 2, 3, Promise.resolve(444)]);
// this will be counted as if the iterable passed contains only the rejected promise with value "555", so it gets rejected
var p3 = Promise.all([1, 2, 3, Promise.reject(555)]);

// using setTimeout we can execute code after the stack is empty
setTimeout(function () {
  console.log(p);
  console.log(p2);
  console.log(p3);
});

// logs
// Promise { <state>: "fulfilled", <value>: Array[3] }
// Promise { <state>: "fulfilled", <value>: Array[4] }
// Promise { <state>: "rejected", <reason>: 555 }
```

### `Promise.all` 的非同步與同步性質

以下例子驗證了 `Promise.all` 的非同步性質（asynchronicity）（或同步性質（synchronicity），若傳入的 iterable 是空的）：

```js
// we are passing as argument an array of promises that are already resolved,
// to trigger Promise.all as soon as possible
var resolvedPromisesArray = [Promise.resolve(33), Promise.resolve(44)];

var p = Promise.all(resolvedPromisesArray);
// immediately logging the value of p
console.log(p);

// using setTimeout we can execute code after the stack is empty
setTimeout(function () {
  console.log("the stack is now empty");
  console.log(p);
});

// logs, in order:
// Promise { <state>: "pending" }
// the stack is now empty
// Promise { <state>: "fulfilled", <value>: Array[2] }
```

`當` `Promise.all` 被拒絕時發生一樣的事情：

```js
var mixedPromisesArray = [Promise.resolve(33), Promise.reject(44)];
var p = Promise.all(mixedPromisesArray);
console.log(p);
setTimeout(function () {
  console.log("the stack is now empty");
  console.log(p);
});

// logs
// Promise { <state>: "pending" }
// the stack is now empty
// Promise { <state>: "rejected", <reason>: 44 }
```

注意！`Promise.all` 同步地被解決**若且唯若**傳入的 iterable 為空：

```js
var p = Promise.all([]); // will be immediately resolved
var p2 = Promise.all([1337, "hi"]); // non-promise values will be ignored, but the evaluation will be done asynchronously
console.log(p);
console.log(p2);
setTimeout(function () {
  console.log("the stack is now empty");
  console.log(p2);
});

// logs
// Promise { <state>: "fulfilled", <value>: Array[0] }
// Promise { <state>: "pending" }
// the stack is now empty
// Promise { <state>: "fulfilled", <value>: Array[2] }
```

### `Promise.all` 的失敗優先（fail-fast）行為

`當任一個陣列成員被拒絕則` `Promise.all` 被拒絕。例如，若傳入四個將在一段時間後被解決的 promises，而其中一個立刻被拒絕，則 `Promise.all` 將立刻被拒絕。

```js
var p1 = new Promise((resolve, reject) => {
  setTimeout(resolve, 1000, "one");
});
var p2 = new Promise((resolve, reject) => {
  setTimeout(resolve, 2000, "two");
});
var p3 = new Promise((resolve, reject) => {
  setTimeout(resolve, 3000, "three");
});
var p4 = new Promise((resolve, reject) => {
  setTimeout(resolve, 4000, "four");
});
var p5 = new Promise((resolve, reject) => {
  reject("reject");
});

Promise.all([p1, p2, p3, p4, p5]).then(
  (values) => {
    console.log(values);
  },
  (reason) => {
    console.log(reason);
  },
);

//From console:
//"reject"

//You can also use .catch
Promise.all([p1, p2, p3, p4, p5])
  .then((values) => {
    console.log(values);
  })
  .catch((reason) => {
    console.log(reason);
  });

//From console:
//"reject"
```

規範
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-promise.all |

瀏覽器相容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

參見
--

* `Promise`
* `Promise.race()`


Function.prototype.call - JavaScript

Function.prototype.call
=======================

使用給定的 `this` 參數以及分別給定的參數來呼叫某個函數

**備註：** 此函數的所有語法大致上與 `apply()` (en-US) 相同，他們基本上不同處只有 `call()` 接受一連串的參數，而 `apply()` 單一的 array 作為參數

| Function (en-US)物件的方法 |
| --- |
| 被實作於 | JavaScript 1.3 |
| ECMAScript 版本 | ECMAScript 第三版 |

語法
--

```js
fun.call(thisArg[, arg1[, arg2[, ...]]])
```

### 參數

`thisArg`

呼叫\*`fun`\*時提供的`this`值。 注意，它可能是一個無法在函數內看到的值：若這個函數是在非嚴苛模式( non-strict mode (en-US) ), `null` `、undefined` 將會被置換成全域變數，而原生型態的值將會被封裝

`arg1, arg2, ...`

其他參數

描述
--

你可以在呼叫一個現存的函數時，使用不一樣的 `this` 物件。`this` 會參照到目前的物件，呼叫的物件上

使用 `call`，你可以實作函數一次，然後在其他的物件上直接繼承它，而不用在新的物件上重寫該函數

範例
--

### 使用 `call` 來串接物件上的建構子

你可以使用 `call` 來串接其他物件的建構子，就像 Java。下面的例子中，`Product` 物件的建構子定義了兩個參數 `name` 以及 `price`。其他函數 `Food` 及 `Toy` 引用了 `Product` 並傳入 `this`、`name` 和 `price`。Product 初始化它的屬性 `name` 和 `price`，而兩個子函數則定義了 `category`。

```js
function Product(name, price) {
  this.name = name;
  this.price = price;

  if (price < 0)
    throw RangeError(
      'Cannot create product "' + name + '" with a negative price',
    );
  return this;
}

function Food(name, price) {
  Product.call(this, name, price);
  this.category = "food";
}
Food.prototype = new Product();

function Toy(name, price) {
  Product.call(this, name, price);
  this.category = "toy";
}
Toy.prototype = new Product();

var cheese = new Food("feta", 5);
var fun = new Toy("robot", 40);
```

### 使用 `call` 來呼叫匿名的函數

下面這個簡易的例子中，我們做了一個匿名的函數，並用 `call` 來讓它應用在每個在串列中的物件中. 這個匿名函數的主要用途是加入一個 print 函數到每個物件上，這個函數可以印出每個物件的 index 指標。 傳入物件作為 `this` 的值並不是必要的，但他有解釋的用途。

```js
var animals = [
  { species: "Lion", name: "King" },
  { species: "Whale", name: "Fail" },
];

for (var i = 0; i < animals.length; i++) {
  (function (i) {
    this.print = function () {
      console.log("#" + i + " " + this.species + ": " + this.name);
    };
    this.print();
  }).call(animals[i], i);
}
```

規範
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-function.prototype.call |

瀏覽器相容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

參見
--

* apply (en-US)


Function.prototype.apply() - JavaScript

Function.prototype.apply()
==========================

`apply()` 方法會呼叫一個以 this 的代表值和一個陣列形式的值組（或是一個 array-like object (en-US)）為參數的函式。

**備註：** 這個函式的語法和 `call()` 幾乎一樣，最大的不同是 `call()` 接受**一連串的參數**，而 `apply()` 接受一組陣列形式的參數。

語法
--

```js
fun.apply(thisArg, [argsArray])
```

### 參數

`thisArg`

讓 *`fun`* 呼叫時可以視為 this 的值。注意，這可能並不是最後會在方法裡看見的值：如果這是一個在非 non-strict mode 下運作的程式碼，`null` (en-US) 及 `undefined` (en-US) 將會被全域物件取代，而原始類別將被封裝。

`argsArray`

一個 array-like 物件 ，定義了 *`fun`* 要呼叫的一組參數，如果沒有需要提供，可以傳入 `null` (en-US) 或 `undefined` (en-US)。從 ECMAScript 5 開始，這些參數不僅可以是泛型的 array-like 物件，而不一定要是一組陣列。查看下方的瀏覽器相容性資訊。

### 回傳值

傳入 `this` 值及一組參數後得到的結果。

描述
--

在呼叫一個現存的函式時，你可以傳入不同的 `this` 物件值。this 參考到現在的物件，也就是正在執行的物件。apply 讓你可以只寫一次方法後，讓其他物件也繼承到這個方法，而不用一再重寫。

`apply` 與 `call()` 非常相似，不同的是支援的傳入參數類型。使用陣列形式的參數，而不是命名過的接收參數。使用 `apply` 時，你可以選擇使用陣列實字：`fun.apply(this, ['eat', 'bananas']);` 或是 `Array` 物件：`fun.apply(this, new Array('eat', 'bananas'))`。

除此之外，你也可以使用 `arguments` (en-US) 代表 `argsArray` 參數。arguments 是在函式裡的區域變數，可用來存取所有沒有特別被所呼叫物件指定的傳入參數。因此，使用 apply 時你不需要知道所呼叫函式的指定參數。使用 `arguments` 把所有參數傳入呼叫的方法裡，而被呼叫的方法會接手處理這些參數。

從 ECMAScript 5th 版本後，也可以使用陣列形式的物件，在實踐上這代表他會擁有 `length` 以及整數範圍 `(0...length-1)` 的屬性。舉例來說，你可以使用 `NodeList` 或是一個像這樣的自定義屬性：`{ 'length': 2, '0': 'eat', '1': 'bananas' }`。

**備註：** 一般瀏覽器，包括 Chrome 14 及 Internet Explorer 9，仍不支援陣列形式的物件，所以會對此丟出一個錯誤。

範例
--

### 使用 `apply` 與建構子鏈結

你可以使用 `apply` 鏈結 constructors 一個物件，與 Java 相似，如下範例中我們可以建立一個全域的 `Function` (en-US) 方法叫 `construct`，使你可以使用類陣列的物件與建構子去替代參數列表。

```js
Function.prototype.construct = function (aArgs) {
  var oNew = Object.create(this.prototype);
  this.apply(oNew, aArgs);
  return oNew;
};
```

**備註：** 如上範例的 `Object.create()` 方法是屬於比較新的寫法。如需使用閉包的替代方法，請參考以下的範例：

```js
Function.prototype.construct = function (aArgs) {
  var fConstructor = this,
    fNewConstr = function () {
      fConstructor.apply(this, aArgs);
    };
  fNewConstr.prototype = fConstructor.prototype;
  return new fNewConstr();
};
```

使用範例：

```js
function MyConstructor() {
  for (var nProp = 0; nProp < arguments.length; nProp++) {
    this["property" + nProp] = arguments[nProp];
  }
}

var myArray = [4, "Hello world!", false];
var myInstance = MyConstructor.construct(myArray);

console.log(myInstance.property1); // logs 'Hello world!'
console.log(myInstance instanceof MyConstructor); // logs 'true'
console.log(myInstance.constructor); // logs 'MyConstructor'
```

**備註：** This non-native `Function.construct` method will not work with some native constructors (like `Date`, for example). In these cases you have to use the `Function.prototype.bind` method (for example, imagine having an array like the following, to be used with `Date` constructor: `[2012, 11, 4]`; in this case you have to write something like: `new (Function.prototype.bind.apply(Date, [null].concat([2012, 11, 4])))()` — anyhow this is not the best way to do things and probably should not be used in any production environment).

### 使用 `apply` 於內建的函數

apply 可以巧妙的在某些任務中使用內建函數，否則可能會循環遍歷整個陣列來寫入。如下範例，我們使用 `Math.max/Math.min` 來找出陣列中最大/最小的值。

```js
// min/max number in an array
var numbers = [5, 6, 2, 3, 7];

// using Math.min/Math.max apply
var max = Math.max.apply(null, numbers);
// This about equal to Math.max(numbers[0], ...)
// or Math.max(5, 6, ...)

var min = Math.min.apply(null, numbers);

// vs. simple loop based algorithm
(max = -Infinity), (min = +Infinity);

for (var i = 0; i < numbers.length; i++) {
  if (numbers[i] > max) {
    max = numbers[i];
  }
  if (numbers[i] < min) {
    min = numbers[i];
  }
}
```

But beware: in using `apply` this way, you run the risk of exceeding the JavaScript engine's argument length limit. The consequences of applying a function with too many arguments (think more than tens of thousands of arguments) vary across engines (JavaScriptCore has hard-coded argument limit of 65536), because the limit (indeed even the nature of any excessively-large-stack behavior) is unspecified. Some engines will throw an exception. More perniciously, others will arbitrarily limit the number of arguments actually passed to the applied function. (To illustrate this latter case: if such an engine had a limit of four arguments [actual limits are of course significantly higher], it would be as if the arguments `5, 6, 2, 3` had been passed to `apply` in the examples above, rather than the full array.) If your value array might grow into the tens of thousands, use a hybrid strategy: apply your function to chunks of the array at a time:

```js
function minOfArray(arr) {
  var min = Infinity;
  var QUANTUM = 32768;

  for (var i = 0, len = arr.length; i < len; i += QUANTUM) {
    var submin = Math.min.apply(null, arr.slice(i, Math.min(i + QUANTUM, len)));
    min = Math.min(submin, min);
  }

  return min;
}

var min = minOfArray([5, 6, 2, 3, 7]);
```

### Using apply in "monkey-patching"

Apply can be the best way to monkey-patch a built-in function of Firefox, or JS libraries. Given `someobject.foo` function, you can modify the function in a somewhat hacky way, like so:

```js
var originalfoo = someobject.foo;
someobject.foo = function () {
  // Do stuff before calling function
  console.log(arguments);
  // Call the function as it would have been called normally:
  originalfoo.apply(this, arguments);
  // Run stuff after, here.
};
```

This method is especially handy where you want to debug events, or interface with something that has no API like the various `.on([event]...` events, such as those usable on the Devtools Inspector).

規範
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-function.prototype.apply |

瀏覽器相容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

參見
--

* `arguments` (en-US) object
* `Function.prototype.bind()`
* `Function.prototype.call()`
* Functions and function scope (en-US)
* `Reflect.apply()` (en-US)


Function.length - JavaScript

Function.length
===============

**`length`** property 表示該 function 預期被傳入的參數數量

| `Function.length` 的屬性特性 |
| --- |
| 可寫 | 否 |
| 可列舉 | 否 |
| 可配置 | 是 |

描述
--

`length` 是 function 物件的一個 property，表示該 function 預期被傳入的參數數量，這個數量並不包含 rest parameter (en-US) 且只包涵第一個預設參數(Default Parameters)前的參數。相較之下 `arguments.length` (en-US) 是 function 內部的物件，會提供真正傳進 function 中的參數數量。

### `Function` 建構子的 data property

`Function` (en-US) 建構子本身就是一個 `Function` (en-US) 物件。其 `length` data property 的值為 1。此 property 的 attributes 包含: Writable: `false`, Enumerable: `false`, Configurable: `true`.

### `Function` prototype 物件的 property

`Function` (en-US) prototype 物件的 length property 其值為 0。

範例
--

```js
console.log(Function.length); /\* 1 \*/

console.log(function () {}.length); /\* 0 \*/
console.log(function (a) {}.length); /\* 1 \*/
console.log(function (a, b) {}.length); /\* 2 以此類推. \*/

console.log(function (...args) {}.length); /\* 0, rest parameter 不包含在內 \*/

console.log(function (a, b = 1, c) {}.length); /\* 1 \*/
// 只有在預設參數前的參數會被算到，也就是只有 a 會被視為必須傳入的參數
// 而 c 將被預設為 undefined
```

規範
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-function-instances-length |

瀏覽器相容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

參見
--

* `Function` (en-US)


Function.prototype.bind() - JavaScript

Function.prototype.bind()
=========================

**`bind()`** 方法，會建立一個新函式。該函式被呼叫時，會將 `this` 關鍵字設為給定的參數，並在呼叫時，帶有提供之前，給定順序的參數。

語法
--

```js
fun.bind(thisArg[, arg1[, arg2[, ...]]])
```

### 參數

`thisArg`

The value to be passed as the `this` parameter to the target function when the bound function is called. The value is ignored if the bound function is constructed using the `new` operator.

`arg1, arg2, ...`

Arguments to prepend to arguments provided to the bound function when invoking the target function.

### 回傳值

A copy of the given function with the specified **`this`** value and initial arguments.

敘述
--

**bind()** 函式建立了一個新的**綁定函式（BF）**。**BF** 是個包裝了原有函式物件的 **exotic function object**（**ECMAScript 2015** 的術語）。通常，呼叫 **BF** 會執行該 **wrapped function**。**BF** 含有以下內部屬性：

* **[[BoundTargetFunction]]** - the wrapped function object;
* **[[BoundThis]]** - the value that is always passed as **this** value when calling the wrapped function.
* **[[BoundArguments]]** - a list of values whose elements are used as the first arguments to any call to the wrapped function.
* **[[Call]]** - executes code associated with this object. Invoked via a function call expression. The arguments to the internal method are a **this** value and a list containing the arguments passed to the function by a call expression.

When bound function is called, it calls internal method **[[Call]]** on **[[BoundTargetFunction]],** with following arguments **Call(*boundThis*, *args*).** Where, ***boundThis*** is **[[BoundThis]]**, **args** is **[[BoundArguments]]** followed by the arguments passed by the function call.

A bound function may also be constructed using the `new` operator: doing so acts as though the target function had instead been constructed. The provided **`this`** value is ignored, while prepended arguments are provided to the emulated function.

範例
--

### 建立綁定函式

The simplest use of `bind()` is to make a function that, no matter how it is called, is called with a particular **`this`** value. A common mistake for new JavaScript programmers is to extract a method from an object, then to later call that function and expect it to use the original object as its `this` (e.g. by using that method in callback-based code). Without special care, however, the original object is usually lost. Creating a bound function from the function, using the original object, neatly solves this problem:

```js
this.x = 9; // this refers to global "window" object here in the browser
var module = {
  x: 81,
  getX: function () {
    return this.x;
  },
};

module.getX(); // 81

var retrieveX = module.getX;
retrieveX();
// returns 9 - The function gets invoked at the global scope

// Create a new function with 'this' bound to module
// New programmers might confuse the
// global var x with module's property x
var boundGetX = retrieveX.bind(module);
boundGetX(); // 81
```

### Partially applied functions

The next simplest use of `bind()` is to make a function with pre-specified initial arguments. These arguments (if any) follow the provided `this` value and are then inserted at the start of the arguments passed to the target function, followed by the arguments passed to the bound function, whenever the bound function is called.

```js
function list() {
  return Array.prototype.slice.call(arguments);
}

var list1 = list(1, 2, 3); // [1, 2, 3]

// Create a function with a preset leading argument
var leadingThirtysevenList = list.bind(null, 37);

var list2 = leadingThirtysevenList();
// [37]

var list3 = leadingThirtysevenList(1, 2, 3);
// [37, 1, 2, 3]
```

### 配合 `setTimeout`

By default within `window.setTimeout()` (en-US), the `this` keyword will be set to the `window` (en-US) (or `global`) object. When working with class methods that require `this` to refer to class instances, you may explicitly bind `this` to the callback function, in order to maintain the instance.

```js
function LateBloomer() {
  this.petalCount = Math.floor(Math.random() \* 12) + 1;
}

// Declare bloom after a delay of 1 second
LateBloomer.prototype.bloom = function () {
  window.setTimeout(this.declare.bind(this), 1000);
};

LateBloomer.prototype.declare = function () {
  console.log("I am a beautiful flower with " + this.petalCount + " petals!");
};

var flower = new LateBloomer();
flower.bloom();
// after 1 second, triggers the 'declare' method
```

### Bound functions used as constructors

**警告：** This section demonstrates JavaScript capabilities and documents some edge cases of the `bind()` method. The methods shown below are not the best way to do things and probably should not be used in any production environment.

Bound functions are automatically suitable for use with the `new` operator to construct new instances created by the target function. When a bound function is used to construct a value, the provided `this` is ignored. However, provided arguments are still prepended to the constructor call:

```js
function Point(x, y) {
  this.x = x;
  this.y = y;
}

Point.prototype.toString = function () {
  return this.x + "," + this.y;
};

var p = new Point(1, 2);
p.toString(); // '1,2'

// not supported in the polyfill below,

// works fine with native bind:

var YAxisPoint = Point.bind(null, 0 /\*x\*/);

var emptyObj = {};
var YAxisPoint = Point.bind(emptyObj, 0 /\*x\*/);

var axisPoint = new YAxisPoint(5);
axisPoint.toString(); // '0,5'

axisPoint instanceof Point; // true
axisPoint instanceof YAxisPoint; // true
new Point(17, 42) instanceof YAxisPoint; // true
```

Note that you need do nothing special to create a bound function for use with `new`. The corollary is that you need do nothing special to create a bound function to be called plainly, even if you would rather require the bound function to only be called using `new`.

```js
// Example can be run directly in your JavaScript console
// ...continuing from above

// Can still be called as a normal function
// (although usually this is undesired)
YAxisPoint(13);

emptyObj.x + "," + emptyObj.y;
// > '0,13'
```

If you wish to support the use of a bound function only using `new`, or only by calling it, the target function must enforce that restriction.

### Creating shortcuts

`bind()` is also helpful in cases where you want to create a shortcut to a function which requires a specific **`this`** value.

Take `Array.prototype.slice`, for example, which you want to use for converting an array-like object to a real array. You could create a shortcut like this:

```js
var slice = Array.prototype.slice;

// ...

slice.apply(arguments);
```

With `bind()`, this can be simplified. In the following piece of code, `slice` is a bound function to the `apply()` function of `Function.prototype` (en-US), with the **`this`** value set to the `slice()` function of `Array.prototype`. This means that additional `apply()` calls can be eliminated:

```js
// same as "slice" in the previous example
var unboundSlice = Array.prototype.slice;
var slice = Function.prototype.apply.bind(unboundSlice);

// ...

slice(arguments);
```

Polyfill
--------

You can partially work around this by inserting the following code at the beginning of your scripts, allowing use of much of the functionality of `bind()` in implementations that do not natively support it.

```js
if (!Function.prototype.bind) {
  Function.prototype.bind = function (oThis) {
    if (typeof this !== "function") {
      // closest thing possible to the ECMAScript 5
      // internal IsCallable function
      throw new TypeError(
        "Function.prototype.bind - what is trying to be bound is not callable",
      );
    }

    var aArgs = Array.prototype.slice.call(arguments, 1),
      fToBind = this,
      fNOP = function () {},
      fBound = function () {
        return fToBind.apply(
          this instanceof fNOP ? this : oThis,
          aArgs.concat(Array.prototype.slice.call(arguments)),
        );
      };

    if (this.prototype) {
      // Function.prototype doesn't have a prototype property
      fNOP.prototype = this.prototype;
    }
    fBound.prototype = new fNOP();

    return fBound;
  };
}
```

Some of the many differences (there may well be others, as this list does not seriously attempt to be exhaustive) between this algorithm and the specified algorithm are:

* The partial implementation relies on `Array.prototype.slice()`, `Array.prototype.concat()`, `Function.prototype.call()` and `Function.prototype.apply()`, built-in methods to have their original values.
* The partial implementation creates functions that do not have immutable "poison pill" `caller` (en-US) and `arguments` properties that throw a `TypeError` (en-US) upon get, set, or deletion. (This could be added if the implementation supports `Object.defineProperty`, or partially implemented [without throw-on-delete behavior] if the implementation supports the `Object.prototype.__defineGetter__()` (en-US) and `Object.prototype.__defineSetter__()` (en-US) extensions.)
* The partial implementation creates functions that have a `prototype` property. (Proper bound functions have none.)
* The partial implementation creates bound functions whose `length` property does not agree with that mandated by ECMA-262: it creates functions with length 0, while a full implementation, depending on the length of the target function and the number of pre-specified arguments, may return a non-zero length.

If you choose to use this partial implementation, **you must not rely on those cases where behavior deviates from ECMA-262, 5th edition!** With some care, however (and perhaps with additional modification to suit specific needs), this partial implementation may be a reasonable bridge to the time when `bind()` is widely implemented according to the specification.

Please check https://github.com/Raynos/function-bind for a more thorough solution!

規範
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-function.prototype.bind |

瀏覽器相容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

相關連結
----

* `Function.prototype.apply()`
* `Function.prototype.call()`
* Functions (en-US)


Date.prototype.valueOf() - JavaScript

Date.prototype.valueOf()
========================

**`valueOf()`** 方法回傳 `Date` 物件的原始值。

嘗試一下
----

語法
--

```js
valueOf()
```

### 返回值

從 1970 年 1 月 1 日 00:00:00 UTC 至給定日期之間的毫秒數，若為無效日期則回傳 `NaN` 。

描述
--

`valueOf()` 方法以數字型別回傳一 `Date` 物件的原始值，亦即自 1970 年 1 月 1 日 00:00:00 UTC 起所經過的毫秒數。

此方法在功能上相當於 `Date.prototype.getTime()` 。

通常此方法由 JavaScript 內部呼叫，而非明確寫在程式碼中。

範例
--

### 使用 valueOf()

```js
const x = new Date(56, 6, 17);
const myVar = x.valueOf(); // 指派 -424713600000 至 myVar
```

規範
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-date.prototype.valueof |

瀏覽器相容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

參見
--

* `Object.prototype.valueOf()` (en-US)
* `Date.prototype.getTime()`


Date.prototype.setUTCHours() - JavaScript

Date.prototype.setUTCHours()
============================

**`setUTCHours()`** 方法根據世界時設置指定日期的小時，並回傳自 1970 年 1 月 1 日 00:00:00 UTC 至更新的 `Date` 實例所表示的時間為止，經過的毫秒數。

嘗試一下
----

語法
--

```js
setUTCHours(hoursValue)
setUTCHours(hoursValue, minutesValue)
setUTCHours(hoursValue, minutesValue, secondsValue)
setUTCHours(hoursValue, minutesValue, secondsValue, msValue)
```

### 參數

`hoursValue`

一個表示小時、介於 0 至 23 之間的整數。

`minutesValue`

可選的。一個表示分鐘、介於 0 至 59 之間的整數。

`secondsValue`

可選的。一個表示秒數、介於 0 至 59 之間的整數。若給定 `secondsValue`，則必須同時給定 `minutesValue` 參數值。

`msValue`

可選的。一個表示毫秒數、介於 0 至 999 之間的數。若給定 `msValue` 的值，則必須同時給定 `minutesValue` 與 `secondsValue` 參數值。

### 返回值

1970 年 1 月 1 日 00:00:00 UTC 與更新日期之間的毫秒差異數。

描述
--

如果沒有指明 `minutesValue`、`secondsValue` 與 `msValue` 參數值，則會使用 `getUTCMinutes()`、`getUTCSeconds()`、`getUTCMilliseconds()` 方法回傳的值。

如果給定的參數值超出預期範圍，`setUTCHours()` 會相對應地更新 `Date` 物件的日期資訊。例如，`secondsValue` 傳入 100 ，分鐘數將增加 1（`minutesValue + 1`）、其餘的 40 則計入秒數。

範例
--

### 使用 setUTCHours()

```js
const theBigDay = new Date();
theBigDay.setUTCHours(8);
```

規範
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-date.prototype.setutchours |

瀏覽器相容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

參見
--

* `Date.prototype.getUTCHours()`
* `Date.prototype.setHours()`


Date.prototype.getUTCMinutes() - JavaScript

Date.prototype.getUTCMinutes()
==============================

**`getUTCMinutes()`** 方法根據世界時回傳指定日期的分鐘數。

嘗試一下
----

語法
--

```js
getUTCMinutes()
```

### 返回值

若 `Date` 物件為有效日期，則根據 UTC 時間回傳一個表示分鐘數、介於 0 至 59 之間的整數；若為無效日期，則回傳 `Number.NaN()` (en-US)。

範例
--

### 使用 getUTCMinutes()

下列範例指派當前時間的分鐘至變數 `minutes`。

```js
const today = new Date();
const minutes = today.getUTCMinutes();
```

規範
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-date.prototype.getutcminutes |

瀏覽器相容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

參見
--

* `Date.prototype.getMinutes()`
* `Date.prototype.setUTCMinutes()` (en-US)


Date.prototype.getMilliseconds() - JavaScript

Date.prototype.getMilliseconds()
================================

**`getMilliseconds()`** 方法基於本地時區回傳指定日期的毫秒數。

嘗試一下
----

語法
--

```js
getMilliseconds()
```

### 返回值

一個基於本地時區表示指定日期的毫秒數、介於 0 至 999 的整數值。

範例
--

### 使用 getMilliseconds()

下列範例將當前時間的毫秒數指派給變數 `milliseconds`。

```js
const today = new Date();
const milliseconds = today.getMilliseconds();
```

規範
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-date.prototype.getmilliseconds |

瀏覽器相容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

參見
--

* `Date.prototype.getUTCMilliseconds()`
* `Date.prototype.setMilliseconds()` (en-US)


Date.prototype.getSeconds() - JavaScript

Date.prototype.getSeconds()
===========================

**`getSeconds()`** 方法基於本地時區回傳指定日期的秒數。

嘗試一下
----

語法
--

```js
getSeconds()
```

### 返回值

一個基於本地時區表示指定日期的秒數、介於 0 至 59 的整數值。

範例
--

### 使用 getSeconds()

下方第二行陳述式將 `Date` 物件 `xmas95` 的值 30，指派給變數 `seconds`。

```js
const xmas95 = new Date("December 25, 1995 23:15:30");
const seconds = xmas95.getSeconds();

console.log(seconds); // 30
```

規範
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-date.prototype.getseconds |

瀏覽器相容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

參見
--

* `Date.prototype.getUTCSeconds()`
* `Date.prototype.setSeconds()` (en-US)


Date.prototype.setHours() - JavaScript

Date.prototype.setHours()
=========================

**`setHours()`** 方法基於本地時區設置指定日期的小時，並回傳自 1970 年 1 月 1 日 00:00:00 UTC 起至更新的 `Date` 實例所表示的時間為止，共經過的毫秒數。

嘗試一下
----

語法
--

```js
setHours(hoursValue)
setHours(hoursValue, minutesValue)
setHours(hoursValue, minutesValue, secondsValue)
setHours(hoursValue, minutesValue, secondsValue, msValue)
```

### 參數

`hoursValue`

表示小時，理想上為介於 0 至 23 之間的整數。若傳入的值大於 23，溢出時數會增加日期時間。

`minutesValue`

可選的。表示分鐘，理想上為介於 0 至 59 之間的整數。若傳入的值大於 59，溢出分鐘數會增加日期時間。

`secondsValue`

可選的。表示秒，理想上為介於 0 至 59 之間的整數。若傳入的值大於 59，溢出秒數會增加日期時間。若給定 `secondsValue`，則必須同時給定 `minutesValue` 參數值。

`msValue`

可選的。表示毫秒，理想上為介於 0 至 999 之間的數。若傳入的值大於 999，溢出毫秒數會增加日期時間。若給定 `msValue` 的值，則必須同時給定 `minutesValue` 與 `secondsValue` 參數值。

### 返回值

1970 年 1 月 1 日 00:00:00 UTC 與更新日期之間的毫秒差異數。

描述
--

如果沒有指明 `minutesValue`、`secondsValue` 與 `msValue` 參數值，則會使用 `getMinutes()`、`getSeconds()`、`getMilliseconds()` 方法回傳的值。

如果給定的參數值超出預期範圍，`setHours()` 會相對應地更新 `Date` 物件的日期資訊。例如，`secondsValue` 傳入 100 ，分鐘數將增加 1（`minutesValue + 1`）、其餘的 40 則計入秒數。

範例
--

### 使用 setHours()

```js
const theBigDay = new Date();
theBigDay.setHours(7);
```

規範
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-date.prototype.sethours |

瀏覽器相容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

參見
--

* `Date.prototype.getHours()`
* `Date.prototype.setUTCHours()`


Date.prototype.getDay() - JavaScript

Date.prototype.getDay()
=======================

**`getDay()`** 方法會根據當地時間將指定日期返回一星期中的第幾天，其中 0 代表星期日。 在當月的某天可以參考`Date.prototype.getDate()` (en-US)。

嘗試一下
----

語法
--
```

dateObj.getDay()
```

### 返回值

返回一個整數，數值介於 0 到 6 之間，取決於當地時間對應出指定日期為星期幾:0 代表星期日，1 代表星期一，2 代表星期二，依此類推。

範例
--

### 使用 `getDay()`

下面第二行表示根據日期對象'Xmas95'的值，把 1 賦值給'weekday'。則 1995 年 12 月 25 日是星期一。

```js
var Xmas95 = new Date("December 25, 1995 23:15:30");
var weekday = Xmas95.getDay();

console.log(weekday); // 1
```

**備註：** 如果需要，可以使用`Intl.DateTimeFormat` (en-US)加上`options`參數來獲取星期幾全名。使使用此方法能輕鬆做出各種國際語言：

```js
var options = { weekday: "long" };
console.log(new Intl.DateTimeFormat("en-US", options).format(Xmas95));
// Monday
console.log(new Intl.DateTimeFormat("de-DE", options).format(Xmas95));
// Montag
```

規範
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-date.prototype.getday |

瀏覽器兼容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

參見
--

* `Date.prototype.getUTCDate()` (en-US)
* `Date.prototype.getUTCDay()` (en-US)
* `Date.prototype.setDate()` (en-US)


Date.prototype.getUTCHours() - JavaScript

Date.prototype.getUTCHours()
============================

**`getUTCHours()`** 方法根據世界時回傳指定日期的小時數。

嘗試一下
----

語法
--

```js
getUTCHours()
```

### 返回值

若 `Date` 物件為有效日期，則根據 UTC 時間回傳一個表示小時、介於 0 至 23 之間的整數；若為無效日期，則回傳 `Number.NaN()` (en-US)。

範例
--

### 使用 getUTCHours()

下列範例指派當前時間的小時至變數 `hours`。

```js
const today = new Date();
const hours = today.getUTCHours();
```

規範
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-date.prototype.getutchours |

瀏覽器相容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

參見
--

* `Date.prototype.getHours()`
* `Date.prototype.setUTCHours()`


Date.prototype.getTime() - JavaScript

Date.prototype.getTime()
========================

**`getTime()`** 方法回傳自 1970 年 1 月 1 日 00:00:00 UTC 起經過的毫秒數。

你可以透過此方法指派一日期與時間至另一 `Date` 物件。這個方法在功能上與 `valueOf()` 相同。

嘗試一下
----

語法
--

```js
getTime()
```

### 返回值

一個表示自 1970 年 1 月 1 日 00:00:00 UTC 至給定日期為止，所經過的毫秒數。

描述
--

`new Date().getTime()` 的精確度可能會依瀏覽器設定而做取捨，以防止時序攻擊（timing attack）與指紋辨識（fingerprinting）。如 Firefox 預設會開啟 `privacy.reduceTimerPrecision`，在 Firefox 59 預設為 20µs、Firefox 60 為 2ms。

```js
// 在 Firefox 60 中降低的時間精確度（2ms）
new Date().getTime();
// 1519211809934
// 1519211810362
// 1519211811670
// …

// 啟用 `privacy.resistFingerprinting` 而降低的時間精確度
new Date().getTime();
// 1519129853500
// 1519129858900
// 1519129864400
// …
```

 Firefox 內也可以啟用 `privacy.resistFingerprinting`，將擇 100ms 或
 `privacy.resistFingerprinting.reduceTimerPrecision.microseconds` 的值當中較大者調整精確度。

範例
--

### 使用 `getTime()` 複製日期

建構一個相同時間值的日期物件。

```js
// 因為月份是從零開始，故 birthday 將為 1995 年 1 月 10 日
const birthday = new Date(1994, 12, 10);
const copy = new Date();
copy.setTime(birthday.getTime());
```

### 測量執行時間

在兩個新建立的 `Date` 物件接連呼叫 `getTime()` 方法，並相減兩者返回時間。可透過此法計算某些操作的執行時間。參見 `Date.now()` 以避免產生非必要的 `Date` 物件。

```js
let end, start;

start = new Date();
for (let i = 0; i < 1000; i++) {
  Math.sqrt(i);
}
end = new Date();

console.log(`Operation took ${end.getTime() - start.getTime()} msec`);
```

規範
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-date.prototype.gettime |

瀏覽器相容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

參見
--

* `Date.prototype.setTime()`
* `Date.prototype.valueOf()`
* `Date.now()`


Date.parse() - JavaScript

Date.parse()
============

**`Date.parse()`** 方法解析一表示日期的字串，並回傳自 1970 年 01 月 01 日 00:00:00 UTC 起至該日期共經過的毫秒數；如果字串無法辨識或包含無效值（如：2015-02-31），則回傳 `NaN`。

只有 ISO 8601 格式（ `YYYY-MM-DDTHH:mm:ss.sssZ`）為明確指定支援的格式。其餘格式因實作方式而異，不一定跨瀏覽器通用。若需要涵蓋多種格式，可以引入函式庫協助。

嘗試一下
----

語法
--

```js
Date.parse(dateString)
```

參數
--

`dateString`

一個簡化表示 ISO 8601 日曆日期延伸格式的字串。（亦可使用其他格式，但結果會依實作方式而定。）

### 返回值

一個自 1970 年 01 月 01 日 00:00:00 UTC 起，至解析字串而得的日期為止，所經過的毫秒數值。如果該參數並非有效日期，則回傳 `NaN` 。

描述
--

`parse()` 方法接受一日期字串（例如： `"2011-10-10T14:48:00"`）並回傳自 1970 年 01 月 01 日 00:00:00 UTC 至該日期所經過的毫秒數。

此函式實用於設定日期，例如結合使用 `setTime()` 方法與 `Date` 物件。

### 日期字串格式

呈現日期時間的標準字串格式乃 ISO 8601 日曆日期延伸格式的簡化版。（詳細請參見 ECMAScript 規範的 Date Time String Format章節）

例如，`"2011-10-10"`（*只有日期*）、`"2011-10-10T14:48:00"`（*日期與時間*），或 `"2011-10-10T14:48:00.000+09:00"`（*日期與時間至毫秒級以及時區*）皆可作為有效參數傳入並解析。如果沒有指明時差，只有日期的參數會假設為 UTC 時間，而有日期與時間的參數會當作是本地時間。

解析日期字串的過程雖然會加註時區，但回傳值必定是從 1970 年 01 月 01 日 00:00:00 UTC 起至該參數表示的日期為止，所經過的毫秒數；或是 `NaN`。

 因為 `parse()` 是 `Date` 的靜態方法，故會以
 `Date.parse()` 而非作為 `Date` 實例的方法呼叫。

### 退回至實作定義的日期格式

**備註：** 此段落包含因實作而異的行為，不同實作間可能不一致。

ECMAScript 規範表明：如果字串不符合標準格式，函式可能會退回至實作定義的啟發式或解析演算法。無法辨識的字串或包含無效值的 ISO 格式字串將使 `Date.parse()` 回傳 `NaN`。

不過無效且非 ECMA-262 定義的 ISO 格式的日期字串，其回傳結果會依瀏覽器與實際值而異，不一定回傳 `NaN`，例如：

```js
// 非 ISO 字串且含無效日期值
new Date("23/25/2014");
```

在 Firefox 30 當中會被視為本地時間的 2015 年 11 月 25 日，而 Safari 7 中則為無效日期。

但如果為 ISO 格式的字串而包含無效值，則會回傳 `NaN`：

```js
// ISO 字串且含無效日期值
new Date("2014-25-23").toISOString();
// throws "RangeError: invalid date"
```

SpiderMonkey 的實作啟發可見 `jsdate.cpp`。例如 `"10 06 2014"` 即不符合 ISO 格式，故會執行自定義解析。參見 rough outline 以瞭解運作原理。

```js
new Date("10 06 2014");
```

會被視為本地時間的 2014 年 10 月 06 日 而非 2014 年 06 月 10 日。

其他範例：

```js
new Date("foo-bar 2014").toString();
// returns: "Invalid Date"

Date.parse("foo-bar 2014");
// returns: NaN
```

### 假定時區上的差異

**備註：** 此段落包含因實作而異的行為，不同實作間可能不一致。

給定一非標準的字串 `"March 7, 2014"`，`parse()` 會假定為本地時區；但如果是簡化版的 ISO 8601 日曆日期延伸格式的字串，如 `"2014-03-07"`，則會假定為 UTC 時區。故，除非系統為 UTC 時區，否則依支援的 ECMAScript 版本，由該字串產生的 `Date` 物件可能呈現不同時間。亦即兩個看似相等的日期字串，依傳入的格式而可能產生不同解析結果。

範例
--

### 使用 Date.parse()

下列呼叫皆會回傳 `1546300800000`。第一個隱含為 UTC 時間，其餘則以 ISO 日期規範（`Z` 與 `+00:00`）明確表示 UTC 時區。

```js
Date.parse("2019-01-01");
Date.parse("2019-01-01T00:00:00.000Z");
Date.parse("2019-01-01T00:00:00.000+00:00");
```

以下呼叫並未指明時區，將會設定為使用者系統時區的 2019-01-01 00:00:00。

```js
Date.parse("2019-01-01T00:00:00");
```

### 非標準的日期字串

**備註：** 此段落包含因實作而異的行為，不同實作間可能不一致。

若 `ipoDate` 為既有的 `Date` 物件，可將其設定為本地時間的 1995-08-09，如下：

```js
ipoDate.setTime(Date.parse("Aug 9, 1995"));
```

其他解析非標準日期字串的範例：

```js
Date.parse("Aug 9, 1995");
```

因為此字串未指明時區、且並非 ISO 格式，故預設為本地時區。如在 GMT-0300 時區回傳 `807937200000`，其他時區另計。

```js
Date.parse("Wed, 09 Aug 1995 00:00:00 GMT");
```

因為已指明 GMT (UTC) 時區，不論本地時區為何，皆回傳 `807926400000`。

```js
Date.parse("Wed, 09 Aug 1995 00:00:00");
```

因為參數內沒有指明時區，而且並非 ISO 格式，因此視為本地時間。在 GMT-0300 時區會回傳 `807937200000`，其他時區另計。

```js
Date.parse("Thu, 01 Jan 1970 00:00:00 GMT");
```

因為已指明 GMT (UTC) 時區，不論本地時區為何，皆回傳 `0`。

```js
Date.parse("Thu, 01 Jan 1970 00:00:00");
```

因為此字串未指明時區、且並非 ISO 格式，故預設為本地時區。如在 GMT-0400 回傳 `14400000`，其他時區另計。

```js
Date.parse("Thu, 01 Jan 1970 00:00:00 GMT-0400");
```

因為已指明 GMT (UTC) 時區，不論本地時區為何，皆回傳 `14400000`。

規範
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-date.parse |

瀏覽器相容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

### 相容性資訊

* Firefox 49 將解析兩位數年份的方式從與 Internet Explorer 改為與 Google Chrome 一致。現在小於 `50` 的兩位數年份會解析為 21 世紀年份。例如 `04/16/17`，先前會視為 1917 年 04 月 16 日；現在則解析為 2017 年 04 月 16 日。建議使用 ISO 8601 格式如 `"2017-04-16"`，以避免任何互通性問題或不明確的年份。（bug 1265136）
* Google Chrome 視數字字串為有效的 `dateString` 參數。例如 `!!Date.parse("42")` 在 Firefox 會評估為 `false`，而在 Google Chrome 會評估為 `true`；因為 `"42"` 被當作是 2042 年 01 月 01 日。
參見
--

* `Date.UTC()`


Date.prototype.setTime() - JavaScript

Date.prototype.setTime()
========================

**`setTime()`** 方法將從 1970 年 01 月 01 日 00:00:00 UTC 起所經過的毫秒數設置為 `Date` 物件的值。

嘗試一下
----

語法
--

```js
setTime(timeValue)
```

### 參數

`timeValue`

一個整數，表示自 1970 年 01 月 01 日 00:00:00 UTC 起所經過的毫秒數。

### 返回值

1970 年 01 月 01 日 00:00:00 UTC 與更新日期之間的毫秒數（實際上是參數值）。

描述
--

以 `setTime()` 方法指派一日期與時間至另一 `Date` 物件。

範例
--

### 使用 setTime()

```js
const theBigDay = new Date("July 1, 1999");
const sameAsBigDay = new Date();
sameAsBigDay.setTime(theBigDay.getTime());
```

規範
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-date.prototype.settime |

瀏覽器相容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

參見
--

* `Date.prototype.getTime()`
* `Date.prototype.setUTCHours()`


Date.now() - JavaScript

Date.now()
==========

**`Date.now()`** 方法回傳自 1970/01/01 00:00:00 UTC 起經過的毫秒數。

格式
--
```

var timeInMs = Date.now();
```

### 回傳值

一個代表由經 UNIX 紀元起經過的毫秒數值（`Number`）。

描述
--

由於 `now()` 是 `Date` 的靜態方法，你只能用 `Date.now()` 的方式呼叫它。

補完
--

這個函數是 ECMA-262 第 5 版的標準。 對於未更新支援此方法的引擎，可以利用底下的程式補上：

```js
if (!Date.now) {
  Date.now = function now() {
    return new Date().getTime();
  };
}
```

規範
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-date.now |

瀏覽器相容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

相關資源
----

* `Performance.now()` (en-US) — 提供亞毫秒級的時間戳記，作為評估網頁效能的解決方案。
* `console.time()` (en-US) / `console.timeEnd()` (en-US)


Date.prototype.getMinutes() - JavaScript

Date.prototype.getMinutes()
===========================

**`getMinutes()`** 方法基於本地時區回傳指定日期的分鐘數。

嘗試一下
----

語法
--

```js
getMinutes()
```

### 返回值

一個基於本地時區表示指定日期的分鐘數、介於 0 至 59 的整數值。

範例
--

### 使用 getMinutes()

下方第二行陳述式將 `Date` 物件 `xmas95` 的值 15，指派給變數 `minutes`。

```js
const xmas95 = new Date("December 25, 1995 23:15:30");
const minutes = xmas95.getMinutes();

console.log(minutes); // 15
```

規範
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-date.prototype.getminutes |

瀏覽器相容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

參見
--

* `Date.prototype.getUTCMinutes()`
* `Date.prototype.setMinutes()` (en-US)


Date.prototype.getUTCMilliseconds() - JavaScript

Date.prototype.getUTCMilliseconds()
===================================

**`getUTCMilliseconds()`** 方法根據世界時回傳指定日期的毫秒數。

嘗試一下
----

語法
--

```js
getUTCMilliseconds()
```

### 返回值

若 `Date` 物件為有效日期，則根據 UTC 時間回傳一個表示毫秒數、介於 0 至 999 之間的整數；若為無效日期，則回傳 `Number.NaN()` (en-US)。

別與 Unix 時間搞混了。應使用 `Date.prototype.getTime()` 方法取得自 1970/01/01 起經過的毫秒數。

範例
--

### 使用 getUTCMilliseconds()

下列範例指派當前時間的毫秒數至變數 `milliseconds` 。

```js
const today = new Date();
const milliseconds = today.getUTCMilliseconds();
```

規範
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-date.prototype.getutcmilliseconds |

瀏覽器相容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

參見
--

* `Date.prototype.getMilliseconds()`
* `Date.prototype.setUTCMilliseconds()` (en-US)


Date.UTC() - JavaScript

Date.UTC()
==========

**`Date.UTC()`** 方法接受與建構子相同長度的參數，將參數視為通用時間（UTC）來計算回傳由 1970-01-01 00:00:00 UTC 所經過的毫秒數。

格式
--
```

Date.UTC(year, month[, day[, hour[, minute[, second[, millisecond]]]]])
```

### 參數

`year`

1900 年後的年份。

`month`

月份，介於 0 到 11 之間。

`day`

選用。月份中的日期，介於 1 到 31 之間。

`hour`

選用。小時，介於 0 到 23 之間。

`minute`

選用。分鐘數，介於 0 到 59 之間。

`second`

選用。秒數，介於 0 到 59 之間。

`millisecond`

選用。毫秒數 0 到 999 之間。

### 回傳值

得到傳入這個 `Date` 方法的參數所代表時間，與 1970-01-01 00:00:00 UTC 相差的毫秒數。

描述
--

`UTC()` 取得以逗號分隔的時間參數，回傳 1970-01-01 00:00:00 UTC 與該時間相差的毫秒數。

你應該指定完成的年份資料，例如： 1998。如果一個 0 到 99 的年份被指定，這個方法會將它轉換為 20 世紀的年份（變為 19xx 年），例如你傳入 95 ，則會被當作 1995 年被指定。

這個 `UTC()` 方法與 `Date` 建構子有兩個地方不同。

* `Date.UTC()` 使用 UTC 時區而不是當地時區。
* `Date.UTC()` 回傳一個數值而不是 `Date` 物件。

當你指定參數超出預期的範圍， UTC( ) 方法會去調整其它的參數使之成立。比如如果你指定月份為 15 ，年份將被加 1 ，以 3 作為傳入的月份。

因為 UTC( ) 是 `Date` 的一個靜態方法，只能使用 `Date.UTC()` 的方式呼叫，而不能由建立出來的 `Date` 物件去執行它。

範例
--

### 使用 `Date.UTC()`

以下利用它來將指定的時間以 UTC 而非本地時間的方式來建立 `Date` 物件：

```js
var utcDate = new Date(Date.UTC(96, 11, 1, 0, 0, 0));
```

規範
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-date.utc |

瀏覽器相容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

相關資源
----

* `Date.parse()`


Date.prototype.getUTCSeconds() - JavaScript

Date.prototype.getUTCSeconds()
==============================

**`getUTCSeconds()`** 方法根據世界時回傳指定日期的秒數。

嘗試一下
----

語法
--

```js
getUTCSeconds()
```

### 返回值

若 `Date` 物件為有效日期，則根據 UTC 時間回傳一個表示秒數、介於 0 至 59 之間的整數；若為無效日期，則回傳 `Number.NaN()` (en-US)。

範例
--

### 使用 getUTCSeconds()

下列範例指派當前時間的秒數至變數 `seconds`。

```js
const today = new Date();
const seconds = today.getUTCSeconds();
```

規範
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-date.prototype.getutcseconds |

瀏覽器相容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

參見
--

* `Date.prototype.getSeconds()`
* `Date.prototype.setUTCSeconds()` (en-US)


Date.prototype.getHours() - JavaScript

Date.prototype.getHours()
=========================

**`getHours()`** 方法基於本地時區回傳指定日期的小時數。

嘗試一下
----

語法
--

```js
getHours()
```

### 返回值

一個基於本地時區表示指定日期的小時、介於 0 至 23 的整數值。

範例
--

### 使用 getHours()

下方第二行陳述式將 `Date` 物件 `xmas95` 的值 23，指派給變數 `hours`。

```js
const xmas95 = new Date("December 25, 1995 23:15:30");
const hours = xmas95.getHours();

console.log(hours); // 23
```

規範
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-date.prototype.gethours |

瀏覽器相容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

參見
--

* `Date.prototype.getUTCHours()`
* `Date.prototype.setHours()`


Number.prototype.toFixed() - JavaScript

Number.prototype.toFixed()
==========================

**`toFixed()`** 方法會使用定點小數表示法（fixed-point notation）來格式化數字。

嘗試一下
----

語法
--

```js
numObj.toFixed([digits])
```

### 參數

`digits 小數位`

選擇性輸入。顯示數值至多少個小數點，範圍由 0 到 20 之間，執行時或可支援非常大範圍的數值。如果無輸入會默認做 0。

### 回傳值

一個代表以定點小數表示法（fixed-point notation）格式化數字後的字串。

### 例外

`RangeError`

If `digits` is too small or too large. Values between 0 and 100, inclusive, will not cause a `RangeError`. Implementations are allowed to support larger and smaller values as chosen.

`TypeError` (en-US)

If this method is invoked on an object that is not a `Number`.

說明
--

**`toFixed()`** returns a string representation of `numObj` that does not use exponential notation and has exactly `digits` digits after the decimal place. The number is rounded if necessary, and the fractional part is padded with zeros if necessary so that it has the specified length. If `numObj` is greater than `1e+21`, this method simply calls `Number.prototype.toString()` (en-US) and returns a string in exponential notation.

範例
--

### Using `toFixed`

```js
var numObj = 12345.6789;

numObj.toFixed(); // Returns '12346': note rounding, no fractional part
numObj.toFixed(1); // Returns '12345.7': note rounding
numObj.toFixed(6); // Returns '12345.678900': note added zeros
(1.23e20).toFixed(2); // Returns '123000000000000000000.00'
(1.23e-10).toFixed(2); // Returns '0.00'
(2.34).toFixed(1); // Returns '2.3'
(2.35).toFixed(1); // Returns '2.4'. Note that it rounds up in this case.
-(2.34).toFixed(1); // Returns -2.3 (due to operator precedence, negative number literals don't return a string...)
(-2.34).toFixed(1); // Returns '-2.3' (...unless you use parentheses)
```

規範
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-number.prototype.tofixed |

瀏覽器相容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

參見
--

* `Number.prototype.toExponential()`
* `Number.prototype.toPrecision()` (en-US)
* `Number.prototype.toString()` (en-US)


Number.prototype.toExponential() - JavaScript

Number.prototype.toExponential()
================================

**`toExponential()`** method 用來將數字轉成「科學記數法」格式。

語法
--

```js
numObj.toExponential([fractionDigits])
```

### 參數

| 參數 | 可選 | 默認值 | 類型 | 說明 |
| --- | --- | --- | --- | --- |
| `fractionDigits` | ● | 默認盡可能將數字完整顯示 | `Number`（正整數） | 小數點後的位數。需為 0 至 20 之間。 |

### 回傳值

一 string，將數字以「科學計數法」格式表示出來

### Exceptions

`RangeError`

若 `fractionDigits` 超出範圍（可接受的範圍是 0 ～ 20 之間的正整數）觸發 `RangeError`。

`TypeError` (en-US)

若參數 `fractionDigits` 不是 `Number`，則觸發`TypeError` (en-US)。

Description
-----------

If the `fractionDigits` argument is omitted, the number of digits after the decimal point defaults to the number of digits necessary to represent the value uniquely.

If you use the `toExponential()` method for a numeric literal and the numeric literal has no exponent and no decimal point, leave whitespace(s) before the dot that precedes the method call to prevent the dot from being interpreted as a decimal point.

If a number has more digits than requested by the `fractionDigits` parameter, the number is rounded to the nearest number represented by `fractionDigits` digits. See the discussion of rounding in the description of the `toFixed()` method, which also applies to `toExponential()`.

範例
--

### Using `toExponential`

```js
var numObj = 77.1234;

console.log(numObj.toExponential()); // logs 7.71234e+1
console.log(numObj.toExponential(4)); // logs 7.7123e+1
console.log(numObj.toExponential(2)); // logs 7.71e+1
console.log((77.1234).toExponential()); // logs 7.71234e+1
console.log((77).toExponential()); // logs 7.7e+1
```

規範
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-number.prototype.toexponential |

瀏覽器相容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

參見
--

* `Number.prototype.toFixed()`
* `Number.prototype.toPrecision()` (en-US)
* `Number.prototype.toString()` (en-US)


可選串連 - JavaScript

可選串連
====

**可選串連**運算子 **`?.`** 允許進行深層次的物件值存取，而無需透過明確的物件值串連驗證。`?.` 運算子的操作與 `.` 屬性存取運算子相似，後者會在參照到 nullish (en-US) (`null` (en-US) or `undefined` (en-US)) 的值時出現錯誤，而前者可選串連則回傳 `undefined` 。 當需要存取一個函數，而這函數並不存在時，則會回傳 `undefined` 。

當有機會存在參照不存在的時候，可選串連可以提供更簡短的表述式來進行串連性的屬性存取。這有助於在無法保證物件屬性為必要存在的狀況下，進行物件內容的探索。

嘗試一下
----

語法
--
```

obj?.prop
obj?.[expr]
arr?.[index]
func?.(args)
```

描述
--

當串連物件裡面的參照或方法可能是`undefined` 或 `null` 時，可選串連運算子提供簡單的方法去存取這些串連物件下的值。

舉例來說，當一個物件 `obj` 是巢狀結構時，在沒有可選串連之下，要去查找一深層的屬性值需要驗證每層間的參照連結：

```js
let nestedProp = obj.first && obj.first.second;
```

`obj.first` 的值需要先確定不是 `null` 值（和並非 `undefined` ），才能存取 `obj.first.second` 的值。這才能避免在存取值時，因為直接使用 `obj.first.second` 而沒有測試 `obj.first` 之下帶來的錯誤。

當使用了可選串連運算子（`?.`），你不再需要明確地進行測測，並能在基於 `obj.first` 的狀態下直接回傳，忽略存取 `obj.first.second` 的動作：

```js
let nestedProp = obj.first?.second;
```

從只是 `.` 改用作 `?.` 運算子，JavaScript 會知道在存取 `obj.first.second` 之前，需要間接地檢查並確保 `obj.first` 並不是 `null` 或 `undefined` 。當 `obj.first` 是 `null` 或 `undefined` ，運算式會像短路一樣跳過整個串連存取式，而回傳 `undefined` 。

這是跟以下是相等同的，但是實際上是不會建立臨時變數：

```js
let temp = obj.first;
let nestedProp = temp === null || temp === undefined ? undefined : temp.second;
```

### 可選串連呼叫函數

你可以使用可選串連來嘗試呼叫一個或許沒有存在的方法。這可能有助於，舉例來說，使用一些未能提供服務的 API ，這可能因為過時的應用或是使用者的裝置未能支援某種功能。

當需要使用的方法並不存在時，透過可選串連去進行呼叫將不會抛出錯誤，取而代之的是回傳 `undefined` ：

```js
let result = someInterface.customMethod?.();
```

**備註：** 假如物件有同樣的屬性名稱，而不是一個方法，使用 `?.` 將會抛出 `TypeError` (en-US) 錯誤（`x.y 不是一個函數`）。

#### 處理回呼函式或事件處理器

如果你使用回呼函式，或是透過解構賦值來擷取物件中的方法，你可能會因為這些方法沒有存在，而無法進行呼叫，除非你事先驗證其存在性。所以，你可以利用 `?.` 來避免這樣的測試：

```js
// 在 ES2019 下撰寫
function doSomething(onContent, onError) {
  try {
    // ... 對資料進行一些處理
  } catch (err) {
    if (onError) {
      // 測試 onError 是否真的存在
      onError(err.message);
    }
  }
}
```

```js
// 使用可選串連進行函式呼叫
function doSomething(onContent, onError) {
  try {
    // ... 對資料進行一些處理
  } catch (err) {
    onError?.(err.message); // 就算 onError 是 undefined 也不會抛出錯誤
  }
}
```

### 可選串連表述式

你也可以在方括號屬性存取 (en-US)表達式中使用可選串連：

```js
let nestedProp = obj?.["prop" + "Name"];
```

### 矩陣項目的可選串連

```js
let arrayItem = arr?.[42];
```

範例
--

### 基本範例

這個範例會找出 Map 物件中一個鍵為 `bar` 成員的 `name` 屬性值，但事實上並沒有相關成員。所以結果為 `undefined` 。

```js
let myMap = new Map();
myMap.set("foo", { name: "baz", desc: "inga" });

let nameBar = myMap.get("bar")?.name;
```

### 短路式運算

當可選串連接上表述式時，如果左邊的運算數值是 `null` 或 `undefined` ，表述式則不會被運算。舉例來說：

```js
let potentiallyNullObj = null;
let x = 0;
let prop = potentiallyNullObj?.[x++];

console.log(x); // 因為 x 沒有遞增，所以為 0
```

### 串接多個可選串連

在巢狀結構中可以使用多次的可選串連：

```js
let customer = {
  name: "Carl",
  details: {
    age: 82,
    location: "Paradise Falls", // 詳細地址 address 並不知道
  },
};
let customerCity = customer.details?.address?.city;

// … 同樣地，串接多個可選串連來呼叫函式也是湊效的
let duration = vacations.trip?.getTime?.();
```

### 使用空值合併運算子

在可選串連後可以使用空值合併運算子 (en-US)來編配預設值，如果無法在屬性串連中取得值：

```js
let customer = {
  name: "Carl",
  details: { age: 82 },
};
const customerCity = customer?.city ?? "Unknown city";
console.log(customerCity); // Unknown city
```

規範
--

| Specification |
| --- |
| ECMAScript Language Specification # prod-OptionalExpression |

瀏覽器相容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

參見
--

* 空值合併運算子 (en-US)
* TC39 proposals