建構子函數的使用 - JavaScript

建構子函數的使用
========

還有一個選擇，你可以按照這兩個步驟來建立物件︰

1. 編寫建構子函數以完成物件類型的定義。
2. 使用 new 建立物件的實體。

若要定義物件類型，就指定物件類型的名稱、屬性、方法並建立函數。舉例來說，假設你想要給 car 建立物件類型。你希望這個物件的類型稱作 `car`，而且你還希望他有 make、model、year 這些屬性。要做到這些，你需要編寫出以下的函數︰

```js
function car(make, model, year) {
  this.make = make;
  this.model = model;
  this.year = year;
}
```

注意 `this` 是用來把傳送給函數的值代入給物件的屬性。

現在你可以建立稱作 `mycar` 的物件如下所示︰

```js
mycar = new car("Eagle", "Talon TSi", 1993);
```

這個語句建立 `mycar` 並且把指定的值代入給他自己的屬性。然後 `mycar.make` 的值是字串 "Eagle"，`mycar.year` 是整數 1993，依此類推。

你可以藉由呼叫 `new` 來建立許多個 `car` 的物件。例如，

```js
kenscar = new car("Nissan", "300ZX", 1992);
vpgscar = new car("Mazda", "Miata", 1990);
```

物件可以有另一個物件本身的屬性。例如，假設你定義稱為 `person` 的物件如下︰

```js
function person(name, age, sex) {
  this.name = name;
  this.age = age;
  this.sex = sex;
}
```

然後實體化兩個新的 person 物件如下︰

```js
rand = new person("Rand McKinnon", 33, "M");
ken = new person("Ken Jones", 39, "M");
```

然後你可以改寫 car 的定義，加入用來接受 `person` 物件的 owner 屬性，如下︰

```js
function car(make, model, year, owner) {
  this.make = make;
  this.model = model;
  this.year = year;
  this.owner = owner;
}
```

若要實體化新的物件，你可以如下使用︰

```js
car1 = new car("Eagle", "Talon TSi", 1993, rand);
car2 = new car("Nissan", "300ZX", 1992, ken);
```

注意，當建立新的物件的時候，傳入的並不是字面表達字串或整數值，上面的語句把 `rand` 和 `ken` 物件當作參數傳給 owners。然後如果你希望找出 car2 的 owner 的名稱，你可以如下存取屬性︰

```js
car2.owner.name
```

注意，你永遠可以給之前定義的物件加入屬性。例如，語句

```js
car1.color = "black";
```

把 `color` 屬性加入給 car1，並且把 "black" 的值代入給新加入的屬性。然而，這樣並不能影響到其他的任何物件。若要給所有同樣類型的物件加入新的屬性，你必須把新的屬性加入到 car 物件類型的定義。


一元正號運算子（+） - JavaScript

一元正號運算子（+）
==========

一元正號運算子（`+`）置於運算元之前並取其數值。如果可以，亦會將之轉為數字。

嘗試一下
----

語法
--

```js
+x
```

詳細說明
----

一元負號運算子（`-`）也可以轉換非數字，但正號運算子卻是將運算元轉換為數字的最快和首選方法。

它不會對該運算元進行任何其他操作。

它可以將字串轉為整數和浮點數（如果字串值符合）；亦可使用在非字串的運算元，例如 `true`、`false`、`null`。

正號運算子支持十進制和十六進制整數（`0x` 前綴）、負數（雖然不適用於十六進制）格式。

若用於 BigInt 類型的值，會觸發 TypeError。

如果無法解析值，它會回傳 `NaN`。

範例
--

### 使用於數字

```js
const x = 1;
const y = -1;

console.log(+x);
// 1
console.log(+y);
// -1
```

### 使用於非數字上

```js
+true  // 1
+false // 0
+null  // 0
+[]    // 0
+function (val) { return val; } // NaN
+1n    // throws TypeError: Cannot convert BigInt value to number
```

規範
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-unary-plus-operator |

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

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

參見
--

* 相加運算子
* 相減運算子
* 相除運算子
* 相乘運算子
* 餘數運算子 (en-US)
* 相乘運算子
* 指數運算子
* 遞減運算子
* 負號運算子


super - JavaScript

super
=====

super 關鍵字被使用於通過函式存取父層

`super.prop` 與 `super[expr]` 表達有效在 method definition 與 classes 與 object literals (en-US).

語法
--
```

super([arguments]); // calls the parent constructor.
super.functionOnParent([arguments]);
```

描述
--

當使用建構子，`super` 關鍵字必須出現在`this` 關鍵字之前使用，`super` 關鍵字也可以使用在呼叫函式與父對象

範例
--

### 在類別中使用 `super`

這個程式碼片段從 classes sample (live demo). 這裏的 `super()` 被呼叫去避免複製到建構子的 `Rectangle` 與 `Square` 的共通部分。

```js
class Rectangle {
  constructor(height, width) {
    this.name = "Rectangle";
    this.height = height;
    this.width = width;
  }
  sayName() {
    console.log("Hi, I am a ", this.name + ".");
  }
  get area() {
    return this.height \* this.width;
  }
  set area(value) {
    this.area = value;
  }
}

class Square extends Rectangle {
  constructor(length) {
    this.height; // ReferenceError, super needs to be called first!

    // Here, it calls the parent class's constructor with lengths
    // provided for the Rectangle's width and height
    super(length, length);

    // Note: In derived classes, super() must be called before you
    // can use 'this'. Leaving this out will cause a reference error.
    this.name = "Square";
  }
}
```

### Super-calling 靜態方法

你也可以使用在靜態方法.

```js
class Rectangle {
  constructor() {}
  static logNbSides() {
    return "I have 4 sides";
  }
}

class Square extends Rectangle {
  constructor() {}
  static logDescription() {
    return super.logNbSides() + " which are all equal";
  }
}
Square.logDescription(); // 'I have 4 sides which are all equal'
```

### 刪除 super 屬性將拋出錯誤

你不能使用 delete operator 以及 `super.prop` 以及 `super[expr]` 去刪除父層的類別屬性, 不然他會丟出一個錯誤 `ReferenceError` (en-US).

```js
class Base {
  constructor() {}
  foo() {}
}
class Derived extends Base {
  constructor() {}
  delete() {
    delete super.foo; // this is bad
  }
}

new Derived().delete(); // ReferenceError: invalid delete involving 'super'.
```

### `super.prop` 不能複寫在不能複寫的屬性

當定義不可寫屬性，例如 `Object.defineProperty`, `super` 不能複寫這個屬性的值.

```js
class X {
  constructor() {
    Object.defineProperty(this, "prop", {
      configurable: true,
      writable: false,
      value: 1,
    });
  }
}

class Y extends X {
  constructor() {
    super();
  }
  foo() {
    super.prop = 2; // Cannot overwrite the value.
  }
}

var y = new Y();
y.foo(); // TypeError: "prop" is read-only
console.log(y.prop); // 1
```

### 使用 `super.prop` 在對象符號

Super 可以使用在 object initializer / literal (en-US) 符號. 在這個範例, 有兩個對象定義在一個方法. 在第二個對象裡面, `super` 呼叫了第一個對象的方法. 這個動作幫助 `Object.setPrototypeOf()` (en-US) 讓我們可以設定原型 `obj2` to `obj1`, 所以 `super` 可以發現 `method1` 在 `obj1`裡被找到.

```js
var obj1 = {
  method1() {
    console.log("method 1");
  },
};

var obj2 = {
  method2() {
    super.method1();
  },
};

Object.setPrototypeOf(obj2, obj1);
obj2.method2(); // logs "method 1"
```

規格
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-super-keyword |

Browser compatibility
---------------------

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

參考
--

* Classes
* Anurag Majumdar - Super & Extends in JavaScript


this - JavaScript

this
====

JavaScript **函式內的 `this` 關鍵字**表現，和其他語言相比略有差異。在嚴格模式 (en-US)與非嚴格模式下也有所不同。

通常，`this` 值由被呼叫的函式來決定。它不能在執行期間被指派，每次函式呼叫調用的值也可能不同。ES5 引入了 `bind` 方法去設置函式的 `this` 值，而不管它怎麼被呼叫。ECMAScript 2015 也導入了定義 `this` 詞法範圍的箭頭函式（它的 `this` 值會維持在詞法作用域）。

嘗試一下
----

語法
--

```js
this
```

全域環境下
-----

`this` 值在所有函式以外的全域執行環境下，會被當作全域物件，無論是否處於嚴格模式。

```js
console.log(this.document === document); // true

// 在網路瀏覽器中，window 物件也是全域物件。
console.log(this === window); // true

this.a = 37;
console.log(window.a); // 37

this.b = "MDN";
console.log(window.b); // "MDN"
console.log(b); // "MDN"
```

函式環境下
-----

在函式內的 `this` 值取決於該函式如何被呼叫。

### 簡易呼叫

因為以下程式碼並不處於嚴謹模式下、而 `this` 值也沒被呼叫（call）設定，`this` 會變成全域物件，在瀏覽器之下則會變成 `window`。

```js
function f1() {
  return this;
}

//在瀏覽器中：
f1() === window; // true

//Node中:
f1() === global; // true
```

然而，在嚴格模式下，`this` 值會在進入執行環境時建立並維持該狀態。因此，下例的 `this` 預設值是 `undefined`：

```js
function f2() {
  "use strict"; // 嚴格模式
  return this;
}

f2() === undefined; //true
```

所以在嚴格模式下，如果 `this` 沒有定義到執行環境內，其預設值就會是 `undefined`。

**備註：** 在第二個例子裡面，`this` 應為 `undefined` (en-US)，因為 `f2` 是直接被呼叫，而不是在其為某個物件的方法或屬性的情況下（例如 `window.f2()`）被直接呼叫。某些瀏覽器首次支援嚴格模式 (en-US)時沒導入這個特徵，它們會因此錯誤的回傳 `window` 物件。

要從某個語境訪問另一個 `this` 語境的值，請使用 call 或 apply:

```js
// 物件可以被當作call或apply的第一個參數，而this會綁定該物件
var obj = { a: "Custom" };

// 此屬性a為全域物件
var a = "Global";

function whatsThis(arg) {
  return this.a; // this 值取決於此函數如何被呼叫
}

whatsThis(); // 'Global'
whatsThis.call(obj); // 'Custom'
whatsThis.apply(obj); // 'Custom'
```

當函式內部調用 `this` 關鍵字時，其值會和所有繼承自 `Function.prototype` 並使用 `call` 或 `apply` 方法呼叫的特定物件綁定。

```js
function add(c, d) {
  return this.a + this.b + c + d;
}

var o = { a: 1, b: 3 };

// 第一個參數（parameter）是調用了 this 的物件，
// 後續參數（parameters）會作為函式呼叫內的參數（arguments）而通過
add.call(o, 5, 7); // 16

// 第一個參數（parameter）是調用了 this 的物件，
// 第二個參數的陣列作為函式呼叫內的參數（arguments）之構件
add.apply(o, [10, 20]); // 34
```

使用 `call` 和 `apply` 時，如果被輸入作為 `this` 的值不是物件，JavaScript 內建的 `ToObject` 運算符會試著把被輸入的值轉變為物件。如果被輸入的值是一個原始型別，例如 `7`或是 `'foo'`，它們會自動被相關的建構方法轉變為物件。因此，原始數值`7`會轉變成類似用`new Number(7)`產生的物件，而字串`'foo'`會轉變成類似用`new String('foo')`產生的物件。

```js
function bar() {
  console.log(Object.prototype.toString.call(this));
}

bar.call(7); // [object Number]
bar.call("foo"); // [Object String]
```

### `bind` 方法

ECMAScript 5 導入了 `Function.prototype.bind`。呼叫 `f.bind(someObject)` 會建立和 `f` 的主體與作用域相同之新函式；但無論函數怎麼被調用，原始函數的 `this` 在新函數將永遠與 `bind` 的第一個參數綁定起來。

```js
function f() {
  return this.a;
}

var g = f.bind({ a: "azerty" });
console.log(g()); // azerty

var h = g.bind({ a: "yoo" }); // bind 只能使用一次！
console.log(h()); // azerty

var o = { a: 37, f: f, g: g, h: h };
console.log(o.f(), o.g(), o.h()); // 37, azerty, azerty
```

### 箭頭函式

在箭頭函式下，`this` 值保留了其在詞法作用域 的 `this` 值。在全域程式碼內，則設為全域物件：

```js
var globalObject = this;
var foo = () => this;
console.log(foo() === globalObject); // true
```

**備註：** 如果這參數被傳遞給箭頭函式的 call, bind, apply 調用，該參數會被忽略。你仍然可以將參數預先調用到 call，但第一個參數(thisArg)必須設置為空。

```js
// 作為物件的方法呼叫
var obj = { foo: foo };
console.log(obj.foo() === globalObject); // true

// 使用呼叫以嘗試設置 this
console.log(foo.call(obj) === globalObject); // true

// 使用 bind 以嘗試設置 this
foo = foo.bind(obj);
console.log(foo() === globalObject); // true
```

無論以上哪種，`foo` 的 `this` 在建立的時候，都會設為原本的樣子（以上面的例子來說，就是全域物件）。這同樣適用於在其他函式內創建的箭頭函式：它們的 `this` 是設置為外部執行上下文。

```js
// 建立一個物件，其方法 bar 含有回傳自己的 this 函式。回傳函式作為箭頭函數而建立，
// 因此該函式的 this 將永遠與外圍函式（enclosing function）的 this 綁定。
// bar 的值可在呼叫內設立，which in turn sets the value of the returned function.
var obj = {
  bar: function () {
    var x = () => this;
    return x;
  },
};

// 將 bar 作為物件的方法呼叫，把它的 this 設為物件
// 指派 fn 作為回傳函數的參照（reference）
var fn = obj.bar();

// 在不設置 this 情況下呼叫的 fn，通常默認為全域物件，在嚴格模式下則是 undefined
console.log(fn() === obj); // true
```

以上面的程式碼為例，稱作匿名函數（anonymous function）A 的函數被指定為 `obj.bar`，它回傳的函數（稱作匿名函數 B）作為箭頭函數而建立。因而，函數 B 的 `this` 在呼叫時，將永遠設為 `obj.bar` （函數 A）的 `this`。呼叫被回傳的函數（函數 B）時，它的 `this` 將一直是原本的樣子。

再以上面的程式碼為例，函數 B 的 `this` 被設為函數 A 的 `this`，而它屬於物件，所以它依然會設為 `obj`，就算在 `this` 設為 `undefined` 或全域物件的呼叫方式下（或在全域執行環境下，上例的任何方法）

### 作為物件方法

如果一個函式是以物件的方法呼叫，它的 `this` 會設為該呼叫函式的物件。

以下面的程式碼為例，呼叫 `o.f()` 的時候，函式內的 `this` 會和 `o` 物件綁定。

```js
var o = {
  prop: 37,
  f: function () {
    return this.prop;
  },
};

console.log(o.f()); // logs 37
```

請注意這個行為，不會受函式如何或何處定義所影響。以上面為例，在我們定義 `o` 時，也定義了行內函式 `f` 作為構件（member）。不過，我們也能先定義函式，接著讓它附屬到 `o.f`。這麼做會得出相同的效果：

```js
var o = { prop: 37 };

function independent() {
  return this.prop;
}

o.f = independent;

console.log(o.f()); // 37
```

這表明了 `this` 只和 `f` 作為 `o` 的構件呼叫有所關聯。

同樣的，`this` 綁定只會受最直接的構件引用（most immediate member reference）所影響。在下面的例子，我們將物件 `o.b` 的方法 `g` 作為函式呼叫。在執行的期間，函式內的 `this` 會參照 `o.b`。物件是否為 `o` 的構件無關緊要，最直接的引用才是最緊要的。

```js
o.b = { g: independent, prop: 42 };
console.log(o.b.g()); // logs 42
```

#### 物件原型鏈上的 `this`

相同概念也能套用定義物件原型鏈的方法。如果方法放在物件的原型鏈上，`this` 會指向方法所呼叫的物件，如同該方法在物件上的樣子。

```js
var o = {
  f: function () {
    return this.a + this.b;
  },
};
var p = Object.create(o);
p.a = 1;
p.b = 4;

console.log(p.f()); // 5
```

在這個示例中，分配給變數 `p` 的物件沒有自己的 `f` 屬性，`p` 繼承了 `o` 的原型。但是查找 `f` 最終在 `o`上找到它的成員名為 f 並不重要。查找開始作為 `p.f` 的引用，所以 `this` 在函式內部物件的值被當作是`p`的引用。也就是說，`f` 作為 `p`的調用方法以來，它的 `this` 指的就是 `p`。這是一個非常有趣的 JavaScript 原型繼承特性。

#### 帶著 getter 或 setter 的 `this`

當函式從 getter 或 setter 被調用的時候，同樣的概念也成立。用作 getter 或 setter 的函式將自己的 `this` 綁定到從中設置或獲取的物件上。

```js
function sum() {
  return this.a + this.b + this.c;
}

var o = {
  a: 1,
  b: 2,
  c: 3,
  get average() {
    return (this.a + this.b + this.c) / 3;
  },
};

Object.defineProperty(o, "sum", {
  get: sum,
  enumerable: true,
  configurable: true,
});

console.log(o.average, o.sum); // logs 2, 6
```

### 作為建構子

若函式以建構子的身份呼叫（使用 `new` 關鍵字） `this` 會和被建構的新物件綁定。

**備註：** 建構子預設透過 `this` 回傳該物件的參照，但它其實能回傳其他物件。如果回傳值不是物件的話，就會回傳 `this` 這個物件。

```js
/\*
 \* 建構子會如此做動：
 \*
 \* function MyConstructor(){
 \* // 實際的函式主體碼在這裡
 \* // 在|this| 上創建屬性
 \* // 希望通過分配給他們，如：
 \* this.fum = "nom";
 \* // et cetera...
 \*
 \* // 如果函式有返回狀態它將返回一個物件
 \* // 那個物件將是新表達式的結果。
 \* // 換句話來說，表達式的結果是現在綁定 |this| 的物件
 \* // (例如，最常見的常見情況).
 \* }
 \*/

function C() {
  this.a = 37;
}

var o = new C();
console.log(o.a); // logs 37

function C2() {
  this.a = 37;
  return { a: 38 };
}

o = new C2();
console.log(o.a); // logs 38
```

在上例的 `C2`，由於物件在建構的時候被呼叫，新的物件 `this` was bound to simply gets discarded。這也實質上令 `this.a = 37;` 宣告死亡：不是真的死亡（因為已經執行了），但它在毫無 outside effects 的情況下遭到消滅。

### 作為 DOM 事件處理器

當一個函式用作事件處理器的話，`this` 值會設在觸發事件的元素（某些瀏覽器如果不用 `addEventListener` 方法的話，在動態添加監聽器時，就不會遵循這個常規）

```js
// 當監聽器被調用，相關元素變為藍色
function bluify(e) {
  // 永遠是真
  console.log(this === e.currentTarget);
  // 當當前目標和目標為相同物件為真
  console.log(this === e.target);
  this.style.backgroundColor = "#A5D9F3";
}

// 取得文件內所有的元素
var elements = document.getElementsByTagName("\*");

// Add bluify as a click listener so when the
// element is clicked on, it turns blue
for (var i = 0; i < elements.length; i++) {
  elements[i].addEventListener("click", bluify, false);
}
```

### 作為行內事件處理器

當程式碼從行內的 on 事件處理器呼叫的話，`this` 就會設在監聽器所置的 DOM 元素：

```html
<button onclick="alert(this.tagName.toLowerCase());">Show this</button>
```

上方的 alert 會秀出 `button`。但請注意只有外層程式碼的 `this` 要這樣設定：

```html
<button onclick="alert((function(){return this})());">Show inner this</button>
```

在這裡，內部函式的並沒有設立 `this`，所以它會回傳全域／window 物件（例如在非嚴格模式下，呼叫函數沒設定 `this` 的預設物件）

規範
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-this-keyword |

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

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

參見
--

* 嚴格模式 (en-US)
* All this，一篇關於 `this` 上下文不同的相關文章
* 親和地解釋 JavaScript 的「this」關鍵字


遞增運算子（++） - JavaScript

遞增運算子（++）
=========

遞增運算子（`++`）遞增（加一）它的運算元並將結果回傳。

嘗試一下
----

語法
--

```js
x++
++x
```

詳細說明
----

若將遞增運算子作為後綴（例如 `x++`），則會先回傳原本的值，再進行遞增。

若作為前綴（例如 `++x`），則會先進行遞增，再將遞增後的結果回傳。

範例
--

### 遞增運算子置於後綴

```js
let x = 3;
y = x++;

// y = 3
// x = 4
```

### 遞增運算子置於前綴

```js
let a = 2;
b = ++a;

// a = 3
// b = 3
```

規範
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-postfix-increment-operator |

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

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

參見
--

* 相加運算子
* 相減運算子
* 相除運算子
* 餘數運算子 (en-US)
* 相乘運算子
* 指數運算子
* 遞減運算子
* 負號運算子
* 正號運算子


屬性的刪除 - JavaScript

屬性的刪除
=====

你可以使用 `delete` 運算子移除屬性。下面的代碼示範如何移除屬性︰

```js
// 建立新的物件 myobj，以及兩個屬性 a 和 b。
myobj = new Object();
myobj.a = 5;
myobj.b = 12;

// 移除一個屬性，只剩 b 屬性留在 myobj 裡。
delete myobj.a;
```

你也可以使用 `delete` 來刪除全域變數，只要這個變數不是使用 `var` 關鍵字宣告的話︰

```js
g = 17;
delete g;
```

參閱 delete 取得更多資訊。

* « 前頁
* 次頁 »


遞減運算子（--） - JavaScript

遞減運算子（--）
=========

遞減運算子（`--`）遞減（減一）它的運算元並將結果回傳。

嘗試一下
----

語法
--

```js
x--
--x
```

詳細說明
----

若將遞減運算子作為後綴（例如 `x--`），則會先回傳原本的值，在進行遞減。

若作為前綴（例如 `--x`），則會先進行遞減，在將遞減後的結果回傳。

範例
--

### 遞減運算子置於後綴

```js
let x = 3;
y = x--;

// y = 3
// x = 2
```

### 遞減運算子置於前綴

```js
let a = 2;
b = --a;

// a = 1
// b = 1
```

規範
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-postfix-decrement-operator |

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

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

參見
--

* 相加運算子
* 相減運算子
* 相除運算子
* 餘數運算子 (en-US)
* 相乘運算子
* 指數運算子
* 遞增運算子
* 負號運算子
* 正號運算子


相減運算子（-） - JavaScript

相減運算子（-）
========

相減運算子（`-`）是用來將兩個值進行相減，並得出它們的差值。

嘗試一下
----

語法
--

```js
x - y
```

範例
--

### 數字相減

```js
5 - 3; // 2
3 - 5; // -2
```

### 非數字之間的相減

```js
"foo" - 3; // NaN
```

規範
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-subtraction-operator-minus |

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

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

參見
--

* 相加運算子
* 相除運算子
* 相乘運算子
* 餘數運算子 (en-US)
* 指數運算子
* 遞增運算子
* 遞減運算子
* 負號運算子
* 正號運算子


相乘運算子（*） - JavaScript

相乘運算子（\*）
=========

相乘運算子（`*`）是用來取得兩個運算元的乘積。

嘗試一下
----

語法
--

```js
x \* y
```

範例
--

### 乘以數字

```js
2 \* 2; // 4
-2 \* 2; // -4
```

### 乘以無限（Infinity）

```js
Infinity \* 0; // NaN
Infinity \* Infinity; // Infinity
```

### 乘以非數字

```js
"foo" \* 2; // NaN
```

規範
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-multiplicative-operators |

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

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

參見
--

* 相加運算子
* 相減運算子
* 相除運算子
* 餘數運算子 (en-US)
* 指數運算子
* 遞增運算子
* 遞減運算子
* 負號運算子
* 正號運算子


解構賦值 - JavaScript

解構賦值
====

**解構賦值** (Destructuring assignment) 語法是一種 JavaScript 運算式，可以把陣列或物件中的資料解開擷取成為獨立變數。

嘗試一下
----

語法
--

```js
let a, b, rest;
[a, b] = [10, 20];
console.log(a); // 10
console.log(b); // 20

[a, b, ...rest] = [10, 20, 30, 40, 50];
console.log(a); // 10
console.log(b); // 20
console.log(rest); // [30, 40, 50]

({ a, b } = { a: 10, b: 20 });
console.log(a); // 10
console.log(b); // 20

// Stage 4(finished) proposal
({ a, b, ...rest } = { a: 10, b: 20, c: 30, d: 40 });
console.log(a); // 10
console.log(b); // 20
console.log(rest); // {c: 30, d: 40}
```

描述
--

物件與陣列運算式提供了簡單的方式，建立特定的資料組。

```js
const x = [1, 2, 3, 4, 5];
```

解構賦值使用類似語法；不過在指定敘述式的左側，要宣告從來源變數接收解開值之變數。

```js
const x = [1, 2, 3, 4, 5];
const [y, z] = x;
console.log(y); // 1
console.log(z); // 2
```

Perl 和 Python 也有類似的語法和功能。

陣列解構
----

### 基本變數指定敘述

```js
const foo = ["one", "two", "three"];

const [red, yellow, green] = foo;
console.log(red); // "one"
console.log(yellow); // "two"
console.log(green); // "three"
```

### 宣告指派分開敍述

變數可以在宣告式後，再透過解構賦值。

```js
let a, b;

[a, b] = [1, 2];
console.log(a); // 1
console.log(b); // 2
```

### 預設值

當解構來源陣列對應的元素是 undefined 時，變數可以被設定預設值。

```js
let a, b;

[a = 5, b = 7] = [1];
console.log(a); // 1
console.log(b); // 7
```

### 變數交換

兩個變數可以透過一個解構指派式交換。

沒有解構指派式時，這需要一個暫存變數來達成（或者像某些低階語言的 XOR-swap trick）。

```js
let a = 1;
let b = 3;

[a, b] = [b, a];
console.log(a); // 3
console.log(b); // 1

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

### 解析自函式回傳的陣列

一直以來函式都可以回傳陣列，而解構指派式可以讓回傳的值更加簡潔。

在這個例子， `f()` 回傳 `[1, 2]` ，接著透過一個解構指派式解析。

```js
function f() {
  return [1, 2];
}

let a, b;
[a, b] = f();
console.log(a); // 1
console.log(b); // 2
```

### 忽略某些回傳值

你可以忽略某些回傳值：

```js
function f() {
  return [1, 2, 3];
}

const [a, , b] = f();
console.log(a); // 1
console.log(b); // 3
```

當然你也可以忽略全部回傳值：

```js
[, ,] = f();
```

### 把矩陣剩餘部分解構到一個變數

解構一個陣列時，你可以透過其餘元素（rest pattern）將來源剩下之元素指派到一個變數：

```js
const [a, ...b] = [1, 2, 3];
console.log(a); // 1
console.log(b); // [2, 3]
```

要注意的是，當左邊函式裡使用其餘解構，同時使用結尾逗號，這樣會拋出例外 `SyntaxError` (en-US) :

```js
const [a, ...b,] = [1, 2, 3];

// SyntaxError 語法錯誤: 其餘元素不可以跟隨結尾逗號
// 需要把其餘運算子放在最後的元素
```

### 從正則運算式的比對結果取值

當正則運算式的方法 `exec()` (en-US) 比對到一個值，其回傳陣列中的第一個值是相符的完整字串，後績的則是比對到正則運算式每組括號內的部分。當你沒需要利用第一個完整比對結果時，解構指派式讓你更簡單的取出後績元素。

```js
function parseProtocol(url) {
  const parsedURL = /^(\w+)\:\/\/([^\/]+)\/(.\*)$/.exec(url);
  if (!parsedURL) {
    return false;
  }
  console.log(parsedURL); // ["https://developer.mozilla.org/en-US/Web/JavaScript", "https", "developer.mozilla.org", "en-US/Web/JavaScript"]

  const [, protocol, fullhost, fullpath] = parsedURL;
  return protocol;
}

console.log(
  parseProtocol("https://developer.mozilla.org/en-US/Web/JavaScript"),
); // "https"
```

物件解構
----

### 基本指派式

```js
const o = { p: 42, q: true };
const { p, q } = o;

console.log(p); // 42
console.log(q); // true
```

### 無宣告指派

變數可以在宣告式後，再透過解構進行指派。

```js
let a, b;

({ a, b } = { a: 1, b: 2 });
```

**備註：** 當針對物件進行解構，而該句式沒有進行宣告時，指派式外必須加上括號 `( ... )` 。

`{a, b} = {a: 1, b: 2}` 不是有效的獨立語法，因為左邊的 `{a, b}` 被視為程式碼區塊而非物件。

然而，`({a, b} = {a: 1, b: 2})` 是有效的，如同 `const {a, b} = {a: 1, b: 2}`

`( ... )` 表達式前句需要以分號結束，否則可能把上一句視為函式隨即執行。

### 指派到新的變數名稱

物件中的屬性可以解構並擷取到名稱跟該屬性不一樣的變數。

```js
const o = { p: 42, q: true };
const { p: foo, q: bar } = o;

console.log(foo); // 42
console.log(bar); // true
```

舉例來說， `const {p: foo} = o` 把物件 `o` 裡名為 `p` 的屬性解出並指派到一個名為 `foo` 的本地變數。

### 預設值

當解構物件中對應的值是 `undefined` 時，變數可以設定預設值。

```js
const { a = 10, b = 5 } = { a: 3 };

console.log(a); // 3
console.log(b); // 5
```

### 指定新的變數名稱及預設值

屬性 1) 可以從物件中被解開，且被指定一個不同名稱的變數及 2) 同時指定一個預設值，在解開的值為 `undefined` 時使用。

```js
const { a: aa = 10, b: bb = 5 } = { a: 3 };

console.log(aa); // 3
console.log(bb); // 5
```

### 從作為函式參數的物件中提出某屬性的值

```js
const user = {
  id: 42,
  displayName: "jdoe",
  fullName: {
    firstName: "John",
    lastName: "Doe",
  },
};

function userId({ id }) {
  return id;
}

function whois({ displayName, fullName: { firstName: name } }) {
  return `${displayName} is ${name}`;
}

console.log(userId(user)); // 42
console.log(whois(user)); // "jdoe is John"
```

這樣從 user 物件中提出了 `id`, `displayName` 和 `firstName` 並且印出。

### 設定函式參數的預設值

```js
function drawChart({
  size = "big",
  coords = { x: 0, y: 0 },
  radius = 25,
} = {}) {
  console.log(size, coords, radius);
  // do some chart drawing
}

drawChart({
  coords: { x: 18, y: 30 },
  radius: 30,
});
```

**備註：** 在上述函式 **`drawChart`** 中，左方之解構式被指派到一個空物件: `{size = 'big', coords = {x: 0, y: 0}, radius = 25} = {}` 。你也可以略過填寫右方的指派式。不過，當你沒有使用右方指派式時，函式在呼叫時會找出最少一個參數。透過上述形式，你可以直接不使用參數的呼叫 **`drawChart()`** 。當你希望在呼叫這個函式時不傳送參數，這個設計會帶來方便。而另一個設計則能讓你確保函式必須傳上一個物件作為參數。

### 巢狀物件或陣列的解構

```js
const metadata = {
  title: "Scratchpad",
  translations: [
    {
      locale: "de",
      localization\_tags: [],
      last\_edit: "2014-04-14T08:43:37",
      url: "/de/docs/Tools/Scratchpad",
      title: "JavaScript-Umgebung",
    },
  ],
  url: "/zh-TW/docs/Tools/Scratchpad",
};

let {
  title: englishTitle, // rename
  translations: [
    {
      title: localeTitle, // rename
    },
  ],
} = metadata;

console.log(englishTitle); // "Scratchpad"
console.log(localeTitle); // "JavaScript-Umgebung"
```

### 循環取出的解構

```js
const people = [
  {
    name: "Mike Smith",
    family: {
      mother: "Jane Smith",
      father: "Harry Smith",
      sister: "Samantha Smith",
    },
    age: 35,
  },
  {
    name: "Tom Jones",
    family: {
      mother: "Norah Jones",
      father: "Richard Jones",
      brother: "Howard Jones",
    },
    age: 25,
  },
];

for (const {
  name: n,
  family: { father: f },
} of people) {
  console.log("Name: " + n + ", Father: " + f);
}

// "Name: Mike Smith, Father: Harry Smith"
// "Name: Tom Jones, Father: Richard Jones"
```

### 以物件演算屬性名稱解構

物件演算屬性名稱（像是在 object literals (en-US)）可以在解構指派式使用。

```js
let key = "z";
let { [key]: foo } = { z: "bar" };

console.log(foo); // "bar"
```

### 在物件解構時使用其餘變數

ECMAScript 中的其餘/展開屬性在 proposal (stage 4) 新增了在解構式內使用其餘 (rest) 語法的定義。其餘屬性可以收集解構式中沒有指定的屬性值。

```js
let { a, b, ...rest } = { a: 10, b: 20, c: 30, d: 40 };
a; // 10
b; // 20
rest; // { c: 30, d: 40 }
```

### 不符合 JavaScript 識別字的屬性名稱

解構賦值可以透過另一個符合 JavaScript 識別字的變數名稱來解出不符合識別字的屬性。

```js
const foo = { "fizz-buzz": true };
const { "fizz-buzz": fizzBuzz } = foo;

console.log(fizzBuzz); // "true"
```

### 混合使用矩陣及物件解構

矩陣及物件解構可以混合進行。與例來說，你只需要使用下列 `props` 矩陣中第三個元素之物件中的 `name` 屬性，你可以如下面的例子進行解構：

```js
const props = [
  { id: 1, name: "Fizz" },
  { id: 2, name: "Buzz" },
  { id: 3, name: "FizzBuzz" },
];

const [, , { name }] = props;

console.log(name); // "FizzBuzz"
```

### 物件解構時的原型鏈追溯

在進行物件解構時，如果一個屬性不在其當下存取，將會透過原型鏈 (prototype chain) 來進行追溯。
```

let obj = {self: '123'};
obj.__proto__.prot = '456';
const {self, prot} = obj;
// self "123"
// prot "456"（Access to the prototype chain）
```

規範
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-destructuring-assignment |
| ECMAScript Language Specification # sec-destructuring-binding-patterns |

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

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

參見
--

* Assignment operators (en-US)
* "ES6 in Depth: Destructuring" on hacks.mozilla.org


相加運算子（+） - JavaScript

相加運算子（+）
========

相加運算子（`+`）用來處理數字的相加或是進行字串的串聯。

嘗試一下
----

語法
--

```js
x + y
```

範例
--

### 數字相加

```js
// Number + Number -> addition
1 + 2; // 3
// Boolean + Number -> addition
true + 1; // 2
// Boolean + Boolean -> addition
false + false; // 0
```

### 字串串聯

```js
// String + String -> concatenation
"foo" + "bar"; // "foobar"
// Number + String -> concatenation
5 + "foo"; // "5foo"
// String + Boolean -> concatenation
"foo" + false; // "foofalse"
```

規範
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-addition-operator-plus |

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

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

參見
--

* 相減運算子
* 相除運算子
* 相乘運算子
* 餘數運算子 (en-US)
* 指數運算子
* 遞增運算子
* 遞減運算子
* 負號運算子
* 正號運算子


await - JavaScript

await
=====

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

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

* Learn more
* See full compatibility
* Report feedback
await 運算子可被用來等待 `Promise`，只能在 `async function`內使用。語法
--
```

[rv] = await expression;
```

`expression`

等待解析的 `Promise` 物件或任何值。

`rv = 回傳值`

回傳 Promise 物件的 resolved 值，或當該值不是 Promise 物件時，回傳該值本身。

描述
--

此 await 表示法會暫停 async 函式執行，等待 Promise 物件的解析，並在 promise 物件的值被 resolve 時回復 async 函式的執行。await 接著回傳這個被 resolve 的值。如果回傳值不是一個 Promise 物件，則會被轉換為 resolved 狀態的 Promise 物件。

如果 Promise 物件被 rejected，則 await 會丟出 rejected 的值。

範例
--

若將 Promise 物件傳給 await 運算式，它會等待 Promise 解析並回傳 resolve 後的值。

```js
function resolveAfter2Seconds(x) {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve(x);
    }, 2000);
  });
}

async function f1() {
  var x = await resolveAfter2Seconds(10);
  console.log(x); // 10
}
f1();
```

若傳給 await 的值並非一個 Promise 物件，它會將該值轉換為 resolved Promise，並等待之。

```js
async function f2() {
  var y = await 20;
  console.log(y); // 20
}
f2();
```

若 Promise 被 reject，則丟出 reject 後的異常值。

```js
async function f3() {
  try {
    var z = await Promise.reject(30);
  } catch (e) {
    console.log(e); // 30
  }
}
f3();
```

規範
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-async-function-definitions |

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

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

See also
--------

* `async function`
* `async function expression` (en-US)
* `AsyncFunction` (en-US) object


運算子優先序 - JavaScript

運算子優先序
======

運算子優先序（Operator precedence）決定了運算子彼此之間被語法解析的方式，優先序較高的運算子會成為優先序較低運算子的運算元（operands）。

嘗試一下
----

相依性(Associativity)
------------------

當優先序相同時，使用相依性決定運算方向。範例如下：
```

a OP b OP c
```

左相依性 (Left-associativity) ，表示處理順序為從左至右 `(a OP b) OP c`，反之，右相依性(right-associativity) 表示處理順序為從右至左 `a OP (b OP c)`。賦值運算符 (Assignment operators) 為右相依性，範例如下：

```js
a = b = 5;
```

`a` 和 `b` 的預期結果為 5，因為賦值運算符 (Assignment operator) 為右相依性，因此從右至左返回值。一開始 `b` 被設定為 5，接著 `a` 也被設定為 5。

表格(Table)
---------

下方表格列出運算子的相依性，從高 (19) 到低 (1)。

| 優先性Precedence | 運算子名稱Operator type | 相依性Associativity | 運算子Individual operators |
| --- | --- | --- | --- |
| 19 | Grouping (en-US) | 無 | `( … )` |
| 18 | Member Access (en-US) | 從左至右 | `… . …` |
| Computed Member Access (en-US) | 從左至右 | `… [ … ]` |
| `new` (with argument list) | 無 | `new … ( … )` |
| 呼叫函式 | 從左至右 | `… ( … )` |
| 可選串連（Optional chaining） | 從左至右 | `?.` |
| 17 | `new` (without argument list) | 從右至左 | `new …` |
| 16 | 字尾遞增 | 無 | `… ++` |
| 字尾遞減 | `… --` |
| 15 | Logical NOT (en-US) | 從右至左 | `! …` |
| Bitwise NOT (en-US) | `~ …` |
| Unary Plus | `+ …` |
| Unary Negation | `- …` |
| 字首遞增 | `++ …` |
| 字首遞減 | `-- …` |
| `typeof` | `typeof …` |
| `void` (en-US) | `void …` |
| `delete` | `delete …` |
| `await` | `await …` |
| 14 | Exponentiation | 從右至左 | `… ** …` |
| 13 | Multiplication | 從左至右 | `… * …` |
| Division | `… / …` |
| Remainder (en-US) | `… % …` |
| 12 | Addition | 從左至右 | `… + …` |
| Subtraction | `… - …` |
| 11 | Bitwise Left Shift (en-US) | 從左至右 | `… << …` |
| Bitwise Right Shift (en-US) | `… >> …` |
| Bitwise Unsigned Right Shift (en-US) | `… >>> …` |
| 10 | Less Than (en-US) | 從左至右 | `… < …` |
| Less Than Or Equal (en-US) | `… <= …` |
| Greater Than (en-US) | `… > …` |
| Greater Than Or Equal (en-US) | `… >= …` |
| `in` (en-US) | `… in …` |
| `instanceof` (en-US) | `… instanceof …` |
| 9 | Equality (en-US) | 從左至右 | `… == …` |
| Inequality (en-US) | `… != …` |
| Strict Equality (en-US) | `… === …` |
| Strict Inequality (en-US) | `… !== …` |
| 8 | Bitwise AND (en-US) | 從左至右 | `… & …` |
| 7 | Bitwise XOR (en-US) | 從左至右 | `… ^ …` |
| 6 | Bitwise OR (en-US) | 從左至右 | `… | …` |
| 5 | Logical AND (en-US) | 從左至右 | `… && …` |
| 4 | Logical OR (en-US) | 從左至右 | `… || …` |
| Nullish Coalescing (en-US) | 從左至右 | `… ?? …` |
| 3 | 條件運算 | 從右至左 | `… ? … : …` |
| 2 | 賦值 | 從右至左 | `… = …` |
| `… += …` |
| `… -= …` |
| `… **= …` |
| `… *= …` |
| `… /= …` |
| `… %= …` |
| `… <<= …` |
| `… >>= …` |
| `… >>>= …` |
| `… &= …` |
| `… ^= …` |
| `… |= …` |
| `… &&= …` |
| `… ||= …` |
| `… ??= …` |
| 1 | Comma / Sequence (en-US) | 從左至右 | `… , …` |


一元負號運算子（-） - JavaScript

一元負號運算子（-）
==========

一元負號運算子（`-`）置於運算元之前，並將運算元轉為其負值。

嘗試一下
----

語法
--

```js
-x
```

範例
--

### 轉換數字

```js
const x = 3;
const y = -x;

// y = -3
// x = 3
```

### 轉換非數字

一元負號運算子可以將非數字轉為數字。

```js
const x = "4";
const y = -x;

// y = -4
```

規範
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-unary-minus-operator |

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

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

參見
--

* 相加運算子
* 相減運算子
* 相除運算子
* 相乘運算子
* 餘數運算子 (en-US)
* 相乘運算子
* 指數運算子
* 遞減運算子
* 正號運算子


typeof - JavaScript

typeof
======

摘要
--

typeof 運算子會傳回一個字串值, 指出未經運算 (unevaluated) 的運算元所代表的型別。

| 運算子 |
| --- |
| 實作於: | JavaScript 1.1 |
| ECMA 版本: | ECMA-262 (以及 ECMA-357 for E4X objects) |

語法
--

`typeof` 之後面跟著它的唯一運算元:
```

typeof operand
```

參數
--

`operand` 表示式代表傳入的物件或原始型別。

說明
--

下表摘要列出了 `typeof 可能的傳回值`:

| 型別 | 傳回 |
| --- | --- |
| Undefined | `"undefined"` |
| Null | `"object"` |
| Boolean | `"boolean"` |
| Number | `"number"` |
| String | `"string"` |
| 主機端物件 (由 JS 執行環境提供) | *視實作方式而異* |
| Function 物件 (實作 ECMA-262 所定義的 [[Call]]) | `"function"` |
| E4X XML 物件 | "xml" |
| E4X XMLList 物件 | "xml" |
| 所有其它物件 | `"object"` |

範例
--

### 一般情況

```js
// Numbers
typeof 37 === "number";
typeof 3.14 === "number";
typeof Math.LN2 === "number";
typeof Infinity === "number";
typeof NaN === "number"; // 雖然是 "Not-A-Number"
typeof Number(1) === "number"; // 但是不要使用這種方式!

// Strings
typeof "" === "string";
typeof "bla" === "string";
typeof typeof 1 === "string"; // typeof 一律會傳回一個字串
typeof String("abc") === "string"; // 但是不要使用這種方式!

// Booleans
typeof true === "boolean";
typeof false === "boolean";
typeof Boolean(true) === "boolean"; // 但是不要使用這種方式!

// Undefined
typeof undefined === "undefined";
typeof blabla === "undefined"; // 一個 undefined 變數

// Objects
typeof { a: 1 } === "object";
typeof [1, 2, 4] === "object"; // 請使用 Array.isArray 或者 Object.prototype.toString.call 以區分正規運算式和陣列
typeof new Date() === "object";

typeof new Boolean(true) === "object"; // 這樣會令人混淆。不要這樣用!
typeof new Number(1) === "object"; // 這樣會令人混淆。不要這樣用!
typeof new String("abc") === "object"; // 這樣會令人混淆。不要這樣用!

// Functions
typeof function () {} === "function";
typeof Math.sin === "function";
```

### `null`

```js
typeof null === "object"; // 自從有 JavaScript 開始就是這樣了
```

自從 JavaScript 一開始出現, JavaScript 的值就總以型別標簽跟著一個值的方式表示。物件的型別標簽是 0. 而 `null` 這個值是使用 NULL 指標 (在大部份平台上是 0x00) 來表示. 因此, null 看起來像是一個以 0 為型別標簽的值, 並使得 `typeof` 傳回不甚正確的結果. (參考來源)

這個問題已計畫在下一版 ECMAScript 予以修正 (會以 opt-in 方式提供). 屆時它將會做出如 `typeof null === 'null'` 的正確回傳結果。

**備註：** 此修正計畫已被拒絕

### 正規表示式 (Regular expressions)

可呼叫的正規表示式在某些瀏覽器上面必須借助非正式插件 (need reference to say which).

```js
typeof /s/ === "function"; // Chrome 1-12 ... // 不符合 ECMAScript 5.1 (譯註: 在新版 Chrome 已修正為 'object')
typeof /s/ === "object"; // Firefox 5+ ... // 符合 ECMAScript 5.1
```

### 其它怪異輸入 (quirks)

#### 舊版 Internet Explorer 請留意 alert 函數

在 IE 6, 7 和 8, `typeof alert === 'object'`

**備註：** 這並不怪異。這是實情。在許多較舊的 IE 中, 主機端物件的確是物件, 而非函數

規範
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-typeof-operator |

參照
--

* instanceof (en-US)


相除運算子（/） - JavaScript

相除運算子（/）
========

相除運算子（`/`）是用來將兩個值進行相除並取得其商數。其中左運算元是被除數；右運算元是除數。

嘗試一下
----

語法
--

```js
x / y
```

範例
--

### 基本的除法

```js
1 / 2; // 0.5

Math.floor(3 / 2); // 1

1.0 / 2.0; // 0.5
```

### 除以零

```js
2.0 / 0; // Infinity

2.0 / 0.0; // Infinity, because 0.0 === 0

2.0 / -0.0; // -Infinity
```

規範
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-multiplicative-operators |

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

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

參見
--

* 相加運算子
* 相減運算子
* 相乘運算子
* 餘數運算子 (en-US)
* 指數運算子
* 遞增運算子
* 遞減運算子
* 負號運算子
* 正號運算子


條件運算子 - JavaScript

條件運算子
=====

**條件 (三元) 運算子** 是 JavaScript 唯一用到三個運算元的運算子：在一個條件後面會跟著一個問號 (`?`)，如果條件是 truthy (en-US)，在冒號(`:`)前的表達式會被執行，如果條件是 falsy (en-US)，在冒號後面的表達式會被執行，這個運算子常常被用來當作 `if` 的簡潔寫法.

嘗試一下
----

語法
--
```

condition ? exprIfTrue : exprIfFalse
```

### 參數

`condition`

值用來做為條件的表達式

`exprIfTrue`

如果 `condition` 的值是 truthy (en-US) (等於或是可轉換為 `true`) , `exprIfTrue` 會被執行

`exprIfFalse`

如果 `condition` 的值是 falsy (en-US) (等於或是可轉換為 `false`) , `exprIfFalse` 會被執行

描述
--

除了 `false`, 可能是 falsy 的表達式有 `null`, `NaN`, `0`, 空字串 (`""`) 和 `undefined`. 如果`condition` 是他們其中之一 , 那麼條件表達式的結果會是 `exprIfFalse` 的執行結果.

一個簡單的範例:

```js
var age = 26;
var beverage = age >= 21 ? "Beer" : "Juice";
console.log(beverage); // "Beer"
```

一個常用來處理 `null` 的用法 :

```js
function greeting(person) {
  var name = person ? person.name : "stranger";
  return "Howdy, " + name;
}

console.log(greeting({ name: "Alice" })); // "Howdy, Alice"
console.log(greeting(null)); // "Howdy, stranger"
```

### 條件鏈

條件 (三元) 運算子是右相依性的 (right-associative), 代表他可以以下面的方式鏈結 , 類似於 `if … else if … else if … else` 的鏈結方法 :

```js
function example(…) {
    return condition1 ? value1
         : condition2 ? value2
         : condition3 ? value3
         : value4;
}

// Equivalent to:

function example(…) {
    if (condition1) { return value1; }
    else if (condition2) { return value2; }
    else if (condition3) { return value3; }
    else { return value4; }
}
```

規範
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-conditional-operator |

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

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

參見
--

* if statement
* Nullish coalescing operator (en-US)
* Optional chaining
* Making decisions in your code — conditionals
* Expressions and operators


指數運算子（**） - JavaScript

指數運算子（\*\*）
===========

指數運算子（`**`）會回傳以第一個數字作為底數；第二個數字做為指數的運算結果。

它類同於 `Math.pow`，不一樣的是 `**` 可以用於 BigInt 的計算而 `Math.pow` 不行。

嘗試一下
----

語法
--

```js
x \*\* y
```

簡介
--

指數運算子是 right-associative：`a ** b ** c` 相當於 `a ** (b ** c)`。

在絕大多數的程式語言，例如 PHP、Python……等等，指數運算的優先順序比一元運算子（ `+` 或 `-` ）較高。但並非所有程式語言均是如此。

舉例來說，在 Bash，`**` 的優先順序就低於一元運算子。

在 Javascript，模棱兩可的求冪運算式。說得清楚一點，`+/-/~/!/delete/void/typeof` 這類一元運算子均不能置於底數之前，否則會出現 `SyntaxError`。

```js
-2 \*\* 2;
// 在 Bash 的結果為 4；其他語言則為 -4
// 在 JavaScript 則是被視為語意不明。

-(2 \*\* 2);
// 在 Javascript 就會得出 -4。這種寫法的語意就很明確
```

注意，在部分語言之中，指數運算採用插入符號 `^` ，但是在 Javascript ，`^` 則是用於XOR 位元邏輯運算子 (en-US).

範例
--

### 指數的基本運算

```js
2 \*\* 3; // 8
3 \*\* 2; // 9
3 \*\* 2.5; // 15.588457268119896
10 \*\* -1; // 0.1
NaN \*\* 2; // NaN
```

### 連續使用

```js
2 \*\* (3 \*\* 2); // 512
2 \*\* (3 \*\* 2); // 512
(2 \*\* 3) \*\* 2; // 64
```

### 與一元運算子一同使用

反轉指數運算結果之正負：

```js
-(2 \*\* 2); // -4
```

計算底數為負數的指數運算：

```js
(-2) \*\* 2; // 4
```

規範
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-exp-operator |

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

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

參見
--

* 相加運算子
* 相減運算子
* 相除運算子
* 相乘運算子
* 餘數運算子 (en-US)
* 遞增運算子
* 遞減運算子
* 負號運算子
* 正號運算子


debugger - JavaScript

debugger
========

**debugger 的宣告**會執行可用的除錯功能，例如設定斷點。如果沒有可用的除錯功能，這個宣告沒有任何作用。

語法
--
```

debugger;
```

示例
--

以下示例示範了插入 debugger 宣告的程式碼，它會在函式被呼叫、而且有除錯器的時候執行除錯器。

```js
function potentiallyBuggyCode() {
  debugger;
  // 執行並驗證一些潛在的問題、或是單步執行之類的。
}
```

呼叫除錯器時，程式會在 debugger 宣告處暫停執行。它有點像是程式碼的斷點。

![Paused at a debugger statement.](/zh-TW/docs/Web/JavaScript/Reference/Statements/debugger/screen_shot_2014-02-07_at_9.14.35_am.png)

規範
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-debugger-statement |

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

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

參見
--

* JavaScript 除錯
* Firefox 開發工具的的除錯器


do...while 語法 - JavaScript

do...while 語法
=============

`do...while` 語法會反覆執行直到指定條件的求值結果為 false 為止。`do...while` 語法如下︰

```js
do
  statement
while (condition);
```

`statement` 會在檢測條件之前就先執行一次。若要執行多個語句，就使用區塊語法（`{ ... }`）把語句群組化。如果 `condition` 為 true，就會再執行一次語句。每回執行以後，就會檢測條件。當條件為 false 時，就停止執行並把控制權轉移給 `do...while` 後面的語句。

範例
--

在以下範例中，do 循環至少會反覆執行一次，並一直反覆到 i 不再小於 5 為止。

```js
do {
  i += 1;
  document.write(i);
} while (i < 5);
```


var - JavaScript

var
===

宣告一個變數, 同時可以非強制性地賦予一初始值。

語法
--
```

var varname1 [= value1 [, varname2 [, varname3 ... [, varnameN]]]];
```

`varnameN`

變數名稱。可以是任何合法的識別字符 (identifier)。

`valueN`

變數的初始值。可以是任何合法的表示式 (expression)。

說明
--

以 `var` 宣告的變數, 其作用範圍 (scope) 及於該函數之內; 但是如果在函數外宣告, 其作用範圍則為全域性 (global) (亦即包納於全域物件之內)。

在函數之外使用以 `var` 宣告的變數是非強制的 (optional); 如果對一個未經宣告的變數賦值, 它會被暗中 (implicitly) 宣告成為一個全域變數 (亦即成為全域物件的屬性)。其中差異在於, 已宣告的變數是全域物件裡的一個無法變更 (non-configurable) 的屬性, 而未宣告的變數則是可變更的 (configurable)。

因此, 建議你一定要宣告你的變數, 不管你要將它使用於全域範圍內或者函數內。

若未宣告變數, 將非常可能導致無法預測的結果。所以, 在 ECMAScript 5 strict mode (en-US) 中, 若在函數中給一個未經宣告的函數賦值, 將會丟出錯誤。

Variable declarations, wherever they occur, are processed before any code is executed. The scope of a variable declared with `var` is its current *execution context*, which is either the enclosing function or, for variables declared outside any function, global.

Assigning a value to an undeclared variable implicitly creates it as a global variable (it becomes a property of the global object) when the assignment is executed. The differences between declared and undeclared variables are:

1. Declared variables are constrained in the execution context in which they are declared. Undeclared variables are always global.

```js
function x() {
  y = 1; // Throws a ReferenceError in strict mode
  var z = 2;
}

x();

console.log(y); // logs "1"
console.log(z); // Throws a ReferenceError: z is not defined outside x
```

2. Declared variables are created before any code is executed. Undeclared variables do not exist until the code assigning to them is executed.

```js
console.log(a); // Throws a ReferenceError.
console.log("still going..."); // Never executes.
```

```js
var a;
console.log(a); // logs "undefined" or "" depending on browser.
console.log("still going..."); // logs "still going...".
```

3. Declared variables are a non-configurable property of their execution context (function or global). Undeclared variables are configurable (e.g. can be deleted).

```js
var a = 1;
b = 2;

delete this.a; // Throws a TypeError in strict mode. Fails silently otherwise.
delete this.b;

console.log(a, b); // Throws a ReferenceError.
// The 'b' property was deleted and no longer exists.
```

Because of these three differences, failure to declare variables will very likely lead to unexpected results. Thus **it is recommended to always declare variables, regardless of whether they are in a function or global scope.** And in ECMAScript 5 strict mode (en-US), assigning to an undeclared variable throws an error.

### var hoisting

在 JavaScript 中, 變數可以先使用再宣告。

因此, 建議你永遠都把變數的宣告放在函數的最頂端。否則可能導致混亂的情況。

Because variable declarations (and declarations in general) are processed before any code is executed, declaring a variable anywhere in the code is equivalent to declaring it at the top. This also means that a variable can appear to be used before it's declared. This behavior is called "hoisting", as it appears that the variable declaration is moved to the top of the function or global code.

```js
bla = 2;
var bla;
// ...

// is implicitly understood as:

var bla;
bla = 2;
```

For that reason, it is recommended to always declare variables at the top of their scope (the top of global code and the top of function code) so it's clear which variables are function scoped (local) and which are resolved on the scope chain.

範例
--

### Declaring and initializing two variables

```js
var a = 0,
  b = 0;
```

### Assigning two variables with single string value

```js
var a = "A";
var b = a;

// Equivalent to:

var a,
  b = (a = "A");
```

Be mindful of the order:

```js
var x = y,
  y = "A";
console.log(x + y); // undefinedA
```

Here, `x` and `y` are declared before any code is executed, the assignments occur later. At the time "`x = y`" is evaluated, `y` exists so no `ReferenceError` is thrown and its value is '`undefined`'. So, `x` is assigned the undefined value. Then, `y` is assigned a value of 'A'. Consequently, after the first line, `x === undefined && y === 'A'`, hence the result.

### Initialization of several variables

```js
var x = 0;

function f() {
  var x = (y = 1); // x is declared locally. y is not!
}
f();

console.log(x, y); // Throws a ReferenceError in strict mode (y is not defined). 0, 1 otherwise.
// In non-strict mode:
// x is the global one as expected
// y leaked outside of the function, though!
```

### Implicit globals and outer function scope

Variables that appear to be implicit globals may be references to variables in an outer function scope:

```js
var x = 0; // x is declared global, then assigned a value of 0

console.log(typeof z); // undefined, since z doesn't exist yet

function a() {
  // when a is called,
  var y = 2; // y is declared local to function a, then assigned a value of 2

  console.log(x, y); // 0 2

  function b() {
    // when b is called
    x = 3; // assigns 3 to existing global x, doesn't create a new global var
    y = 4; // assigns 4 to existing outer y, doesn't create a new global var
    z = 5; // creates a new global variable z and assigns a value of 5.
  } // (Throws a ReferenceError in strict mode.)

  b(); // calling b creates z as a global variable
  console.log(x, y, z); // 3 4 5
}

a(); // calling a also calls b
console.log(x, z); // 3 5
console.log(typeof y); // undefined as y is local to function a
```

規範
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-variable-statement |

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

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

參見
--

* `let`
* `const`


async function - JavaScript

async function
==============

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

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

* Learn more
* See full compatibility
* Report feedback
**`async function`** 宣告被定義為一個回傳 `AsyncFunction` (en-US) 物件的*非同步函式* 。

你也可以使用 async function expression (en-US) 來定義一個*非同步函式*。

語法
--
```

async function name([param[, param[, ... param]]]) {
   statements
}
```

### 參數

`name`

函式名稱。

`param`

傳遞至函式的參數名稱。

`statements`

組成該函式主體的陳述。

### 回傳值

`AsyncFunction` (en-US) 物件，代表著一個非同步函式，該函式會執行該函式內的程式碼。

描述
--

當 `async` 函式被呼叫時，它會回傳一個 `Promise`。如果該 `async` 函式回傳了一個值，`Promise` 的狀態將為一個帶有該回傳值的 resolved。如果 `async` 函式拋出例外或某個值，`Promise` 的狀態將為一個帶有被拋出值的 rejected。

async 函式內部可以使用 `await` 表達式，它會暫停此 async 函式的執行，並且等待傳遞至表達式的 Promise 的解析，解析完之後會回傳解析值，並繼續此 async 函式的執行。

**備註：** `async/await` 函式的目的在於簡化同步操作 promise 的表現，以及對多個 `Promise` 物件執行某些操作。就像 `Promise` 類似於具結構性的回呼函式，同樣地，async/await 好比將 generator 與 promise 組合起來。

範例
--

### 簡單範例

```js
function resolveAfter2Seconds(x) {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve(x);
    }, 2000);
  });
}

async function add1(x) {
  const a = await resolveAfter2Seconds(20);
  const b = await resolveAfter2Seconds(30);
  return x + a + b;
}

add1(10).then((v) => {
  console.log(v); // prints 60 after 4 seconds.
});

async function add2(x) {
  const p_a = resolveAfter2Seconds(20);
  const p_b = resolveAfter2Seconds(30);
  return x + (await p_a) + (await p_b);
}

add2(10).then((v) => {
  console.log(v); // prints 60 after 2 seconds.
});
```

**警告：** 不要誤解 `Promise.all` 的 `await`

在 `add1` 裡，該執行為了第一個 `await` 而暫停了兩秒，接著為了第二個 `await` 又暫停了兩秒。在第一個計時器（timer）被觸發前，第二個計時器並不會被建立。而在 `add2` 裡，兩個計時器都被建立起來、也都執行 `await` 過了。這把它帶往了 resolve 所的 2 秒暫停、而不是 4 秒暫停。然而這兩個 `await` 呼叫都在連續運行，而非平行運行。`await` **並不是** `Promise.all` 的自動程式。如果你想讓兩個、甚至兩個以上的 `await` promises 同時執行（in parallel），你必須使用 `Promise.all`.

### 使用 async function 改寫 promise 鏈

一個 API 呼叫所回傳的 `Promise` 會導致一個 promise 鏈，將函式分隔成多個部份。考慮下列的程式碼：

```js
function getProcessedData(url) {
  return downloadData(url) // returns a promise
    .catch((e) => {
      return downloadFallbackData(url); // returns a promise
    })
    .then((v) => {
      return processDataInWorker(v); // returns a promise
    });
}
```

它可以用一個簡單的 `async function` 來改寫成這樣：

```js
async function getProcessedData(url) {
  let v;
  try {
    v = await downloadData(url);
  } catch (e) {
    v = await downloadFallbackData(url);
  }
  return processDataInWorker(v);
}
```

注意上方的範例，在 return 陳述中沒有使用 await 陳述，這是因為 async function 的回傳值隱含地被包裝於 `Promise.resolve` 之中。

規範
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-async-function-definitions |

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

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

參見
--

* `async function expression` (en-US)
* `AsyncFunction` (en-US) 物件
* `await`
* "Decorating Async Javascript Functions" on "innolitics.com"


export - JavaScript

export
======

用 **export** 可以指派函式、物件或變數，透過 `import` 宣告給外部檔案引用。

導出的模塊都會處於`嚴謹模式`，無論是否有所宣告。導出宣告無法使用嵌入式腳本（embedded script）。

語法
--
```

export { name1, name2, …, nameN };
export { variable1 as name1, variable2 as name2, …, nameN };
// 用 var, const 也通
export let name1, name2, …, nameN;
export let name1 = …, name2 = …, …, nameN;

// 底下的 function 用 class, function* 也可以
export default expression;
export default function (…) { … }
export default function name1(…) { … }

export { name1 as default, … };
export * from …;
export { name1, name2, …, nameN } from …;
export { import1 as name1, import2 as name2, …, nameN } from …;
```

`nameN`

外部檔案使用 `import` 時，用於辨認的名稱。

使用說明
----

有兩種使用 export 的方式，**named** 與 **default**。每個模組中可以有多個 named exports, 但只能有一個 default export。每種 export 都對應到一個先前說的語法。

* Named exports:

```js
// 前面已經宣告的函式可以這樣輸出
export { myFunction };

// 輸出常數
export const foo = Math.sqrt(2);
```

* 預設 export （一個 js 檔案只能有一個）:

```js
export default function () {}
// 或是 'export default class {}'
// 結尾不用分號
```

Named exports 在輸出多個值的時候很有用，在 import 的時候, 會強制根據使用相同的物件名稱.

但如果是 default export 則可以用任意的名字輸出.
```

export default k = 12; // 在test.js中這樣子寫

import m from './test' // 注意這邊因為 export default 的關係, 可以用任意名字 import 原先的k出來

console.log(m);        // will log 12
```

以下語法並不會導出所有被引入的模塊：
```

export * from …;
```

你必須額外引入它的預設輸出，再導出之：
```

import mod from "mod";
export default mod;
```

使用範例
----

### 輸出命名過的變數

模塊內可以這樣用：

```js
// module "my-module.js"
function cube(x) {
  return x \* x \* x;
}
const foo = Math.PI + Math.SQRT2;
var graph = {
  options: {
    color: "white",
    thickness: "2px",
  },
  draw: function () {
    console.log("From graph draw function");
  },
};
export { cube, foo, graph };
```

在另一個腳本就會變成這樣：

```js
//You should use this script in html with the type module ,
//eg ''<script type="module" src="demo.js"></script>",
//open the page in a httpserver,otherwise there will be a CORS policy error.
//script demo.js

import { cube, foo, graph } from "my-module";
graph.options = {
  color: "blue",
  thickness: "3px",
};
graph.draw();
console.log(cube(3)); // 27
console.log(foo); // 4.555806215962888
```

### 使用預設輸出

如果我們要輸出單獨的函式、物件、class 或當做 fallback 值來輸出的話，就可以用預設輸出：

```js
// module "my-module.js"
export default function cube(x) {
  return x \* x \* x;
}
```

外部檔案的 import 用法：

```js
import cube from "my-module";
console.log(cube(3)); // 27
```

Note 注意預設輸出不能使用 var, let , const。

規範
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-exports |

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

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

參見
--

* `import`
* ES6 in Depth: Modules, Hacks blog post by Jason Orendorff
* Axel Rauschmayer's book: "Exploring JS: Modules"


let - JavaScript

let
===

\*\*`let`\*\*用於宣告一個「只作用在當前區塊的變數」，初始值可選擇性的設定。

嘗試一下
----

語法
--
```

let var1 [= value1] [, var2 [= value2]] [, ..., varN [= valueN]];
```

### 參數

`var1`, `var2`, …, `varN`

變數名稱。

`value1`, `value2`, …, `valueN`

變數的初始值，可以是任何合法的表達式。

描述
--

`let` 可以宣告只能在目前區塊、階段或表達式中作用的變數。而 `var 則是定義了一個全域變數，或是在整個 function 而不管該區塊範圍。`

### Scoping rules

宣告 `let` 的作用範圍是它們被定義的區塊，以及該區塊包含的子區塊。這樣看起來功能跟 **`var`** 很相似。主要不同的地方在於 **`var`** 作用範圍是「整個」function：

```js
function varTest() {
  var x = 1;
  {
    var x = 2; // 這裡的 x 與 function 區塊內部的 x 是一樣的，因此會影響 function 區塊內所有的 x
    console.log(x); // 2
  }
  console.log(x); // 2
}

function letTest() {
  let x = 1;
  {
    let x = 2; // 這裡的 x 與 function 區塊內部的 x 是不同的，只會作用在這層 block 區塊中
    console.log(x); // 2
  }
  console.log(x); // 1
}
```

在上列例子裡的最前行 `let` 和 `var` 不同，`let` 並不會在全域物件中建立變數。舉例來說：

```js
var x = "global";
let y = "global";
console.log(this.x); // "global"
console.log(this.y); // undefined
```

### Emulating private members

In dealing with constructors it is possible to use the **`let`** bindings to share one or more private members without using closures:

```js
var Thing;

{
  let privateScope = new WeakMap();
  let counter = 0;

  Thing = function () {
    this.someProperty = "foo";

    privateScope.set(this, {
      hidden: ++counter,
    });
  };

  Thing.prototype.showPublic = function () {
    return this.someProperty;
  };

  Thing.prototype.showPrivate = function () {
    return privateScope.get(this).hidden;
  };
}

console.log(typeof privateScope);
// "undefined"

var thing = new Thing();

console.log(thing);
// Thing {someProperty: "foo"}

thing.showPublic();
// "foo"

thing.showPrivate();
// 1
```

### Temporal Dead Zone and errors with `let`

Redeclaring the same variable within the same function or block scope raises a `SyntaxError` (en-US).

```js
if (x) {
  let foo;
  let foo; // SyntaxError thrown.
}
```

In ECMAScript 2015, **`let`** bindings are not subject to **Variable Hoisting**, which means that **`let`** declarations do not move to the top of the current execution context. Referencing the variable in the block before the initialization results in a `ReferenceError` (en-US) (contrary to a variable declared with var, which will just have the undefined value). The variable is in a "temporal dead zone" from the start of the block until the initialization is processed.

```js
function do\_something() {
  console.log(foo); // ReferenceError
  let foo = 2;
}
```

你可能會在 `switch` (en-US) 中遇到錯誤，因為所有的 `case` 都屬於同樣的區塊中。

```js
switch (x) {
  case 0:
    let foo;
    break;

  case 1:
    let foo; // SyntaxError for redeclaration.
    break;
}
```

### `let` 於 `for` 迴圈的宣告範圍

You can use the `let` keyword to bind variables locally in the scope of `for` loops. This is different from the var keyword in the head of a for loop, which makes the variables visible in the whole function containing the loop.

```js
var i = 0;
for (let i = i; i < 10; i++) {
  console.log(i);
}
```

However, it's important to point out that a block nested inside a case clause will create a new block scoped lexical environment, which will not produce the redeclaration errors shown above.

```js
let x = 1;

switch (x) {
  case 0: {
    let foo;
    break;
  }
  case 1: {
    let foo;
    break;
  }
}
```

### The temporal dead zone and `typeof`

Unlike with simply undeclared variables and variables that hold a value of `undefined`, using the `typeof` operator to check for the type of a variable in that variable's TDZ will throw a `ReferenceError`:

```js
// prints out 'undefined'
console.log(typeof undeclaredVariable);
// results in a 'ReferenceError'
console.log(typeof i);
let i = 10;
```

### Another example of temporal dead zone combined with lexical scoping

 Due to lexical scoping, the identifier **"foo"** inside the expression `(foo + 55)` evaluates to the *if block's foo*, and **not** the *overlying variable foo* with the value of 33.
 In that very line, the *if block's "foo"* has already been created in the lexical environment, but has not yet reached (and **terminated**) its initialization (which is part of the statement itself): it's still in the temporal dead zone.

```js
function test() {
  var foo = 33;
  {
    let foo = foo + 55; // ReferenceError
  }
}
test();
```

This phenomenon may confuse you in a situation like the following. The instruction `let n of n.a` is already inside the private scope of the *for loop's block*, hence the identifier **"n.a"** is resolved to the property 'a' of the *'n' object located in the first part of the instruction itself* ("let n"), which is still in the temporal dead zone since its declaration statement has not been reached and **terminated**.

```js
function go(n) {
  // n here is defined!
  console.log(n); // Object {a: [1,2,3]}

  for (let n of n.a) {
    // ReferenceError
    console.log(n);
  }
}

go({ a: [1, 2, 3] });
```

Other situations
----------------

When used inside a block, **`let`** limits the variable's scope to that block. Note the difference between **`var`** whose scope is inside the function where it is declared.

```js
var a = 1;
var b = 2;

if (a === 1) {
  var a = 11; // the scope is global
  let b = 22; // the scope is inside the if-block

  console.log(a); // 11
  console.log(b); // 22
}

console.log(a); // 11
console.log(b); // 2
```

規範
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-let-and-const-declarations |

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

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

參見
--

* `var`
* `const`
* ES6 In Depth: `let` and `const`
* Breaking changes in `let` and `const` in Firefox 44.


for...in - JavaScript

for...in
========

迭代物件的可列舉屬性。對每個相異屬性，執行陳述式。

| Statement |
| --- |
| Implemented in: | JavaScript 1.0 |
| ECMA Version: | ECMA-262 |

語法
--
```

for (變數 in 物件) {...
}
```

### 參數

`變數`

A different property name is assigned to *variable* on each iteration.

`物件`

Object whose enumerable properties are iterated.

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

`for...in` 迴圈只迭代可列舉屬性。由內建建構式(如：Array、Object) 製造的物件，從 `Object.prototype` 和 `String.prototype` 繼承了不可列舉屬性，如： `String` (en-US)的`indexOf` (en-US) 方法，或 `Object` (en-US)的 `toString` (en-US) 方法。 迴圈將迭代全部可列舉屬性，包括了物件自身的和物件繼承自它的建構式之原型的可列舉屬性。(原型鏈上較接近物件的屬性覆蓋原型的屬性)

A `for...in` loop iterates over the properties of an object in an arbitrary order (see the delete operator (en-US) for more on why one cannot depend on the seeming orderliness of iteration, at least in a cross-browser setting). If a property is modified in one iteration and then visited at a later time, its value in the loop is its value at that later time. A property that is deleted before it has been visited will not be visited later. Properties added to the object over which iteration is occurring may either be visited or omitted from iteration. In general it is best not to add, modify or remove properties from the object during iteration, other than the property currently being visited. There is no guarantee whether or not an added property will be visited, whether a modified property (other than the current one) will be visited before or after it is modified, or whether a deleted property will be visited before it is deleted.

**備註：** If you only want to consider properties attached to the object itself, and not its prototypes, use getOwnPropertyNames (en-US) or perform a hasOwnProperty (en-US) check (propertyIsEnumerable (en-US) can also be used). Alternatively, if you know there won't be any outside code interference, you can extend built-in prototypes with a check method.

**備註：** `for..in` 不應該用來迭代一個索引順序很重要的陣列 (en-US)。 陣列索引只是以整數命名的可列舉屬性，其他方面等同於一般物件屬性。 無法擔保 `for...in` 以特定順序傳回索引，並且它將傳回全部可列舉屬性，包括非整數名的，以及繼承而來的可列舉屬性。因為迭代的順序依賴於 JavaScript 引擎的實作，在不同引擎下，迭代一個陣列可能不是以一個一致的順序存取陣列元素。因此，當你迭代陣列，且該陣列的存取順序很重要時，最好是使用以數值索引的 for (en-US) 迴圈 (或 Array.forEach (en-US) 或非標準 `for...of` (en-US) 迴圈)。

Examples
--------

The following function takes as its arguments an object and the object's name. It then iterates over all the object's enumerable properties and returns a string of the property names and their values.

```js
var o = { a: 1, b: 2, c: 3 };

function show\_props(obj, objName) {
  var result = "";

  for (var prop in obj) {
    result += objName + "." + prop + " = " + obj[prop] + "\n";
  }

  return result;
}

alert(
  show\_props(o, "o"),
); /\* alerts (in different lines): o.a = 1 o.b = 2 o.c = 3 \*/
```

The following function illustrates the use of hasOwnProperty: the inherited properties are not displayed.

```js
var triangle = { a: 1, b: 2, c: 3 };

function ColoredTriangle() {
  this.color = "red";
}

ColoredTriangle.prototype = triangle;

function show\_own\_props(obj, objName) {
  var result = "";

  for (var prop in obj) {
    if (obj.hasOwnProperty(prop)) {
      result += objName + "." + prop + " = " + obj[prop] + "\n";
    }
  }

  return result;
}

o = new ColoredTriangle();
alert(show\_own\_props(o, "o")); /\* alerts: o.color = red \*/
```

規範
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-for-in-and-for-of-statements |

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

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

See also
--------

* `for...of` (en-US) - a similar statement that iterates over the property *values*
* `for each...in` - a similar statement, but iterates over the values of object's properties, rather than the property names themselves (New in JavaScript 1.6 but deprecated)
* for (en-US)
* Generator expressions (en-US) (uses the `for...in` syntax)
* Enumerability and ownership of properties (en-US)
* `getOwnPropertyNames` (en-US)
* `hasOwnProperty` (en-US)
* `Array.prototype.forEach` (en-US)


const - JavaScript

const
=====

Constants (常數) 有點像使用 `let` 所宣告的變數，具有區塊可視範圍。常數不能重複指定值，也不能重複宣告。嘗試一下
----

語法
--
```

const name1 = value1 [, name2 = value2 [, ... [, nameN = valueN]]];
```

`nameN`

常數的名稱，可以是任何合法的 identifier。

`valueN`

常數的值，可以是任何合法的 expression，包括 function expression。

描述
--

上述宣告建立一個常數，它的可視範圍可能是全域的，或是在它所宣告的區域區塊中。 和 `var` 變數不同的是，全域的常數不會變成 window 物件的屬性。常數必須要初始化；也就是說，你必須在宣告常數的同一個敘述式中指定這個常數的值。(這很合理，因為稍後就不能再變更常數的值了)

宣告 **`const`** 會對於它的值建立一個唯讀的參考。並不是說這個值不可變更，而是這個變數不能再一次指定值。例如，假設常數的內容(值)是個物件，那麼此物件的內容(物件的參數)是可以更改的。

所有關於 "temporal dead zone" 的狀況，都適用於 `let` and `const` 。

在相同的可視範圍內，常數不能和函數，變數具有相同名稱。

範例
--

以下範例展示常數的行為。請在你的瀏覽器中試試以下程式碼。

```js
// 注意: 常數可以宣告成大寫或小寫,
// 但習慣上使用全部大寫的字母。

// 定義一個常數 MY\_FAV 並賦予它的值為7
const MY\_FAV = 7;

// 這裡會發生錯誤 - Uncaught TypeError: Assignment to constant variable.
MY\_FAV = 20;

// MY\_FAV 是 7
console.log('我喜歡的數字是: ' + MY\_FAV);

// 嘗試重複宣告同名的常數，將會發生錯誤 - Uncaught SyntaxError: Identifier 'MY\_FAV' has already been declared
const MY\_FAV = 20;

// MY\_FAV 這個名稱已經保留給上面的常數, 所以這裡也會錯誤。
var MY\_FAV = 20;

// 這式子也會錯誤
let MY\_FAV = 20;

// 很重要，請注意區塊可視範圍的特性。
if (MY\_FAV === 7) {
    // 以下式子沒有問題，並且會建立一個名叫 MY\_FAV 的具有區塊可視範圍的變數。
    // (等同於使用 let 來宣告一個具有區塊可視範圍的非常數變數。)
    let MY\_FAV = 20;

    // MY\_FAV 現在變成 20
    console.log('我喜歡的數字是：' + MY\_FAV);

    // 這會將變數懸掛於全域，而導致錯誤。(與常數同名)
    var MY\_FAV = 20;
}

// MY\_FAV 仍然是 7
console.log('我喜歡的數字是：' + MY\_FAV);

// 發生錯誤 - Uncaught SyntaxError: Missing initializer in const declaration
const FOO;

// 常數的值可以是一個物件
const MY\_OBJECT = {'key': 'value'};

// 嘗試覆寫該物件將會發生錯誤 - Uncaught TypeError: Assignment to constant variable.
MY\_OBJECT = {'OTHER\_KEY': 'value'};

// 然而, 物件的屬性並沒有被保護,
// 所以，以下敘述式沒有問題。
MY\_OBJECT.key = 'otherValue'; // Use Object.freeze() to make object immutable

// 對陣列來說也是一樣
const MY\_ARRAY = [];
// 可以把項目加到陣列中。
MY\_ARRAY.push('A'); // ["A"]
// 然而，對這個變數指定新陣列，將會發生錯誤 - Uncaught TypeError: Assignment to constant variable.
MY\_ARRAY = ['B'];
```

規範
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-let-and-const-declarations |

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

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

參閱
--

* `var`
* `let`
* Constants in the JavaScript Guide


switch - JavaScript

switch
======

**`switch` 語句**會比對一個表達式裡頭的值是否符合 `case` 條件，然後執行跟這個條件相關的陳述式 (en-US)，以及此一符合條件以外，剩下其他條件裡的陳述式。

嘗試一下
----

語法
--

```js
switch (expression) {
  case value1:
        //當 expression 的值符合 value1
        //要執行的陳述句
    [break;]
  case value2:
        //當 expression 的值符合 value2
        //要執行的陳述句
    [break;]
  ...
  case valueN:
        //當 expression 的值符合 valueN
        //要執行的陳述句
    [break;]
  [default:
        //當 expression 的值都不符合上述條件
        //要執行的陳述句
    [break;]]
}
```

`expression`

一個表達式其結果用來跟每個 `case` 條件比對。

`case valueN` 選擇性

一個 `case` 條件是用來跟 `expression` 匹配的。 如果 `expression` 符合特定的 `valueN`，那在 case 條件裡的語句就會執行，直到這個 `switch` 陳述式結束或遇到一個 `break` 。

`default` 選擇性

一個 `default` 條件；倘若有這個條件，那在 `expression` 的值並不符合任何一個 `case` 條件的情況下，就會執行這個條件裡的語句。

描述
--

一個 switch 陳述式會先評估自己的 expression。然後他會按照 `case` 條件順序開始尋找，直到比對到第一個表達式值跟輸入 expression 的值相等的 case 條件（使用嚴格的邏輯運算子 (en-US), `===`）並把控制流交給該子句、並執行裡面的陳述式（如果給定值符合多個 case，就執行第一個符合的 case，就算該 case 與其他 case 不同）

If no matching `case` clause is found, the program looks for the optional `default` clause, and if found, transfers control to that clause, executing the associated statements. If no `default` clause is found, the program continues execution at the statement following the end of `switch`. 按照慣例， `default` 語句會是最後一個條件，但不一定要存在。

The optional `break` statement associated with each case label ensures that the program breaks out of switch once the matched statement is executed and continues execution at the statement following switch. If `break` is omitted, the program continues execution at the next statement in the `switch` statement.

範例
--

### 使用 `switch`

In the following example, if `expr` evaluates to "Bananas", the program matches the value with case "Bananas" and executes the associated statement. When `break` is encountered, the program breaks out of `switch` and executes the statement following `switch`. If `break` were omitted, the statement for case "Cherries" would also be executed.

```js
switch (expr) {
  case "Oranges":
    console.log("Oranges are $0.59 a pound.");
    break;
  case "Apples":
    console.log("Apples are $0.32 a pound.");
    break;
  case "Bananas":
    console.log("Bananas are $0.48 a pound.");
    break;
  case "Cherries":
    console.log("Cherries are $3.00 a pound.");
    break;
  case "Mangoes":
  case "Papayas":
    console.log("Mangoes and papayas are $2.79 a pound.");
    break;
  default:
    console.log("Sorry, we are out of " + expr + ".");
}

console.log("Is there anything else you'd like?");
```

### 如果我忘記 break 會發生什麼事？

If you forget a break then the script will run from the case where the criterion is met and will run the case after that regardless if criterion was met. See example here:

```js
var foo = 0;
switch (foo) {
  case -1:
    console.log("negative 1");
    break;
  case 0: // foo is 0 so criteria met here so this block will run
    console.log(0);
  // NOTE: the forgotten break would have been here
  case 1: // no break statement in 'case 0:' so this case will run as well
    console.log(1);
    break; // it encounters this break so will not continue into 'case 2:'
  case 2:
    console.log(2);
    break;
  default:
    console.log("default");
}
```

### 我可以在 cases 中間放 default 嗎？

Yes, you can! JavaScript will drop you back to the default if it can't find a match:

```js
var foo = 5;
switch (foo) {
  case 2:
    console.log(2);
    break; // it encounters this break so will not continue into 'default:'
  default:
    console.log("default");
  // fall-through
  case 1:
    console.log("1");
}
```

It also works when you put default before all other cases.

### 同時使用多個條件 case 的方法

Source for this technique is here:

Switch statement multiple cases in JavaScript (Stack Overflow)

#### Multi-case - single operation

This method takes advantage of the fact that if there is no break below a case statement it will continue to execute the next case statement regardless if the case meets the criteria. See the section titled "What happens if I forgot a break?"

This is an example of a single operation sequential switch statement, where four different values perform exactly the same.

```js
var Animal = "Giraffe";
switch (Animal) {
  case "Cow":
  case "Giraffe":
  case "Dog":
  case "Pig":
    console.log("This animal will go on Noah's Ark.");
    break;
  case "Dinosaur":
  default:
    console.log("This animal will not.");
}
```

#### Multi-case - chained operations

This is an example of a multiple-operation sequential switch statement, where, depending on the provided integer, you can receive different output. This shows you that it will traverse in the order that you put the case statements, and it does not have to be numerically sequential. In JavaScript, you can even mix in definitions of strings into these case statements as well.

```js
var foo = 1;
var output = "Output: ";
switch (foo) {
  case 0:
    output += "So ";
  case 1:
    output += "What ";
    output += "Is ";
  case 2:
    output += "Your ";
  case 3:
    output += "Name";
  case 4:
    output += "?";
    console.log(output);
    break;
  case 5:
    output += "!";
    console.log(output);
    break;
  default:
    console.log("Please pick a number from 0 to 5!");
}
```

The output from this example:

| Value | Log text |
| --- | --- |
| foo is NaN or not 1, 2, 3, 4, 5 or 0 | Please pick a number from 0 to 5! |
| 0 | Output: So What Is Your Name? |
| 1 | Output: What Is Your Name? |
| 2 | Output: Your Name? |
| 3 | Output: Name? |
| 4 | Output: ? |
| 5 | Output: ! |

### Block-scope variables within `switch` statements

With ECMAScript 2015 (ES6) support made available in most modern browsers, there will be cases where you would want to use let and const statements to declare block-scoped variables.

Take a look at this example:

```js
const action = "say\_hello";
switch (action) {
  case "say\_hello":
    let message = "hello";
    console.log(message);
    break;
  case "say\_hi":
    let message = "hi";
    console.log(message);
    break;
  default:
    console.log("Empty action received.");
    break;
}
```

This example will output the error `Uncaught SyntaxError: Identifier 'message' has already been declared` which you were not probably expecting.

This is because the first `let message = 'hello';` conflicts with second let statement `let message = 'hi';` even they're within their own separate case statements `case 'say_hello':` and `case 'say_hi':`; ultimately this is due to both `let` statements being interpreted as duplicate declarations of the same variable name within the same block scope.

We can easily fix this by wrapping our case statements with brackets:

```js
const action = "say\_hello";
switch (action) {
  case "say\_hello": {
    // added brackets
    let message = "hello";
    console.log(message);
    break;
  } // added brackets
  case "say\_hi": {
    // added brackets
    let message = "hi";
    console.log(message);
    break;
  } // added brackets
  default: {
    // added brackets
    console.log("Empty action received.");
    break;
  } // added brackets
}
```

This code will now output `hello` in the console as it should, without any errors at all.

規範
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-switch-statement |

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

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

你也可以看看
------

* `if...else`


continue 語法 - JavaScript

continue 語法
===========

`continue` 語法可用來重新開始 `while`、`do-while`、`for`、`label` 語法。

* 當你使用沒加標籤的 `continue` 時，他會終止這一次的最內層的 `while`、`do-while`、`for` 語法的反覆過程，並繼續執行下一次的反覆過程。與 `break` 語法相較之下，`continue` 不會終止整個循環的執行。在 `while` 循環中，他會跳回條件處。在 `for` 循環中，他會跳回遞增表達式。
* 當你使用加上標籤的 `continue` 時，他會跳到以 `label` 標記的循環語句。

`continue` 語法如下︰

1. `continue`
2. `continue label`
範例 1
----

以下範例示範加上 `continue` 語法的 `while` 循環，`continue` 語法會在 `i` 值為 3 時執行。因此，`n` 的值依序為 1、3、7、12。

```js
i = 0;
n = 0;
while (i < 5) {
  i++;
  if (i == 3) continue;
  n += i;
}
```

範例 2
----

已加上標籤的語法 `checkiandj` 內含已加上標籤的語法 `checkj`。如果遇到 `continue`，程式會終止 `checkj` 這一次的反覆過程，並開始下一次的反覆過程。每當遇到 `continue`，就會反覆執行 `checkj` 直到他的條件返回 false 為止。當返回 false 時，`checkiandj` 語句完成了餘數的計算，且 `checkiandj` 會反覆執行，直到他的條件返回為 false 為止。當返回 false 時，程式繼續執行 `checkiandj` 後面的語句。

如果 `continue` 有一個 `checkiandj` 標籤，程式就會從 `checkiandj` 語句的開始處繼續執行。

```js
checkiandj: while (i < 4) {
  document.write(i + "<br/>");
  i += 1;
  checkj: while (j > 4) {
    document.write(j + "<br/>");
    j -= 1;
    if (j % 2 == 0) continue checkj;
    document.write(j + " is odd.<br/>");
  }
  document.write("i = " + i + "<br/>");
  document.write("j = " + j + "<br/>");
}
```


try...catch 語法 - JavaScript

try...catch 語法
==============

`try...catch` 語法標記出一整塊需要測試的語句，並指定一個以上的回應方法，萬一有例外拋出時，`try...catch` 語句就會捕捉。

`try...catch` 語法由 `try` 區塊所組成，其中內含一個以上的語句，和零個以上的 `catch` 區塊，其中內含語句用來指明當例外在 try 區塊裡拋出時要做些什麼。也就是當你希望 `try` 區塊成功，但如果他不成功時，你會想要把控制權移交給 `catch` 區塊。如果任何在 `try` 區塊內部裡的語句（或者在 `try` 區塊內部呼叫的函數裡）拋出例外，控制權將立即轉移給 `catch` 區塊。如果沒有例外從 `try` 區塊裡拋出，就會跳過 `catch` 區塊。`finally` 區塊會在 `try` 或 `catch` 區塊執行之後才執行，但會在 `try...catch` 語法後面的語句之前執行。

以下範例使用 `try...catch` 語法。本範例呼叫函數，這個函數是用來在陣列裡根據傳給函數的值來查詢月份的名稱。如果傳入的值不符合月份的數字 (1-12)，就會拋出值為 `InvalidMonthNo` 的例外，而且在 `catch` 區塊裡的語句會把 `monthName` 變數設定為 `unknown`。

```js
function getMonthName(mo) {
  mo = mo - 1; // 針對陣列索引調整月份的數字 (1=Jan, 12=Dec)
  var months = new Array(
    "Jan",
    "Feb",
    "Mar",
    "Apr",
    "May",
    "Jun",
    "Jul",
    "Aug",
    "Sep",
    "Oct",
    "Nov",
    "Dec",
  );
  if (months[mo] != null) {
    return months[mo];
  } else {
    throw "InvalidMonthNo";
  }
}

try {
  // 需要測試的語句
  monthName = getMonthName(myMonth); // 可拋出例外的函數
} catch (e) {
  monthName = "unknown";
  logMyErrors(e); // 把例外物件傳給錯誤處理器
}
```

#### catch 區塊

你可以使用單一的 `catch` 區塊來處理所有在 `try` 區塊裡可能會產生的例外，或者你也可以使用分離的 `catch` 區塊，每一個皆各自處理特定的例外類型。

**單一 catch 區塊**
 使用單一 `try...catch` 語法的 `catch` 區塊針對在 `try` 區塊裡拋出的所有例外來執行錯誤處理的代碼。

單一的 `catch` 區塊語句如下︰

```js
catch (catchID) {
  statements
}
```

`catch` 區塊所指定的識別子（前面語句裡的 `catchID`）持有由 `throw` 語法所指定的值。你可以使用這個識別子來取得有關於被拋出的例外的資訊。當進入 `catch` 區塊時，JavaScript 就會建立這個識別子。識別子只能在 `catch` 區塊的期間內持續作用。`catch` 區塊執行結束以後，識別子就不再能使用。

舉例來說，以下代碼會拋出例外。當例外出現的時候，控制權就轉移給 `catch` 區塊。

```js
try {
  throw "myException"; // 產生例外
} catch (e) {
  // 用來處理任何例外的語句
  logMyErrors(e); // 把例外物件傳給錯誤處理器
}
```

**多重 catch 區塊**
 單一的 `try` 語句可以對應複數個有前提條件的 `catch` 區塊，每一個皆可處理特定的例外的類型。於是，當指定的的例外被拋出時，就只會進入適當條件的 `catch` 區塊。你也可以針對所有未指定的例外，使用選用性的對應所有例外的 `catch` 區塊來作為語法裡最後一個的 catch 區塊。

舉例來說，以下函數呼叫三個其他的函數（已在別處定義了）來檢驗自己的參數。如果檢驗函數判斷出他所要檢驗的元素是無效的話，他就返回 0，導致呼叫者拋出對應的例外。

```js
function getCustInfo(name, id, email) {
  var n, i, e;

  if (!validate\_name(name)) throw "InvalidNameException";
  else n = name;
  if (!validate\_id(id)) throw "InvalidIdException";
  else i = id;
  if (!validate\_email(email)) throw "InvalidEmailException";
  else e = email;
  cust = n + " " + i + " " + e;
  return cust;
}
```

有各種條件的 `catch` 區塊會把控制權安排給適當的例外處理器。

```js
try {
// 可以拋出三個例外的函數
   getCustInfo("Lee", 1234, "lee@netscape.com")
}

catch (e if e == "InvalidNameException") {
// 針對無效的名稱呼叫處理器
   bad\_name\_handler(e)
}

catch (e if e == "InvalidIdException") {
// 針對無效的 ID 呼叫處理器
   bad\_id\_handler(e)
}

catch (e if e == "InvalidEmailException") {
// 針對無效的電子郵件位址呼叫處理器
   bad\_email\_handler(e)
}

catch (e){
// 不知道該做什麼，就記在日誌裡
   logError(e)
}
```

#### finally 區塊

`finally` 區塊內含的語句，會在 try 和 catch 區塊執行以後、並在 `try...catch` 語法後面的語句之前來執行。無論有沒有被拋出的例外，`finally` 區塊都會執行。如果有被拋出的例外，即使沒有 catch 區塊來處理這些例外，還是會執行 `finally` 區塊裡的語句。

當出現例外時，你可以使用 `finally` 區塊來使你的 Script 優美的停止。舉例來說，你可能需要釋放 Script 所佔用的資源。以下範例開啟了檔案，並執行使用這個檔案（伺服端的 JavaScript 可讓你存取檔案）的語句。如果在開啟檔案時有例外被拋出，`finally` 區塊會在 Script 停止之前把檔案關閉。

```js
openMyFile();
try {
  writeMyFile(theData); // 這裡有可能拋出錯誤
} catch (e) {
  handleError(e); // 如果我們得到錯誤，就處理他
} finally {
  closeMyFile(); // 永遠會關閉這項資源
}
```

#### try...catch 語法的嵌套

你可以嵌套一個以上的 `try...catch` 語法。如果有一個內部的 `try...catch` 語法沒有 catch 區塊，圍住這些 `try...catch` 語法的 catch 區塊就會被用來比對。

#### Error 物件的用處

根據錯誤的類型，你有可能使用 「name」 和 「message」 屬性來取得更多明確的訊息。「name」 提供錯誤的一般類別（例如，「DOMException」 或 「Error」），「message」 通常提供更為簡練的訊息，如此就能把錯誤物件轉換為字串來取得訊息。

如果你要拋出你自己的例外，以從這些屬性取得好處（例如，如果你的 catch 區塊不區分你自己的例外和系統的例外的話），你可以使用錯誤建構子。例如︰

```js
function doSomethingErrorProne () {
   if (ourCodeMakesAMistake()) {
      throw (new Error('The message'));
   }
   else {
      doSomethingToGetAJavascriptError();
   }
}
....
try {
   doSomethingErrorProne();
}
catch (e) {
   alert(e.name);// 警報 'Error'
   alert(e.message); // 警報 'The message' 或 JavaScript 錯誤訊息
}
```

* « 前頁
* 次頁 »


return - JavaScript

return
======

**`return` 表達式**會終止函式執行，並指明函式呼叫器（function caller）要回傳的數值。

嘗試一下
----

語法
--
```

return [[expression]];
```

`expression`

要被回傳的表達式。如果省略了表達式，函式就會回傳 `undefined`。

敘述
--

如果在 function body 內宣告 `return` 的話，函式執行就會終止。如果指定數值的話，函式呼叫器就會回傳給定的數值。例如說，以下函式會回傳 `x` 參數的次方數。

```js
function square(x) {
  return x \* x;
}
var demo = square(3);
// demo will equal 9
```

如果省略了表達式，函式就會回傳 `undefined`。

以下所有的 return 宣告都會終止函式執行：

```js
return;
return true;
return false;
return x;
return x + y / 3;
```

### 自動插入分號

`return` 宣告會受自動插入分號（automatic semicolon insertion，ASI）影響。No line terminator is allowed between the `return` keyword and the expression.

```js
return;
a + b;
```

會因為 ASI 而變成：

```js
return;
a + b;
```

主控台會警告「unreachable code after return statement」（在 return 宣告後面有無法抵達的程式碼）。

**備註：** 從 Gecko 40 開始，如果主控台發現在 return 宣告後面有無法抵達的程式碼，就會顯示警告。

要避免 ASI 問題，可以添加括號：

```js
return a + b;
```

示例
--

### 終止函式

在到達呼叫 `return` 的地方後，函式會立即停止。

```js
function counter() {
  for (var count = 1; ; count++) {
    // 無限迴圈
    console.log(count + "A"); // 直到 5
    if (count === 5) {
      return;
    }
    console.log(count + "B"); // 直到 4
  }
  console.log(count + "C"); // 永不顯示
}

counter();

// 輸出：
// 1A
// 1B
// 2A
// 2B
// 3A
// 3B
// 4A
// 4B
// 5A
```

### 函式回傳

請參見閉包。

```js
function magic(x) {
  return function calc(x) {
    return x \* 42;
  };
}

var answer = magic();
answer(1337); // 56154
```

規範
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-return-statement |

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

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

參見
--

* 函式 (en-US)
* 閉包


label - JavaScript

label
=====

**標記陳述式**可以和 `break` 或 `continue` 語句一起使用。標記就是在一條陳述式前面加個可以引用的識別符號。

嘗試一下
----

**備註：** 標記的迴圈或程式碼區塊非常罕見。通常可以使用函式呼叫而不是使用迴圈跳轉。

語法
--
```

label :
   statement
```

`label`

任何不是保留字的 JavaScript 識別符號。

`statement`

一個 JavaScript 陳述式。`break` 可用於任何標記陳述式，而 `continue` 可用於循環標記陳述式。

描述
--

可使用一個標籤來唯一標記一個循環，然後使用 `break` 或 `continue` 陳述式來指示程式是否中斷循環或繼續執行。

需要注意的是 JavaScript **沒有** `goto` 陳述式，標記只能和 `break` 或 `continue` 一起使用。

在嚴格模式中，你不能使用 「`let`」 作為標籤名稱。它會拋出一個`SyntaxError` (en-US)（let 是一個保留的識別符號）。

範例
--

### 在 `for` 迴圈中使用帶標記的 `continue`

```js
var i, j;

loop1: for (i = 0; i < 3; i++) {
  //The first for statement is labeled "loop1"
  loop2: for (j = 0; j < 3; j++) {
    //The second for statement is labeled "loop2"
    if (i === 1 && j === 1) {
      continue loop1;
    }
    console.log("i = " + i + ", j = " + j);
  }
}

// Output is:
// "i = 0, j = 0"
// "i = 0, j = 1"
// "i = 0, j = 2"
// "i = 1, j = 0"
// "i = 2, j = 0"
// "i = 2, j = 1"
// "i = 2, j = 2"
// Notice how it skips both "i = 1, j = 1" and "i = 1, j = 2"
```

### 使用帶標記的 `continue` 陳述式

給定一組資料和一組測試，下面的例子可以統計通過測試的資料。

```js
var itemsPassed = 0;
var i, j;

top: for (i = 0; i < items.length; i++) {
  for (j = 0; j < tests.length; j++) {
    if (!tests[j].pass(items[i])) {
      continue top;
    }
  }

  itemsPassed++;
}
```

### 在 `for` 迴圈中使用帶標記的 `break`

```js
var i, j;

loop1: for (i = 0; i < 3; i++) {
  //The first for statement is labeled "loop1"
  loop2: for (j = 0; j < 3; j++) {
    //The second for statement is labeled "loop2"
    if (i === 1 && j === 1) {
      break loop1;
    }
    console.log("i = " + i + ", j = " + j);
  }
}

// Output is:
// "i = 0, j = 0"
// "i = 0, j = 1"
// "i = 0, j = 2"
// "i = 1, j = 0"
// Notice the difference with the previous continue example
```

### 使用帶標記 `break` 陳述式

給定一組資料和一組測試，下面的例子判斷是否所有的資料均通過了測試。

```js
var allPass = true;
var i, j;

top: for (i = 0; items.length; i++)
  for (j = 0; j < tests.length; i++)
    if (!tests[j].pass(items[i])) {
      allPass = false;
      break top;
    }
```

### 在標記的區塊中使用 `break`

你可以在程式碼區塊中使用標記，但只有 `break` 陳述式可以使用非迴圈的標記。

```js
foo: {
  console.log("face");
  break foo;
  console.log("this will not be executed");
}
console.log("swap");

// this will log:

// "face"
// "swap
```

### 標記的函式宣告式

從 ECMAScript 2015 開始，標準的函式宣告式現在對規範的 Web 相容性附件中的非嚴格程式碼進行了標準化。

```js
L: function F() {}
```

在嚴格模式中，這會拋出 `SyntaxError` (en-US) 例外：

```js
"use strict";
L: function F() {}
// SyntaxError: functions cannot be labelled
```

產生器函式既不能在嚴格模式中標記，也不能在非嚴格模式中標記：

```js
L: function\* F() {}
// SyntaxError: generator functions cannot be labelled
```

規格
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-labelled-statements |

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

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

相關連結
----

* `break`
* `continue`


if...else - JavaScript

if...else
=========

當條件成立的時候會執行 if 陳述式裡的程式，而不成立時則執行另外一個陳述式。

嘗試一下
----

語法
--

```js
if (condition)
  statement1

// With an else clause
if (condition)
  statement1
else
  statement2
```

`condition`

一個成立或不成立的運算式。

`statement1`

如果 if 中的條件(conditions)為真時執行陳述式(statements)。陳述式可以為任何內容，包含巢狀式(nested)的 if 陳述。當要執行多行的陳述式(statements)時，使用區塊(block)將所要執行的陳述式包覆。如果不需要執行任何動作時，則不撰寫任何陳述式(empty statement)。

`statement2`

當件不成立時所執行的部份，當 else 被撰寫時才會被執行。可以是任何的陳述式，包含使用區塊(block)及巢狀(nested)的陳述。

描述
--

多重的 `if...else` 陳述式可以使用 `else if` 子句來建立一個巢狀結構的句子。要記住，在 JavaScript 中沒有 `elseif` (一個單字) 的語法可以用。

```js
if (condition1)
   statement1
else if (condition2)
   statement2
else if (condition3)
   statement3
// …
else
   statementN
```

將巢狀結構適當的排版後，我們能更了解其背後運作的邏輯：

```js
if (condition1)
  statement1
else
  if (condition2)
    statement2
  else
    if (condition3)
      statement3
// …
```

如果在一個條件式中有多個陳述要執行，可以使用區塊陳述式(`{ ... }`) 把所有陳述包在一起。 通常來說，無論如何都使用區塊陳述式是個很好的習慣，尤其是當你使用巢狀結構的 `if` 陳述式時，這會讓人更容易理解你的程式碼。

```js
if (condition) {
  statements1
} else {
  statements2
}
```

不要被Boolean物件中，布林值的 `true` 和 `false` 給混淆了。任何值只要不是 `false`、 `undefined`、 `null`、 `0`、 `NaN`，或者空字串 (`""`)，並且任何物件，包括其值是 `false`的布林物件 ，仍然會被條件陳述式視為條件成立。舉例而言：

```js
var b = new Boolean(false);
if (b) // this condition is truthy
```

實例
--

### 使用 `if...else`

```js
if (cipherChar === fromChar) {
  result += toChar;
  x++;
} else {
  result += clearChar;
}
```

### 使用 `else if`

要記得 JavaScript 沒有 `elseif` 可以使用。不過，你可以使用 `else` 和 `if`中間夾著空白的語法：

```js
if (x > 50) {
  /\* do something \*/
} else if (x > 5) {
  /\* do something \*/
} else {
  /\* do something \*/
}
```

### 條件表達式中的賦值

建議不要在條件表達式中直接對物件賦值，因為這會使人在瀏覽程式碼時很容易將賦值( assignment )與相等( equality )混淆。舉例而言，不要使用以下寫法：

```js
if ((x = y)) {
  /\* do the right thing \*/
}
```

如果你必須在條件表達式中使用賦值，最好 ˇ 的作法是以額外的括號包住賦值語句，如下所示：

```js
if (x = y) {
  // do something
}
```

規範
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-if-statement |

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

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

參見
--

* `block`
* `switch`
* `conditional operator`


for 語法 - JavaScript

for 語法
======

`for` 循環反覆執行直到指定的條件的求值為 false 為止。JavaScript 的 for 循環和 Java 和 C 的 for 循環很類似。`for` 語法如下︰

```js
for ([initialExpression]; [condition]; [incrementExpression]) statement;
```

執行 `for` 循環時，會執行以下步驟︰

1. 執行初始化表達式 `initialExpression`。這個表達式通常會初始化為 1 以上的計數器，不過也可以是任意複雜程度的表達式。也可以在表達式裡宣告變數。
2. 對 `condition` 表達式求值。如果 `condition` 的值為 true，就會執行循環語法。如果 `condition` 的值為 false，就終止 `for` 循環。如果完全省略 `condition` 表達式，條件就會被代入為 true。
3. 執行 `statement`。若要執行多個語句，就使用區塊語法（`{ ... }`）把這些語句群組化。
4. 執行更新表達式 `incrementExpression`，並回到第 2 步驟。
範例
--

以下函數內含 `for` 語法，計數至下拉式選單的已選擇選項的數目為止（Select 物件允許複選）。`for` 語法宣告變數 `i` 並以 0 初始化。他會檢驗 `i` 是否小於 `Select` 物件的選項數目，持續執行 `if` 語句，並在每一次循環之後以 1 遞增 `i`。

```html
<script type="text/javascript">
 //<![CDATA[

 function howMany(selectObject) {
 var numberSelected = 0;
 for (var i = 0; i < selectObject.options.length; i++) {
 if (selectObject.options[i].selected) numberSelected++;
 }
 return numberSelected;
 }

 //]]>
</script>
<form name="selectForm">
  <p>
    <strong>Choose some music types, then click the button below:</strong>
    <br />
    <select name="musicTypes" multiple="multiple">
      <option selected="selected">R&B</option>
      <option>Jazz</option>
      <option>Blues</option>
      <option>New Age</option>
      <option>Classical</option>
      <option>Opera</option>
    </select>
  </p>
  <p>
    <input
 type="button"
 value="How many are selected?"
 onclick="alert ('Number of options selected: ' + howMany(document.selectForm.musicTypes))" />
  </p>
</form>
```

* « 前頁
* 次頁 »


function* - JavaScript

function\*
==========

**`function*`** 宣告式（`function` 關鍵字後面跟著一個星號）定義了一個*生成器函式（generator function）*，他會回傳一個`生成器（Generator）` (en-US)物件。

嘗試一下
----

你可以透過 `GeneratorFunction` (en-US) 建構式來定義生成器函式。

語法
--
```

function* name([param[, param[, ... param]]]) {
   statements
}
```

`name`

函式名稱。

`param`

要被傳入函式的引數名稱，一個函式最多可以擁有 255 個引數。

`statements`

statements 構成了函式內容的陳述式。

描述
--

生成器是可以離開後再次進入的函式。在兩次進入之間，生成器的執行狀態（變數綁定狀態）會被儲存。

呼叫生成器函式並不會讓裡面的程式碼立即執行，而是會回傳一個針對該函式的迭代器（iterator）物件。當呼叫迭代器的 `next()` 方法時，生成器函式將會執行到遭遇的第一個 `yield` (en-US) 運算式，該運算式給定的值將從迭代器中回傳，如果是 `yield*` (en-US) 則會交給另一個生成器函式處理。`next()` 方法回傳一個物件，該物件有 `value` 屬性，包含了產生的數值，還有 `done` 屬性，為布林值，指出該生成器是否產出最後的數值。呼叫 `next()` 方法如果帶有一個參數，將會讓先前暫停的生成器函式恢復執行，以該參數值取代先前暫停的 `yield` 陳述式。

生成器中的 `return` 陳述式被執行時，會讓生成器 `done` 狀態為真。若有數值被返回的動作帶回，將是放在 `value` 傳回的。已返回的生成器不會再產生任何數值。

範例
--

### 簡單例子

```js
function\* idMaker() {
  var index = 0;
  while (index < index + 1) yield index++;
}

var gen = idMaker();

console.log(gen.next().value); // 0
console.log(gen.next().value); // 1
console.log(gen.next().value); // 2
console.log(gen.next().value); // 3
// ...
```

### yield\* 的範例

```js
function\* anotherGenerator(i) {
  yield i + 1;
  yield i + 2;
  yield i + 3;
}

function\* generator(i) {
  yield i;
  yield\* anotherGenerator(i);
  yield i + 10;
}

var gen = generator(10);

console.log(gen.next().value); // 10
console.log(gen.next().value); // 11
console.log(gen.next().value); // 12
console.log(gen.next().value); // 13
console.log(gen.next().value); // 20
```

### 傳入引數至生成器

```js
function\* logGenerator() {
  console.log(0);
  console.log(1, yield);
  console.log(2, yield);
  console.log(3, yield);
}

var gen = logGenerator();

// the first call of next executes from the start of the function
// until the first yield statement
gen.next(); // 0
gen.next("pretzel"); // 1 pretzel
gen.next("california"); // 2 california
gen.next("mayonnaise"); // 3 mayonnaise
```

### 生成器中的回傳陳述式

```js
function\* yieldAndReturn() {
  yield "Y";
  return "R";
  yield "unreachable";
}

var gen = yieldAndReturn();
console.log(gen.next()); // { value: "Y", done: false }
console.log(gen.next()); // { value: "R", done: true }
console.log(gen.next()); // { value: undefined, done: true }
```

### 生成器無法被建構

```js
function\* f() {}
var obj = new f(); // throws "TypeError: f is not a constructor"
```

### 以表達式定義生成器
```

const foo = function* () { yield 10; yield 20; };
const bar = foo();console.log(bar.next()); // {value: 10, done: false}
```

規範
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-generator-function-definitions |

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

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

Firefox 規範註記
------------

#### Generators and iterators in Firefox versions before 26

Older Firefox versions implement an older version of the generators proposal. In the older version, generators were defined using a regular `function` keyword (without an asterisk) among other differences. See Legacy generator function (en-US) for further information.

#### `IteratorResult` object returned instead of throwing

Starting with Gecko 29, the completed generator function no longer throws a `TypeError` (en-US) "generator has already finished". Instead, it returns an `IteratorResult` object like `{ value: undefined, done: true }` (Firefox bug 958951).

參見
--

* `function* expression` (en-US)
* `GeneratorFunction` (en-US) object
* 迭代協議
* `yield` (en-US)
* `yield*` (en-US)
* `Function` (en-US) object
* `function declaration` (en-US)
* `function expression` (en-US)
* `Functions and function scope` (en-US)
* Other web resources:
    + Regenerator an ES2015 generator compiler to ES5
    + Forbes Lindesay: Promises and Generators: control flow utopia — JSConf EU 2013
    + Task.js
    + Iterating generators asynchronously


break - JavaScript

break
=====

**break 陳述句**會中斷目前的迭代、`switch` 或 `label` 陳述句，並將程式流程轉到被中斷之陳述句後的陳述句。

嘗試一下
----

語法
--
```

break [label];
```

`label`

可選的。欲中斷陳述句的標籤 (label) 識別。若不是要中斷迭代或 `switch`，則需加此參數。

說明
--

中斷陳述 `break` 可加上標籤 (label) 參數，使其跳出被標籤的陳述語句。此中斷陳述 `break` 必須被包含在被標籤的陳述語句中。被標籤的陳述語句可被添加於任一個區塊 (block (en-US)) 前，而非限定在迴圈陳述。

範例
--

下面函式包含一個中斷陳述 `break` ，當 `i` 值為 3 時，中斷 `while` 迴圈，並回傳 `3 * x` 。

```js
function testBreak(x) {
  var i = 0;

  while (i < 6) {
    if (i == 3) {
      break;
    }
    i += 1;
  }

  return i \* x;
}
```

The following code uses `break` statements with labeled blocks. A `break` statement must be nested within any label it references. Notice that `inner_block` is nested within `outer_block`.

```js
outer\_block: {
  inner\_block: {
    console.log("1");
    break outer_block; // breaks out of both inner\_block and outer\_block
    console.log(":-("); // skipped
  }
  console.log("2"); // skipped
}
```

The following code also uses `break` statements with labeled blocks but generates a Syntax Error because its `break` statement is within `block_1` but references `block_2`. A `break` statement must always be nested within any label it references.

```js
block\_1: {
  console.log('1');
  break block_2; // SyntaxError: label not found
}

block\_2: {
  console.log('2');
}
```

規範
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-break-statement |

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

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

參見
--

* `continue`
* `label`
* `switch`


while 語法 - JavaScript

while 語法
========

`while` 語法會執行他的語句，只要指定的條件的求值結果為 true。`while` 語法如下︰

```js
while (condition)
  statement
```

如果條件變成 false，就停止執行循環內部的 `statement`，並把控制權移交給循環後面的語句。

條件的測試會發生在執行循環裡的 `statement` 之前。如果返回的條件為 true，就會執行 `statement`，並再次測試條件。如果返回的條件為 false，就停止執行並把控制權移交給 `while` 後面的語句。

若要執行多個語句，就使用區塊語法（`{ ... }`）把這些語句群組化。

範例 1
----

以下 `while` 循環會一直反覆直到 `n` 小於 3 為止︰

```js
n = 0;
x = 0;
while (n < 3) {
  n++;
  x += n;
}
```

每一次的反覆，循環便會遞增 `n` 並且把 `n` 的值代入給 `x`。因此，`x` 和 `n` 持有下列的值︰

* 第一次循環以後︰`n` = 1、`x` = 1
* 第二次循環以後︰`n` = 2、`x` = 3
* 第三次循環以後︰`n` = 3、`x` = 6

第三次的循環完成以後，條件 `n` < 3 不再為 true，所以終止循環。

範例 2
----

應避免無限循環。確認循環裡的條件最終一定會變成 false。否則循環永遠不會終止。下面的 `while` 循環裡的語句將會永遠執行下去，因為條件永遠不會變成 false︰

```js
while (true) {
  alert("Hello, world");
}
```


import - JavaScript

import
======

**import** 宣告用於引入由另一個模塊所導出的綁定。被引入的模塊，無論是否宣告`strict mode`，都會處於該模式。`import` 宣告無法用於嵌入式腳本（embedded scripts）。

There is also a function-like dynamic **`import()`**, which does not require scripts of `type="module"`.

Dynamic import is useful in situations where you wish to load a module conditionally, or on demand. The static form is preferable for loading initial dependencies, and can benefit more readily from static analysis tools and tree shaking (en-US).

語法
--
```

import defaultExport from "module-name";
import * as name from "module-name";
import { export } from "module-name";
import { export as alias } from "module-name";
import { export1 , export2 } from "module-name";
import { export1 , export2 as alias2 , [...] } from "module-name";
import defaultExport, { export [ , [...] ] } from "module-name";
import defaultExport, * as name from "module-name";
import "module-name";
```

`defaultExport`

從模塊要參照過去的預設導出名。

`module-name`

要導入的模塊名。通常包含 `.js` 模塊文件的相對或絕對路徑名。請確認你的開發環境，某些 bundler 會允許或要求你加入副檔名。只允許使用單引號和雙引號字符串。

`name`

參照導入時，會用做 namespace 種類的模塊名。

`export, exportN`

導出要被引入時，要用的名號。

`alias, aliasN`

別名，重新命名被 import 進來的 js 稱呼。

敘述
--

`name` 參數能將模塊物件（module object）名用於 namespace 種類，以便各導出能參照之。`export` 參數會在引用 `import * as name` 語法時，指定 individual named export。以下示例將展示語法的簡例。

### 引入整個模塊的內容

本例在當前作用域插入了 `myModule` 變數，並把所有來自 `/modules/my-module.js` 檔案的模塊導出。

```js
import \* as myModule from "/modules/my-module.js";
```

這裡會用到指定的模塊名（在此為 myModule）訪問導出來的命名空間。例如說引入模塊有 `doAllTheAmazingThings()` 的話，就可以這麼寫：

```js
myModule.doAllTheAmazingThings();
```

### 從模塊引入單一導出

給定由 `my-module` 導出的模塊，稱作 `myExport` 物件與數值，無論是顯性（因為整個模塊被導出了）與隱性（使用 `export` 宣告），這裡就在當前的作用域插入 `myExport`。

```js
import { myExport } from "/modules/my-module.js";
```

### 從模塊引入數個導出

例在當前作用域插入了 `foo` 與 `bar`。

```js
import { foo, bar } from "/modules/my-module.js";
```

### 使用便利的 alias 引入或導出

在引入時，可以重新命名導出的模塊。例如說，這裡就就在目前作用域插入 `shortName` 變數。

```js
import { reallyReallyLongModuleExportName as shortName } from "/modules/my-module.js";
```

### 引入時重命名數個導出

使用別名（aliases）以便引入或導出模塊

```js
import {
  reallyReallyLongModuleExportName as shortName,
  anotherLongModuleName as short,
} from "/modules/my-module.js";
```

### 僅作為副作用引入模塊

僅作為副作用（side effect）引入整個模塊，而不直接引入任何東西。這樣會在不引入實際數值的情況下，執行整個模塊的程式。

```js
import "/modules/my-module.js";
```

### 引入預設

你可以引入預設好的 `export`，無論他屬於物件、函式、還是類別。`import` 宣告可以接著引入該預設。

最簡單的預設引入：

```js
import myDefault from "/modules/my-module.js";
```

It is also possible to use the default syntax with the ones seen above (namespace imports or named imports). In such cases, the default import will have to be declared first. For instance:

```js
import myDefault, \* as myModule from "/modules/my-module.js";
// myModule used as a namespace
```

或是：

```js
import myDefault, { foo, bar } from "/modules/my-module.js";
// specific, named imports
```

### 動態引入

`import` 關鍵字也能透過函式呼叫引入之。在這種情況下，該函式回傳 promise。

```js
import("/modules/my-module.js").then((module) => {
  // 在模塊內作點事情
});
```

這方法也支援關鍵字 await。

```js
let module = await import("/modules/my-module.js");
```

示例
--

引用次要模塊以協助程式執行 AJAX JSON 請求。

### 模塊：file.js

```js
function getJSON(url, callback) {
  let xhr = new XMLHttpRequest();
  xhr.onload = function () {
    callback(this.responseText);
  };
  xhr.open("GET", url, true);
  xhr.send();
}

export function getUsefulContents(url, callback) {
  getJSON(url, (data) => callback(JSON.parse(data)));
}
```

### 主要程式：main.js

```js
import { getUsefulContents } from "/modules/file.js";

getUsefulContents("http://www.example.com", (data) => {
  doSomethingUseful(data);
});
```

### 動態引入

This example shows how to load functionality on to a page based on a user action, in this case a button click, and then call a function within that module. This is not the only way to implement this functionality. The `import()` function also supports `await`.

```js
const main = document.querySelector("main");
for (const link of document.querySelectorAll("nav > a")) {
  link.addEventListener("click", (e) => {
    e.preventDefault();

    import("/modules/my-module.js")
      .then((module) => {
        module.loadPageInto(main);
      })
      .catch((err) => {
        main.textContent = err.message;
      });
  });
}
```

規範
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-imports |

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

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

參見
--

* `export`
* Previewing ES6 Modules and more from ES2015, ES2016 and beyond
* ES6 in Depth: Modules, Hacks blog post by Jason Orendorff
* ES modules: A cartoon deep-dive, Hacks blog post by Lin Clark
* Axel Rauschmayer's book: "Exploring JS: Modules"


區塊 - JavaScript

區塊
==

總覽
--

區塊陳述用來組合零個或多個陳述。我們使用一對大括號 { } 以界定區塊。

| 陳述句 |
| --- |
| Implemented in | JavaScript 1.0 |
| ECMAScript edition | ECMA-262 1st edition |

語法
--
```

{
  陳述_1
  陳述_2
  ...
  陳述_n
}
```

### 參數

`陳述_1`, `陳述_2`, `陳述_n`

區塊陳述中的陳述句群。

說明
--

區塊陳述通常配合流程控制陳述（如 `if`、`for`、`while`）一併使用。

#### `var`

使用`var`區塊中定義的變數，其存取範圍是整個整個函式或是腳本，即為 Execution Context 的範圍中。

```js
var x = 1;
{
  var x = 2;
}
alert(x); // outputs 2
```

輸出結果是 2。因為 var 是宣告於整個腳本範圍中。

#### `let` 和 `const`

當使用`let`或是`const`進行宣告時，其存取範圍是只有本身定義的區塊中。

```js
let x = 1;
{
  let x = 2;
}
console.log(x); // logs 1
```

#### `function`

當 function 被呼叫時，會建立此 function 的 Execution Context，因此在 function 區塊使用`var`整個 function 區塊中都可對其進行存取。

```js
function foo() {
  {
    var a = "var";
    {
      let a = "let";
      console.log(a); // let
    }
  }
  console.log(a); // var
}
foo();
```

規範
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-block |

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

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


預設參數( Default parameters ) - JavaScript

預設參數( Default parameters )
==========================

**函式預設參數** 允許沒有值傳入或是傳入值為 `undefined 的情況下，參數能以指定的預設值初始化。`

語法
--
```

function [name]([param1[ = defaultValue1 ][, ..., paramN[ = defaultValueN ]]]) {
   要執行的程序
}
```

說明
--

在 JavaScript 中，函式的參數預設值都為 ``undefined` (en-US) 。然而，指定不同的預設值可能在一些場景很有用。這也是函式參數預設值可以幫上忙的地方。`

以往設定預設值有個普遍方法：在函式的內容裡檢查傳入參數是否為 `undefined ，如果是的話，爲他指定一個值。如下列範例，若函式被呼叫時，並沒有提供 b 的值，它的值就會是 undefined，在計算 a*b 時，以及呼叫 multiply 時，就會回傳 NaN。然而這在範例的第二行被阻止了：`:

```js
function multiply(a, b) {
  b = typeof b !== "undefined" ? b : 1;
  return a \* b;
}

multiply(5, 2); // 10
multiply(5, 1); // 5
multiply(5); // 5
```

有了 ES2015 的預設參數，再也不用於函式進行檢查了，現在只要簡單的在函式的起始處為 b 指定 1 的值：

```js
function multiply(a, b = 1) {
  return a \* b;
}

multiply(5, 2); // 10
multiply(5, 1); // 5
multiply(5); // 5
```

範例
--

### 傳入 `undefined`

這邊第二段函式呼叫中，僅管第二個傳入參數在呼叫時明確地指定為 undefined（雖不是 null），其顏色參數的值是預設值（rosybrown）。

```js
function setBackgroundColor(element, color = "rosybrown") {
  element.style.backgroundColor = color;
}

setBackgroundColor(someDiv); // color set to 'rosybrown'
setBackgroundColor(someDiv, undefined); // color set to 'rosybrown' too
setBackgroundColor(someDiv, "blue"); // color set to 'blue'
```

### 呼叫時賦予值

跟 Python 等語言不同的地方是，先前預設的代數值會拿來進行函式內的程序，也因此在函式呼叫的時候，會建立新物件。

```js
function append(value, array = []) {
  array.push(value);
  return array;
}

append(1); //[1]
append(2); //[2], 而非 [1, 2]
```

諸如此類的做法，也適用在函式和變量。

```js
function callSomething(thing = something()) {
  return thing;
}

function something() {
  return "sth";
}

callSomething(); //sth
```

### 預設的參數中，先設定的可提供之後設定的使用

先前有碰到的參數，後來的即可使用。

```js
function singularAutoPlural(
  singular,
  plural = singular + "們",
  rallyingCry = plural + "，進攻啊!!!",
) {
  return [singular, plural, rallyingCry];
}

//["壁虎","壁虎們", "壁虎，進攻啊!!!"]
singularAutoPlural("壁虎");

//["狐狸","火紅的狐狸們", "火紅的狐狸們，進攻啊!!!"]
singularAutoPlural("狐狸", "火紅的狐狸們");

//["鹿兒", "鹿兒們", "鹿兒們 ... 有所好轉"]
singularAutoPlural(
  "鹿兒",
  "鹿兒們",
  "鹿兒們平心靜氣的 \
 向政府請願，希望事情有所好轉。",
);
```

This functionality is approximated in a straight forward fashion and demonstrates how many edge cases are handled.

```js
function go() {
  return ":P";
}

function withDefaults(
  a,
 b = 5,
 c = b,
 d = go(),
 e = this,
 f = arguments,
 g = this.value,
) {
  return [a, b, c, d, e, f, g];
}

function withoutDefaults(a, b, c, d, e, f, g) {
  switch (arguments.length) {
    case 0:
      a;
    case 1:
      b = 5;
    case 2:
      c = b;
    case 3:
      d = go();
    case 4:
      e = this;
    case 5:
      f = arguments;
    case 6:
      g = this.value;
    default:
  }
  return [a, b, c, d, e, f, g];
}

withDefaults.call({ value: "=^\_^=" });
// [undefined, 5, 5, ":P", {value:"=^\_^="}, arguments, "=^\_^="]

withoutDefaults.call({ value: "=^\_^=" });
// [undefined, 5, 5, ":P", {value:"=^\_^="}, arguments, "=^\_^="]
```

### 函式內再定義函式

Introduced in Gecko 33. Functions declared in the function body cannot be referred inside default parameters and throw a `ReferenceError` (en-US) (currently a `TypeError` (en-US) in SpiderMonkey, see Firefox bug 1022967). Default parameters are always executed first, function declarations inside the function body evaluate afterwards.

```js
// 行不通的！ 最後會丟出 ReferenceError。
function f(a = go()) {
  function go() {
    return ":P";
  }
}
```

### Parameters without defaults after default parameters

Prior to Gecko 26, the following code resulted in a `SyntaxError` (en-US). This has been fixed in Firefox bug 777060 and works as expected in later versions. Parameters are still set left-to-right, overwriting default parameters even if there are later parameters without defaults.

```js
function f(x = 1, y) {
  return [x, y];
}

f(); // [1, undefined]
f(2); // [2, undefined]
```

### Destructured parameter with default value assignment

You can use default value assignment with the destructuring assignment notation:

```js
function f([x, y] = [1, 2], { z: z } = { z: 3 }) {
  return x + y + z;
}

f(); // 6
```

規範
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-function-definitions |

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

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

參見
--

* Original proposal at ecmascript.org