Object.defineProperty() - JavaScript

Object.defineProperty()
=======================

靜態方法 **`Object.defineProperty()`** 會直接對一個物件定義、或是修改現有的屬性。執行後會回傳定義完的物件。

**備註：** 這個方法會直接針對 `Object` (en-US) 呼叫建構子（constructor），而不是 `Object` 型別的實例。

嘗試一下
----

語法
--

```js
Object.defineProperty(obj, prop, descriptor)
```

### 參數

`obj`

要定義屬性的物件。

`prop`

要被定義或修改的屬性名字。

`descriptor`

要定義或修改物件敘述內容。

### 回傳值

被定義完或修改完屬性的物件。

描述
--

這個函式可以用來增加或修改物件中的屬性定義。在物件建立屬性後，這些屬性同時有被設定預設的設定，才能讓這些屬性被列舉、改變和刪除。而這個函式可以用來改變這些預設的設定。根據預設，被加到物件且使用`Object.defineProperty()`的值都是Immutable。

物件內的屬性描述器（Property descriptor）主要有兩種：資料描述器（data descriptor）與訪問描述器（accessor descriptor）。*資料描述器*（data descriptor）是可以選擇能否覆寫的屬性。*訪問描述器*（accessor descriptor） is a property described by a getter-setter pair of functions. A descriptor must be one of these two flavors; it cannot be both.

data 和 accessor descriptors 皆為物件，兩者共享下面提及的 key：

`configurable`

`true` 則若且唯若此屬性則將可改變或刪除自相應物件。
 **預設為 `false`**

`enumerable`

`true` 如果且唯若相應物件被列舉，將會列舉此屬性。
 **預設為 `false`**

一個 data descriptor 還有以下可選的 key：

`value`

 The value associated with the property. Can be any valid JavaScript value (number, object, function, etc).
 **預設 `undefined` (en-US).**

`writable`

`true` 則該物件屬性可透過賦予運算子 (en-US)改變其值。
 **預設 `false`**

一個 accessor descriptor 也擁有下述之 optional keys:

`get`

 作為 getter 形式，為屬性存在的函式，如果沒有 getter 的話則回傳 `undefined` (en-US)。函式回傳將用於屬性值。
 **預設 `undefined` (en-US)**

`set`

 作為 setter 形式，為屬性存在的函式，如果沒有 setter 的話則回傳 `undefined` (en-US)。 The function will receive as only argument the new value being assigned to the property.
 **預設 `undefined` (en-US)**

請注意，這些選項並不一定要是 descriptor 屬性，由原型鍊（prototype chain）繼承的屬性，也會被考慮到。要確保需要凍結（freeze）的 `Object.prototype` (en-US) upfront 預設能被保存，請明確指定所有選項，或把 `Object.prototype.__proto__` (en-US) 屬性指向 `null` (en-US)。

```js
// using \_\_proto\_\_
var obj = {};
Object.defineProperty(obj, "key", {
  \_\_proto\_\_: null, // no inherited properties
  value: "static", // not enumerable
  // not configurable
  // not writable
  // as defaults
});

// being explicit
Object.defineProperty(obj, "key", {
  enumerable: false,
  configurable: false,
  writable: false,
  value: "static",
});

// recycling same object
function withValue(value) {
  var d =
    withValue.d ||
    (withValue.d = {
      enumerable: false,
      writable: false,
      configurable: false,
      value: null,
    });
  d.value = value;
  return d;
}
// ... and ...
Object.defineProperty(obj, "key", withValue("static"));

// if freeze is available, prevents adding or
// removing the object prototype properties
// (value, get, set, enumerable, writable, configurable)
(Object.freeze || Object)(Object.prototype);
```

範例
--

If you want to see how to use the `Object.defineProperty` method with a *binary-flags-like* syntax, see additional examples.

### 建立屬性

When the property specified doesn't exist in the object, `Object.defineProperty()` creates a new property as described. Fields may be omitted from the descriptor, and default values for those fields are imputed. All of the Boolean-valued fields default to `false`. The `value`, `get`, and `set` fields default to `undefined` (en-US). A property which is defined without `get`/`set`/`value`/`writable` is called 「generic」 and is 「typed」 as a data descriptor.

```js
var o = {}; // Creates a new object

// Example of an object property added with defineProperty with a data property descriptor
Object.defineProperty(o, "a", {
  value: 37,
  writable: true,
  enumerable: true,
  configurable: true,
});
// 'a' property exists in the o object and its value is 37

// Example of an object property added with defineProperty with an accessor property descriptor
var bValue = 38;
Object.defineProperty(o, "b", {
  get: function () {
    return bValue;
  },
  set: function (newValue) {
    bValue = newValue;
  },
  enumerable: true,
  configurable: true,
});
o.b; // 38
// 'b' property exists in the o object and its value is 38
// The value of o.b is now always identical to bValue, unless o.b is redefined

// You cannot try to mix both:
Object.defineProperty(o, "conflict", {
  value: 0x9f91102,
  get: function () {
    return 0xdeadbeef;
  },
});
// throws a TypeError: value appears only in data descriptors, get appears only in accessor descriptors
```

### 修改屬性

如果該屬性已經存在, `Object.defineProperty()` 將會根據描述符內的值和物件當前的 configuration 來修改屬性。 如果舊的描述符之 `configurable` 的特徵為 false (屬性為 「non-configurable」), 那除了 `writable` 之外的特徵都將無法修改。 在這個情況，也不可能在 data 和 accessor 屬性類型中來回切換。

如果有一個屬性是 non-configurable, 那它的 `writable` 特徵只能被改變為 `false`.

若嘗試改變 non-configurable property attributes，將會丟出一個 `TypeError` (en-US)，除非當前之值與新值相同。

#### Writable attribute

當 `writable` 屬性特徵被設為 `false`, 此屬性為 「non-writable」. 它將無法被重新賦值。

```js
var o = {}; // Creates a new object

Object.defineProperty(o, "a", {
  value: 37,
  writable: false,
});

console.log(o.a); // logs 37
o.a = 25; // No error thrown (it would throw in strict mode, even if the value had been the same)
console.log(o.a); // logs 37. The assignment didn't work.
```

As seen in the example, trying to write into the non-writable property doesn't change it but doesn't throw an error either.

#### 可列舉 attribute

The `enumerable` property attribute defines whether the property shows up in a `for...in` loop and `Object.keys()` or not.

```js
var o = {};
Object.defineProperty(o, "a", { value: 1, enumerable: true });
Object.defineProperty(o, "b", { value: 2, enumerable: false });
Object.defineProperty(o, "c", { value: 3 }); // enumerable defaults to false
o.d = 4; // enumerable defaults to true when creating a property by setting it

for (var i in o) {
  console.log(i);
}
// logs 'a' and 'd' (in undefined order)

Object.keys(o); // ['a', 'd']

o.propertyIsEnumerable("a"); // true
o.propertyIsEnumerable("b"); // false
o.propertyIsEnumerable("c"); // false
```

#### 可設定 attribute

The `configurable` attribute controls at the same time whether the property can be deleted from the object and whether its attributes (other than `writable`) can be changed.

```js
var o = {};
Object.defineProperty(o, "a", {
  get: function () {
    return 1;
  },
  configurable: false,
});

Object.defineProperty(o, "a", { configurable: true }); // throws a TypeError
Object.defineProperty(o, "a", { enumerable: true }); // throws a TypeError
Object.defineProperty(o, "a", { set: function () {} }); // throws a TypeError (set was undefined previously)
Object.defineProperty(o, "a", {
  get: function () {
    return 1;
  },
}); // throws a TypeError (even though the new get does exactly the same thing)
Object.defineProperty(o, "a", { value: 12 }); // throws a TypeError

console.log(o.a); // logs 1
delete o.a; // Nothing happens
console.log(o.a); // logs 1
```

If the `configurable` attribute of `o.a` had been `true`, none of the errors would be thrown and the property would be deleted at the end.

### 新增多個屬性及賦予初始值

It's important to consider the way default values of attributes are applied. There is often a difference between simply using dot notation to assign a value and using `Object.defineProperty()`, as shown in the example below.

```js
var o = {};

o.a = 1;
// is equivalent to:
Object.defineProperty(o, "a", {
  value: 1,
  writable: true,
  configurable: true,
  enumerable: true,
});

// On the other hand,
Object.defineProperty(o, "a", { value: 1 });
// is equivalent to:
Object.defineProperty(o, "a", {
  value: 1,
  writable: false,
  configurable: false,
  enumerable: false,
});
```

### Custom Setters and Getters

Example below shows how to implement a self-archiving object. When `temperature` property is set, the `archive` array gets a log entry.

```js
function Archiver() {
  var temperature = null;
  var archive = [];

  Object.defineProperty(this, "temperature", {
    get: function () {
      console.log("get!");
      return temperature;
    },
    set: function (value) {
      temperature = value;
      archive.push({ val: temperature });
    },
  });

  this.getArchive = function () {
    return archive;
  };
}

var arc = new Archiver();
arc.temperature; // 'get!'
arc.temperature = 11;
arc.temperature = 13;
arc.getArchive(); // [{ val: 11 }, { val: 13 }]
```

or

```js
var pattern = {
  get: function () {
    return "I always return this string, whatever you have assigned";
  },
  set: function () {
    this.myname = "this is my name string";
  },
};

function TestDefineSetAndGet() {
  Object.defineProperty(this, "myproperty", pattern);
}

var instance = new TestDefineSetAndGet();
instance.myproperty = "test";
console.log(instance.myproperty); // I always return this string, whatever you have assigned

console.log(instance.myname); // this is my name string
```

規格
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-object.defineproperty |

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

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

Compatibility notes
-------------------

### Redefining the `length` property of an `Array` object

It is possible to redefine the `length` property of arrays, subject to the usual redefinition restrictions. (The `length` property is initially non-configurable, non-enumerable, and writable. Thus on an unaltered array, it's possible to change the `length` property's value or to make it non-writable. It is not allowed to change its enumerability or configurability, or if it is non-writable to change its value or writability.) However, not all browsers permit this redefinition.

Firefox 4 through 22 will throw a `TypeError` (en-US) on any attempt whatsoever (whether permitted or not) to redefine the `length` property of an array.

Versions of Chrome which implement `Object.defineProperty()` in some circumstances ignore a length value different from the array's current `length` property. In some circumstances changing writability seems to silently not work (and not throw an exception). Also, relatedly, some array-mutating methods like `Array.prototype.push` don't respect a non-writable length.

Versions of Safari which implement `Object.defineProperty()` ignore a `length` value different from the array's current `length` property, and attempts to change writability execute without error but do not actually change the property's writability.

Only Internet Explorer 9 and later, and Firefox 23 and later, appear to fully and correctly implement redefinition of the `length` property of arrays. For now, don't rely on redefining the `length` property of an array to either work, or to work in a particular manner. And even when you *can* rely on it, there's really no good reason to do so.

### Internet Explorer 8 specific notes

Internet Explorer 8 implemented a `Object.defineProperty()` method that could only be used on DOM objects. A few things need to be noted:

* Trying to use `Object.defineProperty()` on native objects throws an error.
* Property attributes must be set to some values. The `configurable`, `enumerable` and `writable` attributes should all be set to `true` for data descriptor and `true` for `configurable`, `false` for `enumerable` for accessor descriptor.(?) Any attempt to provide other value(?) will result in an error being thrown.
* Reconfiguring a property requires first deleting the property. If the property isn't deleted, it stays as it was before the reconfiguration attempt.
參閱
--

* Enumerability and ownership of properties (en-US)
* `Object.defineProperties()` (en-US)
* `Object.propertyIsEnumerable()` (en-US)
* `Object.getOwnPropertyDescriptor()` (en-US)
* `Object.prototype.watch()`
* `Object.prototype.unwatch()`
* `get` (en-US)
* `set` (en-US)
* `Object.create()`
* Additional `Object.defineProperty` examples
* `Reflect.defineProperty()` (en-US)


Object.prototype.hasOwnProperty() - JavaScript

Object.prototype.hasOwnProperty()
=================================

**`hasOwnProperty()`** 回傳物件是否有該屬性的布林值。

表達式
---

```js
obj.hasOwnProperty(prop)
```

### 參數

`prop`

屬性名稱。

說明
--

每個為 `Object` (en-US) 後代的物件都繼承 `hasOwnProperty` 方法。這個方法可以被使用來決定物件是否擁有特定的直接屬性；跟 `in` (en-US) 不一樣，這個方法並未檢查物件的原型鏈。

範例
--

### 使用 `hasOwnProperty` 測試屬性是否存在

這個範例顯示 `o` 物件是否擁有名為 `prop` 的屬性:

```js
o = new Object();
o.prop = "exists";

function changeO() {
  o.newprop = o.prop;
  delete o.prop;
}

o.hasOwnProperty("prop"); // 回傳 true
changeO();
o.hasOwnProperty("prop"); // 回傳 false
```

### 直接與繼承的屬性

這個範例區分直接屬性和從原型鍊繼承的屬性：

```js
o = new Object();
o.prop = "exists";
o.hasOwnProperty("prop"); // 回傳 true
o.hasOwnProperty("toString"); // 回傳 false
o.hasOwnProperty("hasOwnProperty"); // 回傳 false
```

### 遍歷物件的屬性

這個範例顯示如何不執行繼承的屬性去遍歷物件的屬性。注意 `for...in` 已經遍歷了可以被列舉的項目，所以不該基於缺乏不可列舉的屬性(如下)而假設 `hasOwnProperty` 被嚴格地限制在列舉的項目（如同 `Object.getOwnPropertyNames()` (en-US)）。

```js
var buz = {
  fog: "stack",
};

for (var name in buz) {
  if (buz.hasOwnProperty(name)) {
    console.log("this is fog (" + name + ") for sure. Value: " + buz[name]);
  } else {
    console.log(name); // toString or something else
  }
}
```

### `將 hasOwnProperty` 作為屬性

JavaScript 並未保護 `hasOwnProperty`；因此，如果一個物件擁有一樣的屬性名稱，為了獲得正確的結果需要使用 *external* `hasOwnProperty`：

```js
var foo = {
  hasOwnProperty: function () {
    return false;
  },
  bar: "Here be dragons",
};

foo.hasOwnProperty("bar"); // 總是回傳 false

// 使用其他物件的 hasOwnProperty 和 call it with 'this' set to foo
({}).hasOwnProperty.call(foo, "bar"); // true

// 從物件的原型使用 hasOwnProperty 也是可行的
Object.prototype.hasOwnProperty.call(foo, "bar"); // true
```

註：在最後一個例子中並未創建任何新的物件。

規範
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-object.prototype.hasownproperty |

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

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

參見
--

* Enumerability and ownership of properties (en-US)
* `Object.getOwnPropertyNames()` (en-US)
* `for...in`
* `in` (en-US)
* JavaScript Guide: Inheritance revisited (en-US)


String.prototype.trim() - JavaScript

String.prototype.trim()
=======================

**`trim()`** 方法會移除字串起始及結尾處的空白字元。
 本文中的空白字元指所有空格字元（如：空格、欄標、無間斷空格等等）及換行字元（如：換行、回車等等）。

嘗試一下
----

語法
--

```js
trim()
```

### 回傳值

回傳一個新的字串，其為把 `str` 起始及結尾處的空白字元移除後的值。

如果 `str` 的起始及結尾處沒有任何的空白字元，此方法不會拋出任何例外，且仍然會回傳一個新的字串（本質上為 `str` 的複製）。

如果只是想要去除字串起始處或結尾處其中之一的空白字元，那麼可以選擇使用 `trimStart()` (en-US) 或者 `trimEnd()` (en-US)。

Polyfill
--------

在任何其他的程式碼被執行之前，先執行以下的程式碼，它將會在瀏覽器本身未支援 `trim()` 的方法時創造它。

```js
if (!String.prototype.trim) {
  String.prototype.trim = function () {
    return this.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, "");
  };
}
```

範例
--

### 如何使用 `trim()`

以下例子會印出小寫的字串 `'foo'`：

```js
var orig = " foo ";
console.log(orig.trim()); // 'foo'
```

規範
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-string.prototype.trim |

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

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

參見
--

* `String.prototype.trimStart()` (en-US)
* `String.prototype.trimEnd()` (en-US)


String.prototype.concat() - JavaScript

String.prototype.concat()
=========================

**`concat()`** 會將呼叫此方法的字串以及作為參數傳遞進此方法的字串串接在一起，並將串接結果作為一個新的字串回傳。

嘗試一下
----

語法
--

```js
concat(str1)
concat(str1, str2)
concat(str1, str2, ... , strN)
```

### 參數

`strN`

要串接到 `str` 的字串，可以傳入一個至多個。

### 回傳值

此方法會回傳一個新的字串，由呼叫此方法的字串及作為參數傳入的字串組合而成。

描述
--

`concat()` 會將那些作為參數的字串串接在呼叫此方法的字串後面，並作為一個新的字串回傳。
 對於原先的字串、或是回傳的字串做修改，不會讓他們的值互相影響。

如果傳入的參數不是字串型別，那在串接前會先將該參數轉換成字串。

效能
--

 對於字串的串接，強烈建議直接使用運算子 assignment operators (en-US) 來達成，
 像是 `+` 及 `+=`，而不是使用 `concat()` 方法。

範例
--

### 如何使用 concat()

以下的例子示範如何將那些給定的字串組合成新的字串。

```js
let hello = "Hello, ";
console.log(hello.concat("Kevin", ". Have a nice day."));
// Hello, Kevin. Have a nice day.

let greetList = ["Hello", " ", "Venkat", "!"];
"".concat(...greetList); // "Hello Venkat!"

"".concat({}); // [object Object]
"".concat([]); // ""
"".concat(null); // "null"
"".concat(true); // "true"
"".concat(4, 5); // "45"
```

規範
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-string.prototype.concat |

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

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

參見
--

* `Array.prototype.concat()`
* Assignment operators (en-US)


String.prototype.toLowerCase() - JavaScript

String.prototype.toLowerCase()
==============================

**`toLowerCase()`** 函式会回传将字符串转换为英文小写字母后的结果。

嘗試一下
----

语法
--

```js
str.toLowerCase()
```

### 回传值

回传一组将原字串英文内容转换成英文小写字母后的结果。

描述
--

The `toLowerCase()` 函式会回传一组将原字符串英文内容转换成英文小写字母后的结果。 `toLowerCase()` 并不会影响到原字符串 `str` 的内容值。

范例
--

### 使用 `toLowerCase()`

```js
console.log("ALPHABET".toLowerCase()); // 'alphabet'
```

规范
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-string.prototype.tolowercase |

浏览器相容性
------

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

參見
--

* `String.prototype.toLocaleLowerCase()` (en-US)
* `String.prototype.toLocaleUpperCase()` (en-US)
* `String.prototype.toUpperCase()` (en-US)


String.prototype.localeCompare() - JavaScript

String.prototype.localeCompare()
================================

**`localeCompare()`** 回傳一個數字，用來表示其與被比較的字串的先後順序。

如果環境中有支援`Intl.Collator` API (en-US)，這個方法實際上是調用 `Intl.Collator` API。

嘗試一下
----

語法
--

```js
localeCompare(compareString)
localeCompare(compareString, locales)
localeCompare(compareString, locales, options)
```

### 參數

`locales` 和 `options` 參數可以調整函數的回傳結果，並且能指定要依照哪種語言來進行比較。

 在實現 `Intl.Collator` API (en-US)的環境中，這些參數與 `Intl.Collator()` (en-US) 的參數互相對應；
 若環境沒有實現 `Intl.Collator` ，則這兩個參數就會被忽略，其回傳結果完全看該環境如何實作，唯一的要求是（對於同樣的字串）比較結果必須始終一致。

`compareString`

要和`referenceStr`進行比較的字串

`locales` 選擇性

「BCP 47 語言標籤」的字串或是陣列。相當於`Intl.Collator()`的`locales` (en-US) 參數。

如果使用的環境並未實現 `Intl.Collator`，此參數會被忽略，並且視同採用當前主機的語言環境

`options` 選擇性

一個處理輸出格式的物件。相當於`Intl.Collator()`的 `options` (en-US)參數。

如果使用的環境並未實現`Intl.Collator` ，此參數會被忽略。

關於`locales`和`options`參數以及其使用的資訊，可參閱`Intl.Collator()` constructor (en-US)。

### 回傳值

如果`referenceStr`在`compareString`以先，會回傳**負數**；若`referenceStr`在`compareString`以後，則為**正數**; `0`表示兩者相等。

如果所使用的環境有實現 `Intl.Collator`，相當於回傳 `new Intl.Collator(locales, options).compare(referenceStr, compareString)`。

說明
--

回傳 `referenceStr` 和 `compareString`的先後順序

* 若回傳負數，表示 `referenceStr`在 `compareString`以先
* 若為正數，表示 `referenceStr`在`compareString`以後
* 若回傳`0`，表示兩者相等

**警告：** 不要依靠特定的回傳值，例如 `-1` 或是 `1`！

 正數或是負數的回傳值在不同的瀏覽器(也包誇同一瀏覽器但不同版本）之間有可能會有所不同。因為 W3C 規範僅要求值得正負而已。
 也因此，某些瀏覽器可能會回傳 `-2` 、 `2` 甚至其他值。

效能
--

如果要對大量的字串進行比較，例如排序長度很長的陣列，最好是建立一個 `Intl.Collator` (en-US)物件並使用其`compare` (en-US) 方法。

範例
--

### 使用 `localeCompare()`

```js
// "a" 在 "c" 之前，所以會回傳負數
"a".localeCompare("c"); // -2、-1 或是其他負數值
// 按字母順序，「check」的順序在「against」之後，所以回傳正數
"check".localeCompare("against"); // 2、1 或其他正數值
// "a" 和 "a" 相同，所以回傳 0
"a".localeCompare("a"); // 0
```

### 陣列排序

`localeCompare()` 用來進行「不分大小寫」的排序

```js
let items = ["réservé", "Premier", "Cliché", "communiqué", "café", "Adieu"];
items.sort((a, b) => a.localeCompare(b, "fr", { ignorePunctuation: true }));
// ['Adieu', 'café', 'Cliché', 'communiqué', 'Premier', 'réservé']
```

### 檢查瀏覽器對額外參數的支援度

並不是所有瀏覽器都支援 `locales` 和 `options` 參數。

要檢查是否支援，可以使用 `"i"` 參數（正常情況下，非正常的語言標籤會回報錯誤）並檢查是否有 `RangeError` exception：

```js
function localeCompareSupportsLocales() {
  try {
    "foo".localeCompare("bar", "i");
  } catch (e) {
    return e.name === "RangeError";
  }
  return false;
}
```

### 使用 `locales`

`localeCompare()`回傳的結果會因為語言而有所不同。

為了讓回傳結果依照特定語言來排序，請確保使用 `locales` 參數指定該語言（可能還要再加上其他後備語言）：

```js
console.log("ä".localeCompare("z", "de")); // 回傳負數：在德文, ä 的順序在 z 之前
console.log("ä".localeCompare("z", "sv")); // 回傳正數：在瑞典文， ä 的順序在 z 之後
```

### 使用 `options`

`localeCompare()` 可以藉由 `options` 參數來調整：

```js
// 在德文， ä 和 a 是相同字母
console.log("ä".localeCompare("a", "de", { sensitivity: "base" })); // 0
// 在瑞典文， ä 和 a 是各自獨立的字母
console.log("ä".localeCompare("a", "sv", { sensitivity: "base" })); // 回傳正數
```

### 數字排序

```js
// 默認情況下, "2" > "10"
console.log("2".localeCompare("10")); // 1
// 使用 option 讓其視為數字進行比較
console.log("2".localeCompare("10", undefined, { numeric: true })); // -1
// 使用locales標籤
console.log("2".localeCompare("10", "en-u-kn-true")); // -1
```

規範
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-string.prototype.localecompare |
| ECMAScript Internationalization API Specification # sup-String.prototype.localeCompare |

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

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

參見
--

* `Intl.Collator` (en-US)


String.prototype.padStart() - JavaScript

String.prototype.padStart()
===========================

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

**`padStart()`** 會將用給定用於填充的字串，以重複的方式，插入到目標字串的起頭(左側)，直到目標字串到達指定長度。

Syntax
------

```js
str.padStart(targetLength [, padString])
```

### Parameters

`targetLength`

目標字串被填充後的長度。如果此參數小於原字串的長度，那將直接返回原字串。

`padString` 選擇性

用來填充的字串。如果填充字串太長，則由左側開始，擷取所需要的長度。此參數預設值是空白 " " (U+0020).

### Return value

目標字串被填充到指定長度後，所得的新字串。

Examples
--------

```js
"abc".padStart(10); // " abc"
"abc".padStart(10, "foo"); // "foofoofabc"
"abc".padStart(6, "123465"); // "123abc"
```

規範
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-string.prototype.padstart |

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

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

參見
--

* `String.padEnd()` (en-US)


Math.round() - JavaScript

Math.round()
============

**`Math.round()`** 函數回傳四捨五入後的近似值.

表達式
---
```

Math.round(x)
```

### 參數

`x`

數字.

描述
--

如果小數位的部分值大於 0.5, 這個值將會進位. 如果小數位的部分值小於 0.5, 這個值將不會進位.

由於 `round()` 是靜態的方法, 所以總是得這樣使用 `Math.round()`, 而非作為 `Math` 物件的一個方法 (`Math`並沒有建構子).

範例
--

### 使用 `Math.round()`

```js
// Returns the value 20
x = Math.round(20.49);

// Returns the value 21
x = Math.round(20.5);

// Returns the value -20
x = Math.round(-20.5);

// Returns the value -21
x = Math.round(-20.51);

// Returns the value 1 (!)
// Note the rounding error because of inaccurate floating point arithmetics
// Compare this with Math.round10(1.005, -2) from the example below
x = Math.round(1.005 \* 100) / 100;
```

### 十進位近似值

```js
// 閉包含數
(function () {
  /\*\*
 \* Decimal adjustment of a number.
 \*
 \* @param {String} type The type of adjustment.
 \* @param {Number} value The number.
 \* @param {Integer} exp The exponent (the 10 logarithm of the adjustment base).
 \* @returns {Number} The adjusted value.
 \*/
  function decimalAdjust(type, value, exp) {
    // If the exp is undefined or zero...
    if (typeof exp === "undefined" || +exp === 0) {
      return Math[type](value);
    }
    value = +value;
    exp = +exp;
    // If the value is not a number or the exp is not an integer...
    if (isNaN(value) || !(typeof exp === "number" && exp % 1 === 0)) {
      return NaN;
    }
    // Shift
    value = value.toString().split("e");
    value = Math[type](+(value[0] + "e" + (value[1] ? +value[1] - exp : -exp)));
    // Shift back
    value = value.toString().split("e");
    return +(value[0] + "e" + (value[1] ? +value[1] + exp : exp));
  }

  // Decimal round
  if (!Math.round10) {
    Math.round10 = function (value, exp) {
      return decimalAdjust("round", value, exp);
    };
  }
  // Decimal floor
  if (!Math.floor10) {
    Math.floor10 = function (value, exp) {
      return decimalAdjust("floor", value, exp);
    };
  }
  // Decimal ceil
  if (!Math.ceil10) {
    Math.ceil10 = function (value, exp) {
      return decimalAdjust("ceil", value, exp);
    };
  }
})();

// Round
Math.round10(55.55, -1); // 55.6
Math.round10(55.549, -1); // 55.5
Math.round10(55, 1); // 60
Math.round10(54.9, 1); // 50
Math.round10(-55.55, -1); // -55.5
Math.round10(-55.551, -1); // -55.6
Math.round10(-55, 1); // -50
Math.round10(-55.1, 1); // -60
Math.round10(1.005, -2); // 1.01 -- compare this with Math.round(1.005\*100)/100 above
// Floor
Math.floor10(55.59, -1); // 55.5
Math.floor10(59, 1); // 50
Math.floor10(-55.51, -1); // -55.6
Math.floor10(-51, 1); // -60
// Ceil
Math.ceil10(55.51, -1); // 55.6
Math.ceil10(51, 1); // 60
Math.ceil10(-55.59, -1); // -55.5
Math.ceil10(-59, 1); // -50
```

規範
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-math.round |

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

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

參見
--

* `Math.abs()` (en-US)
* `Math.ceil()`
* `Math.floor()`
* `Math.sign()` (en-US)
實驗性質
* `Math.trunc()` (en-US)
實驗性質


Math.random() - JavaScript

Math.random()
=============

函數 **`Math.random()`** 會回傳一個偽隨機小數 (pseudo-random) 介於 0 到 1 之間(包含 0，不包含 1) ，大致符合數學與統計上的均勻分佈 (uniform distribution) ，你可以選定想要的數字區間，它會透過演算法被產生並且不允許使用者自行跳選或重設成特定數字。

嘗試一下
----

**備註：** `Math.random()` 所產生的偽隨機小數不符合加密學安全性要求。*請勿使用於任何加密、資安相關領域。*

*如有加密需求建議參考 Web Crypto API*`window.crypto.getRandomValues()` (en-US)

語法
--
```

Math.random()
```

### 回傳值 Return value

回傳一個偽隨機小數 (pseudo-random)，小數也稱浮點數； 介於 0 到 1 之間(包含 0，不包含 1) 。

範例
--

請留意 JavaScript 中的數字與許多語言一樣使用 IEEE 754 floating point numbers with round-to-nearest-even behavior, the ranges claimed for the functions below (excluding the one for `Math.random()` itself) aren't exact. If extremely large bounds are chosen (2^53 or higher), it's possible in *extremely* rare cases to calculate the usually-excluded upper bound.

### Getting a random number between 0 (inclusive) and 1 (exclusive)

```js
function getRandom() {
  return Math.random();
}
```

### Getting a random number between two values

This example returns a random number between the specified values. The returned value is no lower than (and may possibly equal) `min`, and is less than (and not equal) `max`.

```js
function getRandomArbitrary(min, max) {
  return Math.random() \* (max - min) + min;
}
```

### Getting a random integer between two values

This example returns a random *integer* between the specified values. The value is no lower than `min` (or the next integer greater than `min` if `min` isn't an integer), and is less than (but not equal to) `max`.

```js
function getRandomInt(min, max) {
  min = Math.ceil(min);
  max = Math.floor(max);
  return Math.floor(Math.random() \* (max - min) + min); //The maximum is exclusive and the minimum is inclusive
}
```

**備註：** might be tempting to use `Math.round()` to accomplish that, but doing so would cause your random numbers to follow a non-uniform distribution, which may not be acceptable for your needs.

### Getting a random integer between two values, inclusive

While the `getRandomInt()` function above is inclusive at the minimum, it's exclusive at the maximum. What if you need the results to be inclusive at both the minimum and the maximum? The `getRandomIntInclusive()` function below accomplishes that.

```js
function getRandomIntInclusive(min, max) {
  min = Math.ceil(min);
  max = Math.floor(max);
  return Math.floor(Math.random() \* (max - min + 1) + min); //The maximum is inclusive and the minimum is inclusive
}
```

規範
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-math.random |

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

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

其他參考資料
------

* `window.crypto.getRandomValues()` (en-US)


Math.ceil() - JavaScript

Math.ceil()
===========

**`Math.ceil()`** 函式會回傳大於等於所給數字的最小整數。

嘗試一下
----

語法
--
```

Math.ceil(x)
```

### 參數

`x`

一個數字。

### 回傳值

一個大於等於指定數字的最小整數。

描述
--

Because `ceil()` is a static method of `Math`, you always use it as `Math.ceil()`, rather than as a method of a `Math` object you created (`Math` is not a constructor).

範例
--

### 使用 `Math.ceil()`

The following example shows example usage of `Math.ceil()`.

```js
Math.ceil(0.95); // 1
Math.ceil(4); // 4
Math.ceil(7.004); // 8
Math.ceil(-0.95); // -0
Math.ceil(-4); // -4
Math.ceil(-7.004); // -7
```

### Decimal adjustment

```js
// Closure
(function () {
  /\*\*
 \* Decimal adjustment of a number.
 \*
 \* @param {String} type The type of adjustment.
 \* @param {Number} value The number.
 \* @param {Integer} exp The exponent (the 10 logarithm of the adjustment base).
 \* @returns {Number} The adjusted value.
 \*/
  function decimalAdjust(type, value, exp) {
    // If the exp is undefined or zero...
    if (typeof exp === "undefined" || +exp === 0) {
      return Math[type](value);
    }
    value = +value;
    exp = +exp;
    // If the value is not a number or the exp is not an integer...
    if (isNaN(value) || !(typeof exp === "number" && exp % 1 === 0)) {
      return NaN;
    }
    // Shift
    value = value.toString().split("e");
    value = Math[type](+(value[0] + "e" + (value[1] ? +value[1] - exp : -exp)));
    // Shift back
    value = value.toString().split("e");
    return +(value[0] + "e" + (value[1] ? +value[1] + exp : exp));
  }

  // Decimal round
  if (!Math.round10) {
    Math.round10 = function (value, exp) {
      return decimalAdjust("round", value, exp);
    };
  }
  // Decimal floor
  if (!Math.floor10) {
    Math.floor10 = function (value, exp) {
      return decimalAdjust("floor", value, exp);
    };
  }
  // Decimal ceil
  if (!Math.ceil10) {
    Math.ceil10 = function (value, exp) {
      return decimalAdjust("ceil", value, exp);
    };
  }
})();

// Round
Math.round10(55.55, -1); // 55.6
Math.round10(55.549, -1); // 55.5
Math.round10(55, 1); // 60
Math.round10(54.9, 1); // 50
Math.round10(-55.55, -1); // -55.5
Math.round10(-55.551, -1); // -55.6
Math.round10(-55, 1); // -50
Math.round10(-55.1, 1); // -60
// Floor
Math.floor10(55.59, -1); // 55.5
Math.floor10(59, 1); // 50
Math.floor10(-55.51, -1); // -55.6
Math.floor10(-51, 1); // -60
// Ceil
Math.ceil10(55.51, -1); // 55.6
Math.ceil10(51, 1); // 60
Math.ceil10(-55.59, -1); // -55.5
Math.ceil10(-59, 1); // -50
```

規範
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-math.ceil |

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

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

參見
--

* `Math.abs()` (en-US)
* `Math.floor()`
* `Math.round()`
* `Math.sign()` (en-US)
* `Math.trunc()` (en-US)


Math.floor() - JavaScript

Math.floor()
============

**`Math.floor()`** 函式會回傳小於等於所給數字的最大整數。

嘗試一下
----

語法
--
```

Math.floor(x)
```

### 參數

`x`

數字型態。

### 回傳值

小於等於所給數字的最大整數。

描述
--

`floor()` 是 `Math`的靜態函式, 所以不需實體化`Math` 物件, 只要直接呼叫 `Math.floor()`就能使用。

(此外`Math` 並不是建構子).

範例
--

### 使用 `Math.floor()`

```js
Math.floor(45.95); // 45
Math.floor(45.05); // 45
Math.floor(4); // 4
Math.floor(-45.05); // -46
Math.floor(-45.95); // -46
```

### Decimal adjustment

```js
// Closure
(function () {
  /\*\*
 \* Decimal adjustment of a number.
 \*
 \* @param {String} type The type of adjustment.
 \* @param {Number} value The number.
 \* @param {Integer} exp The exponent (the 10 logarithm of the adjustment base).
 \* @returns {Number} The adjusted value.
 \*/
  function decimalAdjust(type, value, exp) {
    // If the exp is undefined or zero...
    if (typeof exp === "undefined" || +exp === 0) {
      return Math[type](value);
    }
    value = +value;
    exp = +exp;
    // If the value is not a number or the exp is not an integer...
    if (isNaN(value) || !(typeof exp === "number" && exp % 1 === 0)) {
      return NaN;
    }
    // Shift
    value = value.toString().split("e");
    value = Math[type](+(value[0] + "e" + (value[1] ? +value[1] - exp : -exp)));
    // Shift back
    value = value.toString().split("e");
    return +(value[0] + "e" + (value[1] ? +value[1] + exp : exp));
  }

  // Decimal round
  if (!Math.round10) {
    Math.round10 = function (value, exp) {
      return decimalAdjust("round", value, exp);
    };
  }
  // Decimal floor
  if (!Math.floor10) {
    Math.floor10 = function (value, exp) {
      return decimalAdjust("floor", value, exp);
    };
  }
  // Decimal ceil
  if (!Math.ceil10) {
    Math.ceil10 = function (value, exp) {
      return decimalAdjust("ceil", value, exp);
    };
  }
})();

// Round
Math.round10(55.55, -1); // 55.6
Math.round10(55.549, -1); // 55.5
Math.round10(55, 1); // 60
Math.round10(54.9, 1); // 50
Math.round10(-55.55, -1); // -55.5
Math.round10(-55.551, -1); // -55.6
Math.round10(-55, 1); // -50
Math.round10(-55.1, 1); // -60
// Floor
Math.floor10(55.59, -1); // 55.5
Math.floor10(59, 1); // 50
Math.floor10(-55.51, -1); // -55.6
Math.floor10(-51, 1); // -60
// Ceil
Math.ceil10(55.51, -1); // 55.6
Math.ceil10(51, 1); // 60
Math.ceil10(-55.59, -1); // -55.5
Math.ceil10(-59, 1); // -50
```

規範
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-math.floor |

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

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

參見
--

* `Math.abs()` (en-US)
* `Math.ceil()`
* `Math.round()`
* `Math.sign()` (en-US)
* `Math.trunc()` (en-US)


Error.prototype.columnNumber - JavaScript

Error.prototype.columnNumber
============================

**非標準:** This feature is non-standard and is not on a standards track. Do not use it on production sites facing the Web: it will not work for every user. There may also be large incompatibilities between implementations and the behavior may change in the future.

「行數」屬性含括了檔案中引起錯誤的所在行數。

範例
--

### 使用 `columnNumber`

```js
var e = new Error("Could not parse input");
throw e;
console.log(e.columnNumber); // 0
```

規格
--

不是任何規格的一部份，尚未標準化。

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

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

參見
--

* `Error.prototype.stack` (en-US)
非標準
* `Error.prototype.lineNumber` (en-US)
非標準
* `Error.prototype.fileName` (en-US)
非標準


JSON.parse() - JavaScript

JSON.parse()
============

**`JSON.parse()`** 方法把會把一個 JSON 字串轉換成 JavaScript 的數值或是物件。另外也可選擇使用 reviver 函數讓這些數值或是物件在被回傳之前做轉換。

語法
--

```js
JSON.parse(text[, reviver])
```

### 參數

`text`

要解析成 JSON 的字串。針對 JSON 語法的描述，請參見 `JSON` 物件。

`reviver` 選擇性

為選擇性的參數，用來描述 JSON 字串中的值該如何被解析並回傳的函式(function)

### 回傳值

從給定的 JSON `text` 回傳對應的 `Object` (en-US)。

### 例外

如果解析的字串不是合法的 JSON 格式會丟出一個 `SyntaxError` (en-US) 例外

範例
--

### 使用 `JSON.parse()`

```js
JSON.parse("{}"); // {}
JSON.parse("true"); // true
JSON.parse('"foo"'); // "foo"
JSON.parse('[1, 5, "false"]'); // [1, 5, "false"]
JSON.parse("null"); // null
```

### 使用 **`reviver`** 參數

如果 `reviver` 函數有被指定，字串解析後產生出來的值會在函式回傳前經過轉換。 具體來講，解析後的值或是物件屬性會一個接一個地被這個 reviver 函數過濾（順序是由巢狀架構中最深的到最淺的），而當一個屬性即將被過濾時，該屬性的名稱（字串形態）以及值會被當作參數傳入 reviver 函數。如果 reviver 函數回傳了 `undefined` (en-US)（或是沒有回傳值，例如：函式提早結束），則該屬性會從物件中被刪除；反之如果成功的話，該屬性的值就會被新的回傳值取代。

如果 reviver 只需轉換某些特定的值，請記得將其他不須特別轉換的值以原來的值回傳，否則這些值會從回傳的結果物件中刪除。

```js
JSON.parse('{"p": 5}', function (k, v) {
  if (typeof v === "number") {
    return v \* 2; // return v \* 2 for numbers
  }
  return v; // return everything else unchanged
});

// { p: 10 }

JSON.parse('{"1": 1, "2": 2, "3": {"4": 4, "5": {"6": 6}}}', function (k, v) {
  console.log(k); // log the current property name, the last is "".
  return v; // return the unchanged property value.
});

// 1
// 2
// 4
// 6
// 5
// 3
// ""
```

### `JSON.parse()` 不容許尾部有逗號

```js
// 這兩個都會拋出 SyntaxError
JSON.parse("[1, 2, 3, 4, ]");
JSON.parse('{"foo" : 1, }');
```

規範
--

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

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

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

Gecko 相關
--------

從 Gecko 29 版本開始，錯誤格式的 JSON 字串會產生更詳細的錯誤訊息，包含造成解析錯誤的行數及列數。這在針對大量 JSON 資料進行除錯時會很有幫助。

```js
JSON.parse("[1, 2, 3, 4,]");
// SyntaxError: JSON.parse: unexpected character at
// line 1 column 13 of the JSON data
```

參見
--

* `JSON.stringify()` (en-US)


Array.prototype.fill() - JavaScript

Array.prototype.fill()
======================

**`fill()`** 方法會將陣列中索引的第一個到最後一個的每個位置全部填入一個靜態的值。

嘗試一下
----

語法
--
```

arr.fill(value[, start[, end]])
```

### 參數

`value`

欲填入陣列的值。

`start` 選擇性

起始的索引值，預設為 0。

`end` 選擇性

結束的索引值，預設為 `this.length`（即陣列的長度）。

### 回傳值

修改後的陣列。

說明
--

要填入的元素區間為 [`start`, `end`)，意即包含 `start` 但不包含 `end`。

**`fill`** 方法採用了三個傳入引數（arguments），分別為`value`、`start` 及 `end`。`start` 和 `end` 為可選引數，其預設值分別為 `0` 和 `this` 物件（該陣列）的 `length`。

若 `start` 為負數，則此方法會將其換算成 `length+start`，`length` 即該陣列的長度。同理，若 `end` 為負數，其會被換算成 `length+end`。

**`fill`** 函式刻意地被設計成通用的函式，它不需要 `this` 物件一定是一個陣列物件。此外，它是可變動的（mutable）方法，意即會修改 `this` 物件本身並回傳，而非只是回傳拷貝。

當 **`fill`** 方法獲得一個傳入的物件，會將傳入的物件位置進行複製，並把其參考值（reference）之拷貝填入陣列中。

範例
--

```js
[1, 2, 3].fill(4); // [4, 4, 4]
[1, 2, 3].fill(4, 1); // [1, 4, 4]
[1, 2, 3].fill(4, 1, 2); // [1, 4, 3]
[1, 2, 3].fill(4, 1, 1); // [1, 2, 3]
[1, 2, 3].fill(4, 3, 3); // [1, 2, 3]
[1, 2, 3].fill(4, -3, -2); // [4, 2, 3]
[1, 2, 3].fill(4, NaN, NaN); // [1, 2, 3]
[1, 2, 3].fill(4, 3, 5); // [1, 2, 3]
Array(3).fill(4); // [4, 4, 4]
[].fill.call({ length: 3 }, 4); // {0: 4, 1: 4, 2: 4, length: 3}

// Objects by reference.
var arr = Array(3).fill({}); // [{}, {}, {}];
arr[0].hi = "hi"; // [{ hi: "hi" }, { hi: "hi" }, { hi: "hi" }]
```

Polyfill
--------

```js
if (!Array.prototype.fill) {
  Object.defineProperty(Array.prototype, "fill", {
    value: function (value) {
      // 步驟 1 - 2。
      if (this == null) {
        throw new TypeError("this is null or not defined");
      }

      var O = Object(this);

      // 步驟 3 - 5。
      var len = O.length >>> 0;

      // 步驟 6 - 7。
      var start = arguments[1];
      var relativeStart = start >> 0;

      // 步驟 8。
      var k =
        relativeStart < 0
          ? Math.max(len + relativeStart, 0)
          : Math.min(relativeStart, len);

      // 步驟 9 - 10。
      var end = arguments[2];
      var relativeEnd = end === undefined ? len : end >> 0;

      // 步驟 11。
      var final =
        relativeEnd < 0
          ? Math.max(len + relativeEnd, 0)
          : Math.min(relativeEnd, len);

      // 步驟 12。
      while (k < final) {
        O[k] = value;
        k++;
      }

      // 步驟 13。
      return O;
    },
  });
}
```

如果你需要支援實際上棄用的 JavaScript 引擎且其不支援 `Object.defineProperty` 的話，最好不要採用上述的工具來填充方法至 `Array.prototype`，因為你不能將這個方法設定為不可列舉（non-enumerable）的屬性。

規範
--

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

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

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

參見
--

* `Array`
* `TypedArray.prototype.fill()` (en-US)


Array.prototype.reverse() - JavaScript

Array.prototype.reverse()
=========================

**`reverse()`** 方法會*原地*（in place）反轉（reverse）一個陣列。陣列中的第一個元素變為最後一個，而最後一個元素則變成第一個。

嘗試一下
----

語法
--

```js
a.reverse()
```

### 回傳值

反轉後的陣列。

描述
--

`reverse` 方法將原地（in place）變換（transposes）呼叫此方法的陣列物件之元素至其顛倒的位置，改變原陣列後，並回傳此陣列之參考位址（reference）。

範例
--

### 反轉陣列中之元素

下列範例建立了一個包含三個元素的陣列 `a`，接著反轉此陣列。呼叫 `reverse()` 會回傳一個反轉後的原陣列 `a` 之參考。

```js
var a = ["one", "two", "three"];
var reversed = a.reverse();

console.log(a); // ['three', 'two', 'one']
console.log(reversed); // ['three', 'two', 'one']
```

規範
--

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

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

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

參見
--

* `Array.prototype.join()`
* `Array.prototype.sort()`
* `TypedArray.prototype.reverse()` (en-US)


Array.prototype.join() - JavaScript

Array.prototype.join()
======================

**`join()`** 方法會將陣列（或一個類陣列（array-like）物件 (en-US)）中所有的元素連接、合併成一個字串，並回傳此字串。

嘗試一下
----

語法
--
```

arr.join([separator])
```

### 參數

`separator` 選擇性

用來隔開陣列中每個元素的字串。如果必要的話，separator 會自動被轉成字串型態。如果未傳入此參數，陣列中的元素將預設用英文逗號（「,」）隔開。如果 `separator` 是空字串，合併後，元素間不會有任何字元。

### 回傳值

一個合併所有陣列元素的字串。假如 `arr.length` 為 `0`，將回傳空字串。

描述
--

將所有陣列中的元素轉成字串型態後，連接合併成一個字串。任何 `undefined` 或 `null` 的元素都會被視為空字串處理。

範例
--

### 舉例四種合併用法

下方的範例中，首先宣告一個陣列—`a`，其中有三個元素。接著分別用：預設值、逗號、加號和空字串將陣列連接。

```js
var a = ["Wind", "Rain", "Fire"];
a.join(); // 'Wind,Rain,Fire'
a.join(", "); // 'Wind, Rain, Fire'
a.join(" + "); // 'Wind + Rain + Fire'
a.join(""); // 'WindRainFire'
```

### 合併一個類陣列（array-like）物件

下方的範例將合併一個類陣列（array-like）物件（`arguments` (en-US)），藉由 `Function.prototype.call` 來呼叫 `Array.prototype.join`。

```js
function f(a, b, c) {
  var s = Array.prototype.join.call(arguments);
  console.log(s); // '1,a,true'
}
f(1, "a", true);
//expected output: "1,a,true"
```

規範
--

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

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

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

參見
--

* `String.prototype.split()` (en-US)
* `Array.prototype.toString()`
* `TypedArray.prototype.join()` (en-US)


Array.prototype.includes() - JavaScript

Array.prototype.includes()
==========================

**`includes()`** 方法會判斷陣列是否包含特定的元素，並以此來回傳 `true` 或 `false`。

嘗試一下
----

語法
--
```

arr.includes(searchElement[, fromIndex])
```

### 參數

`searchElement`

要搜尋的元素。

`fromIndex` 選擇性

要於此陣列中開始搜尋 `searchElement` 的位置。如為負數值，則自 `array.length + fromIndex` 開始向後搜尋。預設值為 0。

### 回傳值

布林值（`Boolean`）。

範例
--

```js
[1, 2, 3].includes(2); // true
[1, 2, 3].includes(4); // false
[1, 2, 3].includes(3, 3); // false
[1, 2, 3].includes(3, -1); // true
[1, 2, NaN].includes(NaN); // true
```

### `fromIndex` 大於或等於陣列長度

如果 `fromIndex`大於或等於陣列長度, 會回傳`false`. 此陣列將不會被搜尋.

```js
var arr = ["a", "b", "c"];

arr.includes("c", 3); // false
arr.includes("c", 100); // false
```

### Computed index is less than 0

If `fromIndex` is negative, the computed index is calculated to be used as a position in the array at which to begin searching for `searchElement`. If the computed index is less than 0, the entire array will be searched.

```js
// array length is 3
// fromIndex is -100
// computed index is 3 + (-100) = -97

var arr = ["a", "b", "c"];

arr.includes("a", -100); // true
arr.includes("b", -100); // true
arr.includes("c", -100); // true
```

### `includes()` used as a generic method

`includes()` method is intentionally generic. It does not require `this` value to be an Array object, so it can be applied to other kinds of objects (e.g. array-like objects). The example below illustrates `includes()` method called on the function's arguments (en-US) object.

```js
(function () {
  console.log([].includes.call(arguments, "a")); // true
  console.log([].includes.call(arguments, "d")); // false
})("a", "b", "c");
```

Polyfill
--------

```js
// https://tc39.github.io/ecma262/#sec-array.prototype.includes
if (!Array.prototype.includes) {
  Object.defineProperty(Array.prototype, "includes", {
    value: function (searchElement, fromIndex) {
      if (this == null) {
        throw new TypeError('"this" is null or not defined');
      }

      // 1. Let O be ? ToObject(this value).
      var o = Object(this);

      // 2. Let len be ? ToLength(? Get(O, "length")).
      var len = o.length >>> 0;

      // 3. If len is 0, return false.
      if (len === 0) {
        return false;
      }

      // 4. Let n be ? ToInteger(fromIndex).
      // (If fromIndex is undefined, this step produces the value 0.)
      var n = fromIndex | 0;

      // 5. If n ≥ 0, then
      // a. Let k be n.
      // 6. Else n < 0,
      // a. Let k be len + n.
      // b. If k < 0, let k be 0.
      var k = Math.max(n >= 0 ? n : len - Math.abs(n), 0);

      function sameValueZero(x, y) {
        return (
          x === y ||
          (typeof x === "number" &&
            typeof y === "number" &&
            isNaN(x) &&
            isNaN(y))
        );
      }

      // 7. Repeat, while k < len
      while (k < len) {
        // a. Let elementK be the result of ? Get(O, ! ToString(k)).
        // b. If SameValueZero(searchElement, elementK) is true, return true.
        if (sameValueZero(o[k], searchElement)) {
          return true;
        }
        // c. Increase k by 1.
        k++;
      }

      // 8. Return false
      return false;
    },
  });
}
```

If you need to support truly obsolete JavaScript engines that don't support `Object.defineProperty`, it's best not to polyfill `Array.prototype` methods at all, as you can't make them non-enumerable.

規範
--

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

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

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

參見
--

* `TypedArray.prototype.includes()` (en-US)
* `String.prototype.includes()` (en-US)
* `Array.prototype.indexOf()`
* `Array.prototype.find()`
* `Array.prototype.findIndex()`


Array.prototype.concat() - JavaScript

Array.prototype.concat()
========================

**`concat()`** 方法被用來合併兩個或多個陣列。此方法不會改變現有的陣列，回傳一個包含呼叫者陣列本身的值，作為代替的是回傳一個新陣列。

嘗試一下
----

語法
--
```

var new_array = old_array.concat(value1[, value2[, ...[, valueN]]])
```

### 參數

`valueN`

陣列以及／或者值，用來合併成一個新的陣列。請參閱下方詳細資訊描述。

### 回傳值

一個新的`陣列`實體。

描述
--

`concat` 產生一個由呼叫者陣列自己的元素，以及對每一個參數按照順序，合併參數的元素（如果參數是個陣列）或者是參數自己本身（如果參數不是一個陣列）成為一個新的陣列。`concat` 方法不會遞迴巢狀陣列參數。

`concat` 方法不會改變 `this` 自己本身或是任何被提供當做參數的陣列，取而代之則是回傳一個淺層複製（shallow copy）包含了與原始的陣列中一樣的元素的副本。原始陣列的元素被複製到新的陣列的規則如下所示：

* 物件參考（並非為實際的物件）：`concat` 複製物件的參考至新的陣列。不管是原始的還是新的陣列都參考到相同的物件。也就是說，如果一個被參照的物件被修改了，變動會同時反映到新的以及原始的陣列中。
* 資料型態為字串、數值或是布林（非 `String`、`Number` 及 `Boolean` 物件）：`concat` 複製字串及數值的值到新的陣列。

**備註：** 合併（多個）陣列／（多個）值將讓原始的陣列不會被受到影響。此外，任何對新陣列（只有在元素不是物件參考的情況下）的操作都不會影響原始的陣列，反之亦然。

範例
--

### 合併兩個陣列

下面的程式碼為合併兩個陣列：

```js
var alpha = ["a", "b", "c"];
var numeric = [1, 2, 3];

alpha.concat(numeric);
// 結果: ['a', 'b', 'c', 1, 2, 3]
```

### 合併三個陣列

下面的程式碼為合併三個陣列：

```js
var num1 = [1, 2, 3],
  num2 = [4, 5, 6],
  num3 = [7, 8, 9];

var nums = num1.concat(num2, num3);

console.log(nums);
// 結果：[1, 2, 3, 4, 5, 6, 7, 8, 9]
```

### 合併值到一個陣列

下面的程式碼為合併三個值到一個陣列中：

```js
var alpha = ["a", "b", "c"];

var alphaNumeric = alpha.concat(1, [2, 3]);

console.log(alphaNumeric);
// 結果：['a', 'b', 'c', 1, 2, 3]
```

### 合併巢狀陣列

下面的程式碼為合併巢狀陣列，並證明保留了原本的參考（references）：

```js
var num1 = [[1]];
var num2 = [2, [3]];

var nums = num1.concat(num2);

console.log(nums);
// results in [[1], 2, [3]]

// modify the first element of num1
num1[0].push(4);

console.log(nums);
// results in [[1, 4], 2, [3]]
```

規格
--

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

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

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

參見
--

* `push` / `pop` — 從陣列的尾端加入/移除元素
* `unshift` / `shift` — 從陣列的前端加入/移除元素
* `splice` — 從陣列特定的位置加入/移除元素
* `String.prototype.concat()`
* `Symbol.isConcatSpreadable` (en-US) – 控制扁平化


Array.prototype.findIndex() - JavaScript

Array.prototype.findIndex()
===========================

**`findIndex()`** 方法將依據提供的測試函式，尋找陣列中符合的元素，並返回其 **index**（索引）。如果沒有符合的對象，將返回 -1 。

嘗試一下
----

另請參見 `find()` 方法，它返回陣列中找到的元素的**值**，而不是其索引。

語法
--
```

arr.findIndex(callback[, thisArg])
```

### 參數

`callback`

針對陣列中的每個元素，都會執行該回呼函式，執行時會自動傳入下面三個參數：

`element`

當前元素。

`index`選擇性

當前元素的索引。

`array`選擇性

呼叫 `findIndex` 的陣列。

`thisArg`選擇性

可選的。執行 **callback** 時作為 this 對象的值。

### 回傳值

An index in the array if an element passes the test; otherwise, **-1**.

描述
--

`findIndex` 方法對陣列中的每一個索引：`0..length-1`（含）的元素執行一次 `callback` 直到有一個 `callback` 返回 truthy 值（一個可強制轉型（coerces）為 `true` 的值）。如果找到了一個這樣的元素，則 `findIndex` 將會立刻返回此次迭代的索引。若回呼函式從未回傳一個 truthy 值，或陣列的 `length` 為 0，則 `findIndex` 將會返回 -1。不像其他的陣列方法如 `some` 那樣，於稀疏（sparse）陣列上 `callback` **仍會**被呼叫，即使該索引的項目在陣列中並不存在。

`callback` 被呼叫時會傳入三個參數：元素的值、元素的索引，以及被迭代的陣列物件。

如果一個 `thisArg` 參數被提供給 `findIndex`，它將會被當作 `this` 使用在每次回呼函式被調用的時候。如果沒有被提供，將會使用 `undefined` (en-US)。

`findIndex` 不會修改呼叫此方法的陣列。

在第一次呼叫 `callback` 函式時會確定元素的索引範圍，因此在 `findIndex` 方法開始執行之後添加到陣列的新元素將不會被 `callback` 函式訪問到。如果陣列中一個尚未被 `callback` 函式訪問到的元素的值被 `callback` 函式所改變，那麼當 `callback` 函式訪問到它時，它的值是將是根據它在陣列中的索引所訪問到的當前值；被刪除的元素仍然會被訪問到。

範例
--

### 尋找陣列中首個質數元素的索引

以下的範例演示了如何查找一個陣列中首個質數元素的索引，找不到則返回 -1。

```js
function isPrime(element, index, array) {
  var start = 2;
  while (start <= Math.sqrt(element)) {
    if (element % start++ < 1) {
      return false;
    }
  }
  return element > 1;
}

console.log([4, 6, 8, 12].findIndex(isPrime)); // -1, not found
console.log([4, 6, 7, 12].findIndex(isPrime)); // 2
```

### 使用箭頭函式尋找索引

以下範例為使用箭頭函式尋找水果的索引。

```js
const fruits = ["apple", "banana", "cantaloupe", "blueberries", "grapefruit"];

const index = fruits.findIndex((fruit) => fruit === "blueberries");

console.log(index); // 3
console.log(fruits[index]); // blueberries
```

Polyfill
--------

```js
// https://tc39.github.io/ecma262/#sec-array.prototype.findIndex
if (!Array.prototype.findIndex) {
  Object.defineProperty(Array.prototype, "findIndex", {
    value: function (predicate) {
      // 1. Let O be ? ToObject(this value).
      if (this == null) {
        throw new TypeError('"this" is null or not defined');
      }

      var o = Object(this);

      // 2. Let len be ? ToLength(? Get(O, "length")).
      var len = o.length >>> 0;

      // 3. If IsCallable(predicate) is false, throw a TypeError exception.
      if (typeof predicate !== "function") {
        throw new TypeError("predicate must be a function");
      }

      // 4. If thisArg was supplied, let T be thisArg; else let T be undefined.
      var thisArg = arguments[1];

      // 5. Let k be 0.
      var k = 0;

      // 6. Repeat, while k < len
      while (k < len) {
        // a. Let Pk be ! ToString(k).
        // b. Let kValue be ? Get(O, Pk).
        // c. Let testResult be ToBoolean(? Call(predicate, T, « kValue, k, O »)).
        // d. If testResult is true, return k.
        var kValue = o[k];
        if (predicate.call(thisArg, kValue, k, o)) {
          return k;
        }
        // e. Increase k by 1.
        k++;
      }

      // 7. Return -1.
      return -1;
    },
  });
}
```

如果你需要相容過時的不支援 `Object.defineProperty` 的 JavaScript 引擎，最好不要使用 polyfill 來填充 `Array.prototype` 方法，因為無法使它們成為不可枚舉的（non-enumerable）屬性。

規範
--

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

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

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

參見
--

* `Array.prototype.find()`
* `Array.prototype.indexOf()`


Array.prototype.toString() - JavaScript

Array.prototype.toString()
==========================

**`toString()`** 方法將回傳一個可以表達該陣列及其元素的字串。

嘗試一下
----

語法
--

```js
toString()
```

### 回傳值

一個表達該陣列及該陣列中元素的字串。

描述
--

`Array` 覆寫了 `Object` (en-US) 中的 `toString` 方法。
 陣列的 `toString` 方法會將陣列中的每個元素用逗號串接起來成為一個字串，並回傳該字串。

當你在會以文字型態表示的地方使用了陣列，或是在字串的串接中使用到了陣列，JavaScript 會自動為該陣列使用`toString` 方法。

### ECMAScript 5 語義

 始於 JavaScript 1.8.5 (Firefox 4)，並且和 ECMAScript 5 的語義一致。
 `toString()` 方法是通用的，任何的物件都可以使用。 `Object.prototype.toString()` (en-US) 會被呼叫，並回傳結果。

範例
--

### 如何使用 toString

```js
const array1 = [1, 2, "a", "1a"];

console.log(array1.toString());
// expected output: "1,2,a,1a"
```

規範
--

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

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

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

參見
--

* `Array.prototype.join()`
* `Object.prototype.toSource()` (en-US)


Array.prototype.keys() - JavaScript

Array.prototype.keys()
======================

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

嘗試一下
----

語法
--
```

arr.keys()
```

### 回傳值

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

範例
--

### 鍵迭代器不會乎略陣列中的空元素

```js
var arr = ["a", , "c"];
var sparseKeys = Object.keys(arr);
var denseKeys = [...arr.keys()];
console.log(sparseKeys); // ['0', '2']
console.log(denseKeys); // [0, 1, 2]
```

規範
--

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

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

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

參見
--

* `Array.prototype.values()`
* `Array.prototype.entries()`
* 迭代協議


Array.prototype.unshift() - JavaScript

Array.prototype.unshift()
=========================

**`unshift()`** 方法會添加一個或多個元素至陣列的開頭，並且回傳陣列的新長度。

嘗試一下
----

語法
--
```

arr.unshift(element1[, ...[, elementN]])
```

### 參數

`elementN`

欲添加至陣列開頭的元素。

### 回傳值

呼叫此方法之物件的新 `length` 屬性值。

描述
--

`unshift` 方法會將一或多個給定值插入至一個類陣列（array-like）物件的開頭。

`unshift` 被刻意設計為具通用性；此方法可以藉由 called 或 applied 應用於類似陣列的物件上。若欲應用此方法的物件不包含代表一系列啟始為零之數字屬性序列長度的 `length` 屬性，可能是不具任何意義的行為。

範例
--

```js
var arr = [1, 2];

arr.unshift(0); // 執行後的結果是3，其代表處理後的陣列長度
// arr is [0, 1, 2]

arr.unshift(-2, -1); // = 5
// arr is [-2, -1, 0, 1, 2]

arr.unshift([-3]);
// arr is [[-3], -2, -1, 0, 1, 2]
```

規範
--

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

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

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

參見
--

* `Array.prototype.push()`
* `Array.prototype.pop()`
* `Array.prototype.shift()`
* `Array.prototype.concat()`


Array.prototype.push() - JavaScript

Array.prototype.push()
======================

**`push()`** 方法會添加一個或多個元素至陣列的末端，並且回傳陣列的新長度。

嘗試一下
----

語法
--

```js
arr.push(element1[, ...[, elementN]])
```

### 參數

`elementN`

欲添加至陣列末端的元素。

### 回傳值

呼叫此方法之物件的新 `length` 屬性值。

描述
--

`push` 方法會將一或多個值加入至一個陣列中。

`push` 方法被刻意設計為具通用性；此方法可以藉由 `call()` 或 `apply()` 應用於類似陣列的物件上。`push` 方法憑借著物件的 `length` 屬性來判斷從何處開始插入給定的值。如果 `length` 屬性無法被轉為數字，則索引值會使用 0。這包括了 `length` 可能不存在的狀況，在這個情況下 `length` 屬性也將被建立於物件中。

唯一的原生類陣列（array-like）物件為字串，但他們不適合用於此方法，因為字串是不可變的（immutable）。

範例
--

### 將複數個元素添加至陣列

以下的程式碼會建立含有兩個元素的陣列 `sports`，接著再增加兩個元素至陣列中。新的長度以變數 `total` 表示。

```js
var sports = ["soccer", "baseball"];
var total = sports.push("football", "swimming");

console.log(sports); // ['soccer', 'baseball', 'football', 'swimming']
console.log(total); // 4
```

### 合併兩個陣列

這個範例使用 `apply()` 自第二個陣列中增加所有的元素至第一個陣列。

如果第二個陣列（範例中的 `moreVegs`）非常大，就不要使用這個方法。因為一個函式能取得的參數之最大數量是受到實作限制的。詳細請參閱 `apply()`。

```js
var vegetables = ["parsnip", "potato"];
var moreVegs = ["celery", "beetroot"];

// Merge the second array into the first one
// Equivalent to vegetables.push('celery', 'beetroot');
Array.prototype.push.apply(vegetables, moreVegs);

console.log(vegetables); // ['parsnip', 'potato', 'celery', 'beetroot']
```

### 以類陣列（array-like）的方式操作物件

正如上面所提到的，`push` 被刻意設計為具通用性，我們可以善用這個優勢來處理物件。`Array.prototype.push` 可以在物件上運作良好，如本範例所示。請注意，我們不會建立一個陣列來儲存收集到的物件。相反地，我們將物件集合（collection）儲存於物件自己身上，並使用 `call` 來呼叫`Array.prototype.push` 使其認為我們正在處理一個陣列，讓方法可以繼續運作。感謝 JavaScript 允許我們使用這個方式去執行上下文。

```js
var obj = {
  length: 0,

  addElem: function addElem(elem) {
    // obj.length is automatically incremented
    // every time an element is added.
    [].push.call(this, elem);
  },
};

// Let's add some empty objects just to illustrate.
obj.addElem({});
obj.addElem({});
console.log(obj.length);
// → 2
```

請注意雖然 `obj` 不是一個陣列，但 `push` 方法成功增加了 `obj` 的 `length` 屬性，就像我們在處理一個真正的陣列一樣。

規範
--

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

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

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

參見
--

* `Array.prototype.pop()`
* `Array.prototype.shift()`
* `Array.prototype.unshift()`
* `Array.prototype.concat()`


Array.prototype.reduce() - JavaScript

Array.prototype.reduce()
========================

**`reduce()`** 方法將一個累加器及陣列中每項元素（由左至右）傳入回呼函式，將陣列化為單一值。

嘗試一下
----

語法
--

```js
arr.reduce(callback[accumulator, currentValue, currentIndex, array], initialValue)
```

### 參數

* `callback`
    + : 用於處理陣列中每個元素的函式，可傳入四個參數：

    `accumulator`

    用來累積回呼函式回傳值的累加器（accumulator）或 `initialValue`（若有提供的話，詳如下敘）。累加器是上一次呼叫後，所回傳的累加數值。

    `currentValue`

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

    `currentIndex` 選擇性

    原陣列目前所迭代處理中的元素之索引。若有傳入 `initialValue`，則由索引 0 之元素開始，若無則自索引 1 之元素開始。

    `array` 選擇性

    呼叫 `reduce()` 方法的陣列。
    + `initialValue` 選擇性
        - : 於第一次呼叫 `callback` 時要傳入的累加器初始值。若沒有提供初始值，則原陣列的第一個元素將會被當作初始的累加器。假如於一個空陣列呼叫 `reduce()` 方法且沒有提供累加器初始值，將會發生錯誤。
### 回傳值

簡化後的結果值。

描述
--

`reduce()` 會對每一個目前迭代到的陣列元素（除了空值以外）執行 `callback` 函式，回呼函式會接收四個參數：

* `accumulator`
* `currentValue`
* `currentIndex`
* `array`

當回呼函式第一次被呼叫時，`accumulator` 與 `currentValue` 的值可能為兩種不同的狀況：若在呼叫 `reduce()` 時有提供 `initialValue`，則 `accumulator` 將會等於 `initialValue`，且 `currentValue` 會等於陣列中的第一個元素值；若沒有提供 `initialValue`，則 `accumulator` 會等於陣列的第一個元素值，且 `currentValue` 將會等於陣列的第二個元素值。

**備註：** 假如 `initialValue` 未被提供，`reduce()` 將會跳過第一個陣列索引，從陣列索引 1 開始執行回呼函式。若有提供 `initialValue`，則會由陣列索引 0 開始執行。

若陣列為空且沒有提供 `initialValue`，將會拋出 `TypeError` (en-US)。假如陣列只有一個元素（無論其索引位置為何）並且沒有提供 `initialValue`，或如果提供了 `initialValue` 但陣列為空，則此唯一的值將會被直接回傳*而不會呼叫 `callback` 函式*。

提供累加器初始值通常較為安全，因為在沒有傳入 `initialValue` 的情況下會有三種可能的輸出結果，如下列範例：

```js
var maxCallback = (acc, cur) => Math.max(acc.x, cur.x);
var maxCallback2 = (max, cur) => Math.max(max, cur);

// reduce() without initialValue
[{ x: 22 }, { x: 42 }].reduce(maxCallback); // 42
[{ x: 22 }].reduce(maxCallback); // { x: 22 }
[].reduce(maxCallback); // TypeError

// map/reduce; better solution, also works for empty or larger arrays
[{ x: 22 }, { x: 42 }].map((el) => el.x).reduce(maxCallback2, -Infinity);
```

### reduce() 如何運作

假設 `reduce()` 以下例方式使用：

```js
[0, 1, 2, 3, 4].reduce(
  function (accumulator, currentValue, currentIndex, array) {
    return accumulator + currentValue;
  },
);
```

所傳入的回呼函式將被呼叫四次，所傳入的參數與回傳值如下所示：

| `callback` | `accumulator` | `currentValue` | `currentIndex` | `array` | return value |
| --- | --- | --- | --- | --- | --- |
| first call | `0` | `1` | `1` | `[0, 1, 2, 3, 4]` | `1` |
| second call | `1` | `2` | `2` | `[0, 1, 2, 3, 4]` | `3` |
| third call | `3` | `3` | `3` | `[0, 1, 2, 3, 4]` | `6` |
| fourth call | `6` | `4` | `4` | `[0, 1, 2, 3, 4]` | `10` |

`reduce()` 的最終回傳值將會是最後一次呼叫回呼函式的回傳值 (`10`)。

你也可以傳入一個箭頭函式來替代一個完整的函式。下方的程式碼執行的結果將與前述例子相同。

```js
[0, 1, 2, 3, 4].reduce((prev, curr) => prev + curr);
```

如果你有提供第二個參數值給 `reduce()`，執行的結果如下：

```js
[0, 1, 2, 3, 4].reduce((accumulator, currentValue, currentIndex, array) => {
  return accumulator + currentValue;
}, 10);
```

| `callback` | `accumulator` | `currentValue` | `currentIndex` | `array` | return value |
| --- | --- | --- | --- | --- | --- |
| first call | `10` | `0` | `0` | `[0, 1, 2, 3, 4]` | `10` |
| second call | `10` | `1` | `1` | `[0, 1, 2, 3, 4]` | `11` |
| third call | `11` | `2` | `2` | `[0, 1, 2, 3, 4]` | `13` |
| fourth call | `13` | `3` | `3` | `[0, 1, 2, 3, 4]` | `16` |
| fifth call | `16` | `4` | `4` | `[0, 1, 2, 3, 4]` | `20` |

`reduce()` 執行的結果將會是 `20`。

範例
--

### 加總所有陣例之元素值

```js
var sum = [0, 1, 2, 3].reduce(function (a, b) {
  return a + b;
}, 0);
// sum is 6
```

另外，也可以寫成箭頭函式：

```js
var total = [0, 1, 2, 3].reduce((acc, cur) => acc + cur, 0);
```

### 攤平一個多維陣列

```js
var flattened = [
  [0, 1],
  [2, 3],
  [4, 5],
].reduce(function (a, b) {
  return a.concat(b);
}, []);
// flattened is [0, 1, 2, 3, 4, 5]
```

另外，也可以寫成箭頭函式：

```js
var flattened = [
  [0, 1],
  [2, 3],
  [4, 5],
].reduce((acc, cur) => acc.concat(cur), []);
```

### 計算相同元素數量並以物件鍵值顯示

```js
var names = ["Alice", "Bob", "Tiff", "Bruce", "Alice"];

var countedNames = names.reduce(function (allNames, name) {
  if (name in allNames) {
    allNames[name]++;
  } else {
    allNames[name] = 1;
  }
  return allNames;
}, {});
// countedNames is:
// { 'Alice': 2, 'Bob': 1, 'Tiff': 1, 'Bruce': 1 }
```

### 使用 spread 運算子與給定初始值，結合物件中的陣列元素

```js
// friends - an array of objects
// where object field "books" - list of favorite books
var friends = [
  {
    name: "Anna",
    books: ["Bible", "Harry Potter"],
    age: 21,
  },
  {
    name: "Bob",
    books: ["War and peace", "Romeo and Juliet"],
    age: 26,
  },
  {
    name: "Alice",
    books: ["The Lord of the Rings", "The Shining"],
    age: 18,
  },
];

// allbooks - list which will contain all friends' books +
// additional list contained in initialValue
var allbooks = friends.reduce(
  function (prev, curr) {
    return [...prev, ...curr.books];
  },
  ["Alphabet"],
);

// allbooks = [
// 'Alphabet', 'Bible', 'Harry Potter', 'War and peace',
// 'Romeo and Juliet', 'The Lord of the Rings',
// 'The Shining'
// ]
```

### 移除陣列中的重複項目

```js
let arr = [1, 2, 1, 2, 3, 5, 4, 5, 3, 4, 4, 4, 4];
let result = arr.sort().reduce((init, current) => {
  if (init.length === 0 || init[init.length - 1] !== current) {
    init.push(current);
  }
  return init;
}, []);
console.log(result); //[1,2,3,4,5]
```

### 序列執行 Promise

```js
/\*\*
 \* Runs promises from promise array in chained manner
 \*
 \* @param {array} arr - promise arr
 \* @return {Object} promise object
 \*/
function runPromiseInSequense(arr) {
  return arr.reduce((promiseChain, currentPromise) => {
    return promiseChain.then((chainedResult) => {
      return currentPromise(chainedResult).then((res) => res);
    });
  }, Promise.resolve());
}

// promise function 1
function p1() {
  return new Promise((resolve, reject) => {
    resolve(5);
  });
}

// promise function 2
function p2(a) {
  return new Promise((resolve, reject) => {
    resolve(a \* 2);
  });
}

// promise function 3
function p3(a) {
  return new Promise((resolve, reject) => {
    resolve(a \* 3);
  });
}

const promiseArr = [p1, p2, p3];
runPromiseInSequense(promiseArr).then((res) => {
  console.log(res); // 30
});
```

Polyfill
--------

```js
// Production steps of ECMA-262, Edition 5, 15.4.4.21
// Reference: http://es5.github.io/#x15.4.4.21
// https://tc39.github.io/ecma262/#sec-array.prototype.reduce
if (!Array.prototype.reduce) {
  Object.defineProperty(Array.prototype, "reduce", {
    value: function (callback /\*, initialValue\*/) {
      if (this === null) {
        throw new TypeError(
          "Array.prototype.reduce " + "called on null or undefined",
        );
      }
      if (typeof callback !== "function") {
        throw new TypeError(callback + " is not a function");
      }

      // 1. Let O be ? ToObject(this value).
      var o = Object(this);

      // 2. Let len be ? ToLength(? Get(O, "length")).
      var len = o.length >>> 0;

      // Steps 3, 4, 5, 6, 7
      var k = 0;
      var value;

      if (arguments.length >= 2) {
        value = arguments[1];
      } else {
        while (k < len && !(k in o)) {
          k++;
        }

        // 3. If len is 0 and initialValue is not present,
        // throw a TypeError exception.
        if (k >= len) {
          throw new TypeError(
            "Reduce of empty array " + "with no initial value",
          );
        }
        value = o[k++];
      }

      // 8. Repeat, while k < len
      while (k < len) {
        // a. Let Pk be ! ToString(k).
        // b. Let kPresent be ? HasProperty(O, Pk).
        // c. If kPresent is true, then
        // i. Let kValue be ? Get(O, Pk).
        // ii. Let accumulator be ? Call(
        // callbackfn, undefined,
        // « accumulator, kValue, k, O »).
        if (k in o) {
          value = callback(value, o[k], k, o);
        }

        // d. Increase k by 1.
        k++;
      }

      // 9. Return accumulator.
      return value;
    },
  });
}
```

如果還需要支援老舊到不支援 `Object.defineProperty` 的 JavaScript 引擎，最好不要 polyfill `Array.prototype` 方法，因為你無法令其不可枚舉（non-enumerable）。

規範
--

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

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

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

參見
--

* `Array.prototype.reduceRight()` (en-US)


Array.prototype.shift() - JavaScript

Array.prototype.shift()
=======================

**`shift()`** 方法會移除並回傳陣列的**第一個**元素。此方法會改變陣列的長度。

嘗試一下
----

語法
--

```js
arr.shift()
```

### 回傳值

自陣列中移除的元素；若陣列為空，則為 `undefined` (en-US)。

描述
--

`shift` 方法會移除並回傳陣列中索引值為零之元素（即第一個元素），並將隨後的其他索引值減一。假如 `length` 屬性值為 0，則會回傳 `undefined` (en-US)。

`shift` 方法被刻意設計為具通用性；此方法可以藉由 called 或 applied 應用於類似陣列的物件上。若欲應用此方法的物件不包含代表一系列啟始為零之數字屬性序列長度的 `length` 屬性，可能是不具任何意義的行為。

範例
--

### 自陣列中移除一個元素

以下的程式碼會印出 `myFish` 陣列在移除第一個元素之前跟之後的內容，也印出了被移除的元素：

```js
var myFish = ["angel", "clown", "mandarin", "surgeon"];

console.log("myFish before:", JSON.stringify(myFish));
// myFish before: ['angel', 'clown', 'mandarin', 'surgeon']

var shifted = myFish.shift();

console.log("myFish after:", myFish);
// myFish after: ['clown', 'mandarin', 'surgeon']

console.log("Removed this element:", shifted);
// Removed this element: angel
```

### 於 while 迴圈中使用 shift() 方法

`shift()` 方法常被用在 while 迴圈中的條件判斷。在下面的例子，每一次迭代都將會自陣列中移除下一個元素，直到陣列空了為止：

```js
var names = ["Andrew", "Edward", "Paul", "Chris", "John"];

while ((i = names.shift()) !== undefined) {
  console.log(i);
}
// Andrew, Edward, Paul, Chris, John
```

規範
--

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

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

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

參見
--

* `Array.prototype.push()`
* `Array.prototype.pop()`
* `Array.prototype.unshift()`
* `Array.prototype.concat()`


Array.prototype.find() - JavaScript

Array.prototype.find()
======================

**`find()`** 方法會回傳第一個滿足所提供之測試函式的元素**值**。否則回傳 `undefined` (en-US)。

嘗試一下
----

也可以參考 `findIndex()` 方法，它回傳被找到的元素在陣列中的**索引**，而不是它的值。

If you need to find the position of an element or whether an element exists in an array, use `Array.prototype.indexOf()` or `Array.prototype.includes()`.

語法
--
```

arr.find(callback[, thisArg])
```

### 參數

`callback`

會處理陣列中每個元素的函數，它使用三個參數：

`element`

在陣列中正被處理的元素。

`index`選擇性

在陣列中正被處理的元素的索引。

`array`選擇性

呼叫 `find` 的陣列。

`thisArg` `選擇性`

執行 `callback` 函式時被當作 `this` 的物件。

### 回傳值

若元素通過測試則為其值；否則為 `undefined` (en-US)。

描述
--

`find` 方法會對每個元素執行一次 `callback` 函式，直到找到一個讓 `callback` 函式回傳 true 的元素。當元素被找到的時候，`find` 會立刻回傳該元素，否則 `find` 會回傳 `undefined` (en-US)。`callback` 會被使用於陣列索引自 `0` 至 `length - 1`，並會被用於每一個的陣列索引，而不僅是那些有賦值的索引。這代表此方法在稀疏陣列（sparse arrays）上的效能可能較其他只存取已賦值索引的方法來的差。

`callback` 函式被呼叫時會傳入三個參數：元素的值、元素索引，以及正被迭代的陣列物件。

如果提供 `thisArg` 參數予 `find`，其將會被當作 `callback` 每次被呼叫的 `this`。若是沒提供，則會使用 `undefined` (en-US)。

`find` 並不會改變呼叫該方法的陣列。

The range of elements processed by `find` is set before the first invocation of `callback`. Elements that are appended to the array after the call to `find` begins will not be visited by `callback`. If an existing, unvisited element of the array is changed by `callback`, its value passed to the visiting `callback` will be the value at the time that `find` visits that element's index; elements that are deleted are still visited.

範例
--

### Find an object in an array by one of its properties

```js
var inventory = [
  { name: "apples", quantity: 2 },
  { name: "bananas", quantity: 0 },
  { name: "cherries", quantity: 5 },
];

function isCherries(fruit) {
  return fruit.name === "cherries";
}

console.log(inventory.find(isCherries));
// { name: 'cherries', quantity: 5 }
```

### 在陣列中找質數

以下範例在陣列中找出一個屬於質數的元素，如果裡面不含質數則回傳 `undefined` (en-US)。

```js
function isPrime(element, index, array) {
  var start = 2;
  while (start <= Math.sqrt(element)) {
    if (element % start++ < 1) {
      return false;
    }
  }
  return element > 1;
}

console.log([4, 6, 8, 12].find(isPrime)); // undefined, not found
console.log([4, 5, 8, 12].find(isPrime)); // 5
```

The following examples show that non-existent and deleted elements are visited and that the value passed to the callback is their value when visited.

```js
// Declare array with no element at index 2, 3 and 4
var a = [0, 1, , , , 5, 6];

// Shows all indexes, not just those that have been assigned values
a.find(function (value, index) {
  console.log("Visited index " + index + " with value " + value);
});

// Shows all indexes, including deleted
a.find(function (value, index) {
  // Delete element 5 on first iteration
  if (index == 0) {
    console.log("Deleting a[5] with value " + a[5]);
    delete a[5];
  }
  // Element 5 is still visited even though deleted
  console.log("Visited index " + index + " with value " + value);
});
```

Polyfill
--------

這個方法在 ECMAScript 2015 中首次被規範，可能尚未在所有 JavaScript 應用中被實作。你可以使用以下程式片段來 polyfill `Array.prototype.find`：

```js
// https://tc39.github.io/ecma262/#sec-array.prototype.find
if (!Array.prototype.find) {
  Object.defineProperty(Array.prototype, "find", {
    value: function (predicate) {
      // 1. Let O be ? ToObject(this value).
      if (this == null) {
        throw new TypeError('"this" is null or not defined');
      }

      var o = Object(this);

      // 2. Let len be ? ToLength(? Get(O, "length")).
      var len = o.length >>> 0;

      // 3. If IsCallable(predicate) is false, throw a TypeError exception.
      if (typeof predicate !== "function") {
        throw new TypeError("predicate must be a function");
      }

      // 4. If thisArg was supplied, let T be thisArg; else let T be undefined.
      var thisArg = arguments[1];

      // 5. Let k be 0.
      var k = 0;

      // 6. Repeat, while k < len
      while (k < len) {
        // a. Let Pk be ! ToString(k).
        // b. Let kValue be ? Get(O, Pk).
        // c. Let testResult be ToBoolean(? Call(predicate, T, « kValue, k, O »)).
        // d. If testResult is true, return kValue.
        var kValue = o[k];
        if (predicate.call(thisArg, kValue, k, o)) {
          return kValue;
        }
        // e. Increase k by 1.
        k++;
      }

      // 7. Return undefined.
      return undefined;
    },
  });
}
```

If you need to support truly obsolete JavaScript engines that don't support `Object.defineProperty`, it's best not to polyfill `Array.prototype` methods at all, as you can't make them non-enumerable.

規範
--

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

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

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

參見
--

* `Array.prototype.findIndex()` – find and return an index
* `Array.prototype.includes()` – test whether a value exists in the array
* `Array.prototype.filter()` – find all matching elements
* `Array.prototype.every()` (en-US) – test all elements together


Array.prototype.map() - JavaScript

Array.prototype.map()
=====================

**`map()`** 方法會建立一個新的陣列，其內容為原陣列的每一個元素經由回呼函式運算後所回傳的結果之集合。

嘗試一下
----

語法
--
```

let new_array = arr.map(function callback( currentValue[, index[, array]]) {
    // return element for new_array
}[, thisArg])
```

### 參數

`callback`

呼叫 `arr` 所有元素的回呼函式。新數值會在每次執行 `callback` 時加到 `new_array`。

`callback` 函式可傳入以下三個參數：

`currentValue`

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

`index`選擇性

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

`array`選擇性

呼叫 `map` 方法的陣列。

`thisArg`選擇性

選擇性的參數。執行 `callback` 回呼函式的 `this` 值。

### 回傳值

一個所有元素皆為回呼函式運算結果的新陣列。

描述
--

`map` 會將所有陣列中的元素依序**分別傳入一次**至 `callback` 函式當中，並以此回呼函式每一次被呼叫的回傳值來建構一個新的陣列。`callback` 函式只會於陣列目前迭代之索引有指派值時（包含`undefined` (en-US)）被調用，而在該陣列索引沒有元素時（即未被設定的索引：已被刪除或從未被賦值）並不會呼叫回呼函式。

它*並不能*呼叫以下元素：

* 不存在的索引、
* 沒被刪除、
* 沒被賦值。
### 什麼時候*不要用* map()

因為 `map` 會建立新的陣列，如果在不想建立新陣列時使用該方法，就會變成反模式（anti-pattern）：這種情況下，要使用 `forEach` (en-US) 或 `for-of` (en-US)。

以下情況不應該使用 `map`；

1. 不使用回傳的新陣列，
2. 或/且不需要回傳新陣列。

`callback` 函式於被調用時會傳入三個參數：元素值、元素之索引、以及被迭代的陣列物件。

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

`map` 不會修改呼叫它的原始陣列（雖然在 `callback` 執行時有可能會這麼做）。

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

依據規範中定義的演算法，若呼叫 `map` 方法的原始陣列為一稀疏（sparse）陣列，則回傳的新陣列也會是在同樣索引中留空的稀疏陣列。

範例
--

### 把一個數字陣列轉換成對應的開根號後的數字陣列

以下的程式碼把一個數字陣列(array of numbers) 轉換成一個 **新的**以該數字陣列裡的一個個數做開根號計算的數字陣列.

```js
var numbers = [1, 4, 9];
var roots = numbers.map(Math.sqrt); //map會return一個新的array
// roots 現在是 [1, 2, 3]
/\* numbers 還是 [1, 4, 9]，這證明了 map() 不會去變動到 numbers 的值，
 map 內部是做了 immutable 的機制，Array.prototype 底下的這些高階函式
 大多都具有這樣函數式編程裡非常注重的特性 - immutable，不會去改變資料
 來源本身原有的值
\*/
```

### 使用 map 將陣列中的物件變更格式

以下程式碼取出一陣列，將其中物件變更格式後建立為一個新的陣列並傳回。

```js
var kvArray = [
  { key: 1, value: 10 },
  { key: 2, value: 20 },
  { key: 3, value: 30 },
];

var reformattedArray = kvArray.map(function (obj) {
  var rObj = {};
  rObj[obj.key] = obj.value;
  return rObj;
});

// reformattedArray 現在是 [{1: 10}, {2: 20}, {3: 30}],

// kvArray 仍然是：
// [{key: 1, value: 10},
// {key: 2, value: 20},
// {key: 3, value: 30}]
```

### 使用帶參數的函式將一數字陣列進行對應

以下程式碼示範如何使用帶有一個參數的函式來操作 map。這個參數會自動地逐一取出原始陣列中各個元素來使用。

```js
var numbers = [1, 4, 9];
var doubles = numbers.map(function (num) {
  return num \* 2;
});

// doubles 現在是 [2, 8, 18]
// numbers 仍然是 [1, 4, 9]
```

### 使用 `map` 於泛型陣列

以下範例示範如何將一個 `String` 陣列轉換為 byte 陣列:

```js
var map = Array.prototype.map;
var a = map.call("Hello World", function (x) {
  return x.charCodeAt(0);
});
// a 現在等於 [72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100]
```

### 使用 `map` 遍歷 `querySelectorAll`

本範例將展示如何遍歷由 `querySelectorAll` 所產生的物件。我們將得到所有的選項、並印在主控台上：

```js
var elems = document.querySelectorAll("select option:checked");
var values = Array.prototype.map.call(elems, function (obj) {
  return obj.value;
});
```

如果用上 `Array.from()` 方法的話會更簡單。

### 棘手的範例

（透過連結的部落格啟發）

透過一個（被遍歷元素的）參數叫出回調是個常見的用法。有些函式也常常在含有其他可選參數的情況下，使用上一個參數。這種行為常常會給人帶來困惑。

```js
// Consider:
["1", "2", "3"].map(parseInt);
// 以為會是 [1, 2, 3] 嗎
// 其實是 [1, NaN, NaN]

// parseInt 通常只用上一個參數 argument，但他其實用了兩個：
// 第一個是表達式，第二個則是進位數。
// 對該回呼函式來說 Array.prototype.map 帶了三個參數：
// 元素、索引、陣列
// 第三個參數會被 parseInt 忽略，但它可不會忽略第二個，
// 因此可能造成困惑。可以去看上面提到的部落格文章以獲知詳情。

function returnInt(element) {
  return parseInt(element, 10);
}

["1", "2", "3"].map(returnInt); // [1, 2, 3]
// Actual result is an array of numbers (as expected)

// Same as above, but using the concise arrow function syntax
["1", "2", "3"].map((str) => parseInt(str));

// A simpler way to achieve the above, while avoiding the "gotcha":
["1", "2", "3"].map(Number); // [1, 2, 3]
// but unlike `parseInt` will also return a float or (resolved) exponential notation:
["1.1", "2.2e2", "3e300"].map(Number); // [1.1, 220, 3e+300]
```

Polyfill
--------

`map` was added to the ECMA-262 standard in the 5th edition; as such it may not be present in all implementations of the standard. You can work around this by inserting the following code at the beginning of your scripts, allowing use of `map` 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), and `Array` have their original values and that `callback.call` evaluates to the original value of `Function.prototype.call`.

```js
// Production steps of ECMA-262, Edition 5, 15.4.4.19
// Reference: http://es5.github.io/#x15.4.4.19
if (!Array.prototype.map) {
  Array.prototype.map = function (callback /\*, thisArg\*/) {
    var T, A, k;

    if (this == null) {
      throw new TypeError("this is null or not defined");
    }

    // 1. Let O be the result of calling ToObject passing the |this|
    // value as the argument.
    var O = Object(this);

    // 2. Let lenValue be the result of calling the Get internal
    // method of O with the argument "length".
    // 3. Let len be ToUint32(lenValue).
    var len = O.length >>> 0;

    // 4. If IsCallable(callback) is false, throw a TypeError exception.
    // See: http://es5.github.com/#x9.11
    if (typeof callback !== "function") {
      throw new TypeError(callback + " is not a function");
    }

    // 5. If thisArg was supplied, let T be thisArg; else let T be undefined.
    if (arguments.length > 1) {
      T = arguments[1];
    }

    // 6. Let A be a new array created as if by the expression new Array(len)
    // where Array is the standard built-in constructor with that name and
    // len is the value of len.
    A = new Array(len);

    // 7. Let k be 0
    k = 0;

    // 8. Repeat, while k < len
    while (k < len) {
      var kValue, mappedValue;

      // a. Let Pk be ToString(k).
      // This is implicit for LHS operands of the in operator
      // b. Let kPresent be the result of calling the HasProperty internal
      // method of O with argument Pk.
      // This step can be combined with c
      // c. If kPresent is true, then
      if (k in O) {
        // i. Let kValue be the result of calling the Get internal
        // method of O with argument Pk.
        kValue = O[k];

        // ii. Let mappedValue be the result of calling the Call internal
        // method of callback with T as the this value and argument
        // list containing kValue, k, and O.
        mappedValue = callback.call(T, kValue, k, O);

        // iii. Call the DefineOwnProperty internal method of A with arguments
        // Pk, Property Descriptor
        // { Value: mappedValue,
        // Writable: true,
        // Enumerable: true,
        // Configurable: true },
        // and false.

        // In browsers that support Object.defineProperty, use the following:
        // Object.defineProperty(A, k, {
        // value: mappedValue,
        // writable: true,
        // enumerable: true,
        // configurable: true
        // });

        // For best browser support, use the following:
        A[k] = mappedValue;
      }
      // d. Increase k by 1.
      k++;
    }

    // 9. return A
    return A;
  };
}
```

規範
--

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

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

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

參見
--

* `Array.prototype.forEach()` (en-US)
* `Map` object
* `Array.from()`


Array.prototype.indexOf() - JavaScript

Array.prototype.indexOf()
=========================

**`indexOf()`** 方法會回傳給定元素於陣列中第一個被找到之索引，若不存在於陣列中則回傳 -1。

**備註：** 若是調用字串的方法，請參閱 `String.prototype.indexOf()` (en-US)。

嘗試一下
----

語法
--
```

arr.indexOf(searchElement[, fromIndex])
```

### 參數

`searchElement`

欲在陣列中搜尋的元素。

`fromIndex` 選擇性

陣列中搜尋的起始索引。若這個索引值大於或等於陣列長度，會直接回傳 -1，意即不會在陣列中搜尋。如果索引值是一個負數，會從陣列的最後一個往回算，最後一個的索引值為 -1，以此類推。注意：儘管往回算，但依然會從左往右全部搜尋。如果負數索引值在回頭計算之後仍然小於 0，則會從左往右全部搜尋。 這個參數的預設值為 0（即搜尋整個陣列）。

### 回傳值

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

說明
--

`indexOf()` 用嚴格相等（strict equality，`===`） (en-US)的方式比較陣列中的元素與 `searchElement` 是否相等。

範例
--

### 使用 `indexOf()`

下面範例使用`indexOf()`來定位在陣列中的值。

```js
var array = [2, 9, 9];
array.indexOf(2); // 0
array.indexOf(7); // -1
array.indexOf(9, 2); // 2
array.indexOf(2, -1); // -1
array.indexOf(2, -3); // 0
```

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

```js
var indices = [];
var array = ["a", "b", "a", "c", "a", "d"];
var element = "a";
var idx = array.indexOf(element);
while (idx != -1) {
  indices.push(idx);
  idx = array.indexOf(element, idx + 1);
}
console.log(indices);
// [0, 2, 4]
```

### 尋找元素是否存在於陣列中，若沒有則加入到陣列裡

```js
function updateVegetablesCollection(veggies, veggie) {
  if (veggies.indexOf(veggie) === -1) {
    veggies.push(veggie);
    console.log("New veggies collection is : " + veggies);
  } else if (veggies.indexOf(veggie) > -1) {
    console.log(veggie + " already exists in the veggies collection.");
  }
}

var veggies = ["potato", "tomato", "chillies", "green-pepper"];

updateVegetablesCollection(veggies, "spinach");
// New veggies collection is : potato,tomato,chillies,green-pepper,spinach
updateVegetablesCollection(veggies, "spinach");
// spinach already exists in the veggies collection.
```

Polyfill
--------

`indexOf()` was added to the ECMA-262 standard in the 5th edition; as such it may not be present in all browsers. You can work around this by utilizing the following code at the beginning of your scripts. This will allow you to use `indexOf()` when there is still no native support. This algorithm matches the one specified in ECMA-262, 5th edition, assuming `TypeError` (en-US) and `Math.abs()` (en-US) have their original values.

```js
if (!Array.prototype.indexOf) {
  Array.prototype.indexOf = function indexOf(member, startFrom) {
    /\*
 In non-strict mode, if the `this` variable is null or undefined, then it is
 set to the window object. Otherwise, `this` is automatically converted to an
 object. In strict mode, if the `this` variable is null or undefined, a
 `TypeError` is thrown.
 \*/
    if (this == null) {
      throw new TypeError(
        "Array.prototype.indexOf() - can't convert `" + this + "` to object",
      );
    }

    var index = isFinite(startFrom) ? Math.floor(startFrom) : 0,
      that = this instanceof Object ? this : new Object(this),
      length = isFinite(that.length) ? Math.floor(that.length) : 0;

    if (index >= length) {
      return -1;
    }

    if (index < 0) {
      index = Math.max(length + index, 0);
    }

    if (member === undefined) {
      /\*
 Since `member` is undefined, keys that don't exist will have the same
 value as `member`, and thus do need to be checked.
 \*/
      do {
        if (index in that && that[index] === undefined) {
          return index;
        }
      } while (++index < length);
    } else {
      do {
        if (that[index] === member) {
          return index;
        }
      } while (++index < length);
    }

    return -1;
  };
}
```

However, if you are more interested in all the little technical bits defined by the ECMA standard, and are less concerned about performance or conciseness, then you may find this more descriptive polyfill to be more usefull.

```js
// Production steps of ECMA-262, Edition 5, 15.4.4.14
// Reference: http://es5.github.io/#x15.4.4.14
if (!Array.prototype.indexOf) {
  Array.prototype.indexOf = function (searchElement, fromIndex) {
    var k;

    // 1. Let o be the result of calling ToObject passing
    // the this value as the argument.
    if (this == null) {
      throw new TypeError('"this" is null or not defined');
    }

    var o = Object(this);

    // 2. Let lenValue be the result of calling the Get
    // internal method of o with the argument "length".
    // 3. Let len be ToUint32(lenValue).
    var len = o.length >>> 0;

    // 4. If len is 0, return -1.
    if (len === 0) {
      return -1;
    }

    // 5. If argument fromIndex was passed let n be
    // ToInteger(fromIndex); else let n be 0.
    var n = fromIndex | 0;

    // 6. If n >= len, return -1.
    if (n >= len) {
      return -1;
    }

    // 7. If n >= 0, then Let k be n.
    // 8. Else, n<0, Let k be len - abs(n).
    // If k is less than 0, then let k be 0.
    k = Math.max(n >= 0 ? n : len - Math.abs(n), 0);

    // 9. Repeat, while k < len
    while (k < len) {
      // a. Let Pk be ToString(k).
      // This is implicit for LHS operands of the in operator
      // b. Let kPresent be the result of calling the
      // HasProperty internal method of o with argument Pk.
      // This step can be combined with c
      // c. If kPresent is true, then
      // i. Let elementK be the result of calling the Get
      // internal method of o with the argument ToString(k).
      // ii. Let same be the result of applying the
      // Strict Equality Comparison Algorithm to
      // searchElement and elementK.
      // iii. If same is true, return k.
      if (k in o && o[k] === searchElement) {
        return k;
      }
      k++;
    }
    return -1;
  };
}
```

規範
--

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

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

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].indexOf(0, -0)` will now always return `+0` (Firefox bug 1242043).
參見
--

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


Array.prototype.pop() - JavaScript

Array.prototype.pop()
=====================

**`pop()`** 方法會移除並回傳陣列的**最後一個**元素。此方法會改變陣列的長度。

嘗試一下
----

語法
--
```

arr.pop()
```

### 回傳值

自陣列中移除的元素；若陣列為空，則為 `undefined` (en-US)。

描述
--

`pop` 方法會移除陣列中的最後一個元素，並將該值回傳給呼叫者。

`pop` 方法被刻意設計為具通用性；此方法可以藉由 called 或 applied 應用於類似陣列的物件上。若欲應用此方法的物件不包含代表一系列啟始為零之數字屬性序列長度的 `length` 屬性，可能是不具任何意義的行為。

如果於空陣列呼叫 `pop()`，將會回傳 `undefined` (en-US)。

範例
--

### 移除陣列的最後一個元素

下面的程式碼為一個包含四個元素的 `myFish` 陣列，接著移除此陣列的最後一個元素。

```js
var myFish = ["angel", "clown", "mandarin", "sturgeon"];

var popped = myFish.pop();

console.log(myFish); // ['angel', 'clown', 'mandarin' ]

console.log(popped); // 'sturgeon'
```

規範
--

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

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

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

參見
--

* `Array.prototype.push()`
* `Array.prototype.shift()`
* `Array.prototype.unshift()`
* `Array.prototype.concat()`
* `Array.prototype.splice()`


Array.isArray() - JavaScript

Array.isArray()
===============

**`Array.isArray()`** 函式會檢查傳入的值是否為一個 `Array`。

```js
Array.isArray([1, 2, 3]); // true
Array.isArray({ foo: 123 }); // false
Array.isArray("foobar"); // false
Array.isArray(undefined); // false
```

語法
--

```js
Array.isArray(obj)
```

### 參數

`obj`

要檢查的物件。

### 回傳值

若物件為 `Array` 回傳 `true`；否則回傳 `false`。

描述
--

檢查傳入的物件是否為陣列（`Array`），如果是便回傳 `true`，否則回傳 `false`。

更多細節請參考 「Determining with absolute accuracy whether or not a JavaScript object is an array」。

範例
--

```js
// 下方都回傳 true
Array.isArray([]);
Array.isArray([1]);
Array.isArray(new Array());
Array.isArray(new Array("a", "b", "c", "d"));
Array.isArray(new Array(3));
// 小細節：Array.prototype 本身是陣列：
Array.isArray(Array.prototype);

// 下方都回傳 false
Array.isArray();
Array.isArray({});
Array.isArray(null);
Array.isArray(undefined);
Array.isArray(17);
Array.isArray("Array");
Array.isArray(true);
Array.isArray(false);
Array.isArray({ \_\_proto\_\_: Array.prototype });
```

### `instanceof` vs `isArray`

當檢查 `Array` 實例時，`Array.isArray` 相較於 `instanceof` 更加推薦，因為它可以穿透 `iframes`。

```js
var iframe = document.createElement("iframe");
document.body.appendChild(iframe);
xArray = window.frames[window.frames.length - 1].Array;
var arr = new xArray(1, 2, 3); // [1,2,3]

// 正確地檢查陣列型態
Array.isArray(arr); // true
// 有害地，因為它不能在 iframes 之間正常運作
arr instanceof Array; // false
```

Polyfill
--------

如果 `Array.isArray()` 不存在於你的環境，在其他程式碼前執行下列程式碼可建置 `Array.isArray()`。

```js
if (!Array.isArray) {
  Array.isArray = function (arg) {
    return Object.prototype.toString.call(arg) === "[object Array]";
  };
}
```

規範
--

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

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

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

參見
--

* `Array`


Array.prototype.entries() - JavaScript

Array.prototype.entries()
=========================

**`entries()`** 方法會回傳一個包含陣列中每一個索引之鍵值對（key/value pairs）的新陣列迭代器（**`Array Iterator`**）物件。

嘗試一下
----

語法
--

```js
entries()
```

### 回傳值

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

範例
--

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

```js
var a = ["a", "b", "c"];
var iterator = a.entries();

for (let e of iterator) {
  console.log(e);
}
// [0, 'a']
// [1, 'b']
// [2, 'c']
```

規範
--

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

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

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

參見
--

* `Array.prototype.keys()`
* `Array.prototype.values()`
* `Array.prototype.forEach()` (en-US)
* `Array.prototype.every()` (en-US)
* `Array.prototype.some()` (en-US)
* for...of (en-US)
* 迭代協議


Array.prototype[@@iterator]() - JavaScript

Array.prototype[@@iterator]()
=============================

**`@@iterator`** 屬性的初始值與 `values()` 屬性的初始值為相同的的函式物件。

語法
--
```

arr[Symbol.iterator]()
```

### 回傳值

陣列的**迭代器**（iterator）函式，預設與 `values()` 函式相同。

範例
--

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

```js
var arr = ["w", "y", "k", "o", "p"];
var eArr = arr[Symbol.iterator]();
// your browser must support for..of loop
// and let-scoped variables in for loops
for (let letter of eArr) {
  console.log(letter);
}
```

### 另一種迭代方式

```js
var arr = ["w", "y", "k", "o", "p"];
var eArr = arr[Symbol.iterator]();
console.log(eArr.next().value); // w
console.log(eArr.next().value); // y
console.log(eArr.next().value); // k
console.log(eArr.next().value); // o
console.log(eArr.next().value); // p
```

規範
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-array.prototype-@@iterator |

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

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.values()`


Array.prototype.sort() - JavaScript

Array.prototype.sort()
======================

**`sort()`** 方法會\*原地（in place）\*對一個陣列的所有元素進行排序，並回傳此陣列。排序不一定是穩定的（stable）。預設的排序順序是根據字串的 Unicode 編碼位置（code points）而定。

由於依賴執行環境的實作，所以並不能保證排序的時間及空間複雜度。

嘗試一下
----

語法
--

```js
arr.sort([compareFunction])
```

### 參數

`compareFunction` 選擇性

指定一個函式來定義排序順序。假如省略此參數，陣列將根據各個元素轉為字串後的每一個字元之 Unicode 編碼位置值進行排序。

### 回傳值

排序後的陣列。請注意此為*原地*（in place）進行排序過的陣列，並且不是原陣列的拷貝。

描述
--

如果 `compareFunction` 沒有被應用，元素將被轉換為字串並以 Unicode 編碼位置進行比較來排序。舉例來說，"Banana" 會被排在 "cherry" 之前。在數值排序中，9 排在 80 前面，但因為數字被轉換成字串，在 Unicode 順序中 "80" 會在 "9" 的前面。

如果 `compareFunction` 被應用，陣列元素們將根據比較函式之回傳值來排序。如果 `a` 和 `b` 為被比較之兩元素，則：

* 若 `compareFunction(a, b)` 的回傳值小於 0，則會把 `a` 排在小於 `b` 之索引的位置，即 `a` 排在 `b` 前面。
* 若 `compareFunction(a, b)` 回傳 0，則 `a` 與 `b` 皆不會改變彼此的順序，但會與其他全部的元素比較來排序。備註：ECMAscript 標準並不保證這個行為，因此不是所有瀏覽器（如 Mozilla 版本在 2003 以前）都遵守此行為。
* 若 `compareFunction(a, b)` 的回傳值大於 0，則會把 `b` 排在小於 `a` 之索引的位置，即 `b` 排在 `a` 前面。
* `compareFunction(a, b)` 在給予一組特定元素 a 及 b 為此函數之兩引數時必須總是回傳相同的值。若回傳值不一致，排序順序則為 undefined。

所以，比較函式會是以下形式：

```js
function compare(a, b) {
  if (在某排序標準下 a 小於 b) {
    return -1;
  }
  if (在某排序標準下 a 大於 b) {
    return 1;
  }
  // a 必須等於 b
  return 0;
}
```

為了比較數字而不是字串，比較函式可以僅僅利用 `a` 減 `b`。以下函式將會升冪排序陣列：

```js
function compareNumbers(a, b) {
  return a - b;
}
```

`sort` 方法可以直接使用函式運算式 (en-US)（以及閉包（closures） (en-US)）：

```js
var numbers = [4, 2, 5, 1, 3];
numbers.sort(function (a, b) {
  return a - b;
});
console.log(numbers);

// [1, 2, 3, 4, 5]
```

物件可以按照其中一個屬性的值來排序。

```js
var items = [
  { name: "Edward", value: 21 },
  { name: "Sharpe", value: 37 },
  { name: "And", value: 45 },
  { name: "The", value: -12 },
  { name: "Magnetic", value: 13 },
  { name: "Zeros", value: 37 },
];

// sort by value
items.sort(function (a, b) {
  return a.value - b.value;
});

// sort by name
items.sort(function (a, b) {
  var nameA = a.name.toUpperCase(); // ignore upper and lowercase
  var nameB = b.name.toUpperCase(); // ignore upper and lowercase
  if (nameA < nameB) {
    return -1;
  }
  if (nameA > nameB) {
    return 1;
  }

  // names must be equal
  return 0;
});
```

範例
--

### 建立、顯示及排序一個陣列

下列範例建立了四個陣列並顯示其原本陣列內容、再進行排序。數字陣列先不使用比較函式（compare function）來排序，接著才依據比較函式進行排序。

```js
var stringArray = ["Blue", "Humpback", "Beluga"];
var numericStringArray = ["80", "9", "700"];
var numberArray = [40, 1, 5, 200];
var mixedNumericArray = ["80", "9", "700", 40, 1, 5, 200];

function compareNumbers(a, b) {
  return a - b;
}

console.log("stringArray:", stringArray.join());
console.log("Sorted:", stringArray.sort());

console.log("numberArray:", numberArray.join());
console.log("Sorted without a compare function:", numberArray.sort());
console.log("Sorted with compareNumbers:", numberArray.sort(compareNumbers));

console.log("numericStringArray:", numericStringArray.join());
console.log("Sorted without a compare function:", numericStringArray.sort());
console.log(
  "Sorted with compareNumbers:",
  numericStringArray.sort(compareNumbers),
);

console.log("mixedNumericArray:", mixedNumericArray.join());
console.log("Sorted without a compare function:", mixedNumericArray.sort());
console.log(
  "Sorted with compareNumbers:",
  mixedNumericArray.sort(compareNumbers),
);
```

這個範例將產生下列結果。就如結果所示，當使用比較函式時，數字會被正確的排序，不管是數字還是數字字串。
```

stringArray: Blue,Humpback,Beluga
Sorted: Beluga,Blue,Humpback

numberArray: 40,1,5,200
Sorted without a compare function: 1,200,40,5
Sorted with compareNumbers: 1,5,40,200

numericStringArray: 80,9,700
Sorted without a compare function: 700,80,9
Sorted with compareNumbers: 9,80,700

mixedNumericArray: 80,9,700,40,1,5,200
Sorted without a compare function: 1,200,40,5,700,80,9
Sorted with compareNumbers: 1,5,9,40,80,200,700
```

### 排序非 ASCII 字元

為了排列非 ASCII 字元，即重音節字元（e、é、è、a、ä 等等），非英語字串：利用 `String.localeCompare`。此函式將比較這些字元，所以結果將會顯示正確的順序。

```js
var items = ["réservé", "premier", "cliché", "communiqué", "café", "adieu"];
items.sort(function (a, b) {
  return a.localeCompare(b);
});

// items is ['adieu', 'café', 'cliché', 'communiqué', 'premier', 'réservé']
```

### 排序 map

`compareFunction` 可以被陣列中的各個元素多次呼叫。依據 `compareFunction` 的特性，這將會產生大量運算。越多元素要排序 `compareFunction` 就越多工作要做，因此選擇使用 map 來排列也就是一個更明智的選擇。作法為先迭代陣列一次來取得排序時所需的值至暫時的陣列，並對此臨時陣列進行排序。然後再迭代臨時陣列來將正確順序之值放入原始陣列中。

```js
// the array to be sorted
var list = ["Delta", "alpha", "CHARLIE", "bravo"];

// temporary array holds objects with position and sort-value
var mapped = list.map(function (el, i) {
  return { index: i, value: el.toLowerCase() };
});

// sorting the mapped array containing the reduced values
mapped.sort(function (a, b) {
  if (a.value > b.value) {
    return 1;
  }
  if (a.value < b.value) {
    return -1;
  }
  return 0;
});

// container for the resulting order
var result = mapped.map(function (el) {
  return list[el.index];
});
```

規範
--

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

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

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

參見
--

* `Array.prototype.reverse()`
* `String.prototype.localeCompare()`


Array.from() - JavaScript

Array.from()
============

**`Array.from()`** 方法會從類陣列（array-like）或是可迭代（iterable）物件建立一個新的 `Array` 實體。

嘗試一下
----

### 參數

`arrayLike`

將類陣列或可迭代物件轉換成陣列

`mapFn 選擇性`

Map 函式走訪陣列中的每一個元素。

`thisArg 選擇性`

`mapFn` 函式執行時的 `this` 對象。

### 回傳值

一個新的 `Array` 實體。

描述
--

`Array.from()` 讓你從這些物件建立陣列：

* 類陣列（array-like）物件（物件具有 `length` 屬性以及索引化（indexed）的元素）或
* 可迭代物件 (en-US)（物件具有可以讓你利用迭代的方式取得它自己本身的元素，像是 `Map` 和 `Set`）。

`Array.from()` 有個可選用的參數 `mapFn`，它允許你在建立出新的陣列實體之後，可以接著對陣列（或是其子類別物件）中的每一個元素執行 `map` 函式。更清楚地說，`Array.from(obj, mapFn, thisArg)` 跟 `Array.from(obj).map(mapFn, thisArg)` 的結果是一樣的，除非所建立的不是一個可用的中介陣列（intermediate array）。這對於某些陣列的子類別來說就很重要，例如型別陣列，因為中介陣列必須要把內容值做一番截頭去尾的操作來讓它們變成適合的物件型態。

`from()` 方法的 `length` 屬性值為 1。

在 ES2015，類別語法允許原生內建的物件以及使用者自定義的物件可以被子類別化（sub-classing）；因此，靜態方法像是 `Array.from`，是「繼承」了 `Array` 的子類別後，然後建立新的子類別的實體，而不是建立 `Array` 本身。

範例
--

### 從字串產生陣列

```js
Array.from("foo");
// ["f", "o", "o"]
```

### 從集合產生陣列

```js
var s = new Set(["foo", window]);
Array.from(s);
// ["foo", window]
```

### 從映射產生陣列

```js
var m = new Map([
  [1, 2],
  [2, 4],
  [4, 8],
]);
Array.from(m);
// [[1, 2], [2, 4], [4, 8]]
```

### 從類陣列物件（arguments）產生陣列

```js
function f() {
  return Array.from(arguments);
}

f(1, 2, 3);

// [1, 2, 3]
```

### 使用箭頭函式及 `Array.from`

```js
// 使用箭頭函式作為 map 函式來
// 操作元素
Array.from([1, 2, 3], (x) => x + x);
// [2, 4, 6]

// 產生數值序列
// 因為陣列中的每個位置都會被初始化為 `undefined`，
// 下方 `v` 會是 `undefined`
Array.from({ length: 5 }, (v, i) => i);
// [0, 1, 2, 3, 4]
```

Polyfill
--------

`Array.from` 在 ECMA-262 標準第六版（ES2015）被加入；在某些實作可能尚未被支援。你可以將下面的程式碼插入到妳的 script 的最前面，如果你使用的工作環境不具有原生支援 `Array.from` 的能力。這個演算法根據 ECMA-262 第六版中的規範實現，假定 `Object` 及 `TypeError` 它們本身已具有值且 `callback.call` 對應到原本 `Function.prototype.call` 的值。除此之外，因為 Polyfill 無法實現真正的迭代，這個實作不支援 ECMA-262 第六版中所定義的泛型迭代。

```js
// Production steps of ECMA-262, Edition 6, 22.1.2.1
if (!Array.from) {
  Array.from = (function () {
    var toStr = Object.prototype.toString;
    var isCallable = function (fn) {
      return typeof fn === "function" || toStr.call(fn) === "[object Function]";
    };
    var toInteger = function (value) {
      var number = Number(value);
      if (isNaN(number)) {
        return 0;
      }
      if (number === 0 || !isFinite(number)) {
        return number;
      }
      return (number > 0 ? 1 : -1) \* Math.floor(Math.abs(number));
    };
    var maxSafeInteger = Math.pow(2, 53) - 1;
    var toLength = function (value) {
      var len = toInteger(value);
      return Math.min(Math.max(len, 0), maxSafeInteger);
    };

    // The length property of the from method is 1.
    return function from(arrayLike /\*, mapFn, thisArg \*/) {
      // 1. Let C be the this value.
      var C = this;

      // 2. Let items be ToObject(arrayLike).
      var items = Object(arrayLike);

      // 3. ReturnIfAbrupt(items).
      if (arrayLike == null) {
        throw new TypeError(
          "Array.from requires an array-like object - not null or undefined",
        );
      }

      // 4. If mapfn is undefined, then let mapping be false.
      var mapFn = arguments.length > 1 ? arguments[1] : void undefined;
      var T;
      if (typeof mapFn !== "undefined") {
        // 5. else
        // 5. a If IsCallable(mapfn) is false, throw a TypeError exception.
        if (!isCallable(mapFn)) {
          throw new TypeError(
            "Array.from: when provided, the second argument must be a function",
          );
        }

        // 5. b. If thisArg was supplied, let T be thisArg; else let T be undefined.
        if (arguments.length > 2) {
          T = arguments[2];
        }
      }

      // 10. Let lenValue be Get(items, "length").
      // 11. Let len be ToLength(lenValue).
      var len = toLength(items.length);

      // 13. If IsConstructor(C) is true, then
      // 13. a. Let A be the result of calling the [[Construct]] internal method
      // of C with an argument list containing the single item len.
      // 14. a. Else, Let A be ArrayCreate(len).
      var A = isCallable(C) ? Object(new C(len)) : new Array(len);

      // 16. Let k be 0.
      var k = 0;
      // 17. Repeat, while k < len… (also steps a - h)
      var kValue;
      while (k < len) {
        kValue = items[k];
        if (mapFn) {
          A[k] =
            typeof T === "undefined"
              ? mapFn(kValue, k)
              : mapFn.call(T, kValue, k);
        } else {
          A[k] = kValue;
        }
        k += 1;
      }
      // 18. Let putStatus be Put(A, "length", len, true).
      A.length = len;
      // 20. Return A.
      return A;
    };
  })();
}
```

規格
--

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

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

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

參見
--

* `Array`
* `Array.prototype.map()`
* `TypedArray.from()` (en-US)