{% raw %}
## JavaScript 類型
強烈建議你去使用編譯器.
如果使用 JSDoc, 那么盡量具體地, 準確地根據它的規則來書寫類型說明. 目前支持兩種[JS2](http://wiki.ecmascript.org/doku.php?id=spec:spec)和 JS1.x 類型規范.
### JavaScript 類型語言
JS2 提議中包含了一種描述 JavaScript 類型的規范語法, 這里我們在 JSDoc 中采用其來描述函數參數和返回值的類型.
JSDoc 的類型語言, 按照 JS2 規范, 也進行了適當改變, 但編譯器仍然支持舊語法.
| 名稱 | 語法 | 描述 | 棄用語法 |
| --- | --- | --- | --- |
| 普通類型 | `{boolean}`, `{Window}`, `{goog.ui.Menu}` | 普通類型的描述方法. | |
| 復雜類型 | `{Array.<string>}` 字符串數組. `{Object.<string, number>}` 鍵為字符串, 值為整數的對象類型. | 參數化類型, 即指定了該類型中包含的一系列”類型參數”. 類似于 Java 中的泛型. | |
| 聯合類型 | `{(number|boolean)}` 一個整數或者布爾值. | 表示其值可能是 A 類型, 也可能是 B 類型 | `{(number,boolean)}`, `{number|boolean}`, `{(number||boolean)}` |
| 記錄類型 | `{{myNum: number, myObject}}` 由現有類型組成的類型. | 表示包含指定成員及類型的值. 這個例子中, `myNum` 為 `number` 類型, `myObject` 為任意類型. 注意大括號為類型語法的一部分. 比如, `Array.<{length}>`, 表示一具有 `length` 屬性的 `Array` 對象. | |
| 可為空類型 | `{?number}`一個整型數或者為 NULL | 表示一個值可能是 A 類型或者 `null`.默認, 每個對象都是可為空的. 注意: 函數類型不可為空. | `{number?}` |
| 非空類型 | `{!Object}`一個對象, 但絕不會是 `null` 值. | 說明一個值是類型 A 且肯定不是 null.默認情況下, 所有值類型 (boolean, number, string, 和 undefined) 不可為空. | `{Object!}` |
| 函數類型 | `{function(string, boolean)}`具有兩個參數 ( string 和 boolean) 的函數類型, 返回值未知. | 說明一個函數. | |
| 函數返回類型 | `{function(): number}`函數返回一個整數. | 說明函數的返回類型. | |
| 函數的 `this` 類型 | `{function(this:goog.ui.Menu, string)}`函數只帶一個參數 (string), 并且在上下文 goog.ui.Menu 中執行. | 說明函數類型的上下文類型. | |
| 可變參數 | `{function(string, ...[number]): number}`帶一個參數 (字符類型) 的函數類型, 并且函數的參數個數可變, 但參數類型必須為 number. | 說明函數的可變長參數. | |
| 可變長的參數 (使用 `@param` 標記) | `@param {...number} var_args`函數參數個數可變. | 使用標記, 說明函數具有不定長參數. | |
| 函數的 [缺省參數](http://docs.kissyui.com/docs/html/styleguide/google/optional) | `{function(?string=, number=)}` 函數帶一個可空且可選的字符串型參數, 一個可選整型參數. `=` 語法只針對 `function` 類型有效. | 說明函數的可選參數. | |
| 函數 [可選參數](http://docs.kissyui.com/docs/html/styleguide/google/optional) (使用 `@param` 標記) | `@param {number=} opt_argument` `number`類型的可選參數. | 使用標記, 說明函數具有可選參數. | |
| 所有類型 | `{*}` | 表示變量可以是任何類型. | |
### JavaScript中的類型
#### `number`
```
1
1.0
-5
1e5
Math.PI
```
#### `Number`
[數值對象](http://bq69.com/blog/articles/script/868/google-javascript-style-guide.html#Wrapper_objects_for_primitive_types)
```
new Number(true)
```
#### `string`
字符串值
```
'Hello'
"World"
String(42)
```
#### `String`
[字符串對象](http://bq69.com/blog/articles/script/868/google-javascript-style-guide.html#Wrapper_objects_for_primitive_types)
```
new String('Hello')
new String(42)
```
#### `boolean`
布爾值
```
true
false
Boolean(0)
```
#### `Boolean`
[布爾對象](http://bq69.com/blog/articles/script/868/google-javascript-style-guide.html#Wrapper_objects_for_primitive_types)
```
new Boolean(true)
```
#### `RegExp`
```
new RegExp('hello')
/world/g
```
#### `Date`
```
new Date
new Date()
```
#### `null`
```
null
```
#### `undefined`
```
undefined
```
#### `void`
沒有返回值
```
function f() {
return;
}
```
#### `Array`
類型不明確的數組
```
['foo', 0.3, null]
[]
```
#### `Array.<number>`
```
[11, 22, 33]
```
#### `Array.<Array.<string>>`
```
Array.<Array.<string>>
```
#### `Object`
```
{}
{foo: 'abc', bar: 123, baz: null}
```
#### `Object.<string>`
```
{'foo': 'bar'}
```
#### `Object.<number, string>`
鍵為整數, 值為字符串的對象.
注意, JavaScript 中, 鍵總是被轉換成字符串, 所以
`obj['1'] == obj[1]`.
也所以, 鍵在 for…in 循環中是字符串類型. 但在編譯器中會明確根據鍵的類型來查找對象.
```
var obj = {};
obj[1] = 'bar';
```
#### `Function`
[函數對象](http://bq69.com/blog/articles/script/868/google-javascript-style-guide.html#Wrapper_objects_for_primitive_types)
```
function(x, y) {
return x * y;
}
```
#### `function(number, number): number`
函數值
```
function(x, y) {
return x * y;
}
```
#### `SomeClass`
```
/** @constructor */
function SomeClass() {}
new SomeClass();
```
#### `SomeInterface`
```
/** @interface */
function SomeInterface() {}
SomeInterface.prototype.draw = function() {};
```
#### `project.MyClass`
```
/** @constructor */
project.MyClass = function () {}
new project.MyClass()
```
#### `project.MyEnum`
枚舉
```
/** @enum {string} */
project.MyEnum = {
BLUE: '#0000dd',
RED: '#dd0000'
};
```
#### `Element`
DOM 中的元素
```
document.createElement('div')
```
#### `Node`
DOM 中的節點.
```
document.body.firstChild
```
#### `HTMLInputElement`
DOM 中, 特定類型的元素.
```
htmlDocument.getElementsByTagName('input')[0]
```
### 可空 vs. 可選 參數和屬性
JavaScript 是一種弱類型語言, 明白可選, 非空和未定義參數或屬性之間的細微差別還是很重要的.
對象類型(引用類型)默認非空. 注意: 函數類型默認不能為空.
除了字符串, 整型, 布爾, undefined 和 null 外, 對象可以是任何類型.
```
/**
* Some class, initialized with a value.
* @param {Object} value Some value.
* @constructor
*/
function MyClass(value) {
/**
* Some value.
* @type {Object}
* @private
*/
this.myValue_ = value;
}
```
告訴編譯器 `myValue_` 屬性為一對象或 null. 如果 `myValue_` 永遠都不會為 null, 就應該如下聲明:
```
/**
* Some class, initialized with a non-null value.
* @param {!Object} value Some value.
* @constructor
*/
function MyClass(value) {
/**
* Some value.
* @type {!Object}
* @private
*/
this.myValue_ = value;
}
```
這樣, 當編譯器在代碼中碰到 `MyClass` 為 null 時, 就會給出警告.
函數的可選參數可能在運行時沒有定義, 所以如果他們又被賦給類屬性, 需要聲明成:
```
/**
* Some class, initialized with an optional value.
* @param {Object=} opt_value Some value (optional).
* @constructor
*/
function MyClass(opt_value) {
/**
* Some value.
* @type {Object|undefined}
* @private
*/
this.myValue_ = opt_value;
}
```
這告訴編譯器 `myValue_` 可能是一個對象, 或 null, 或 undefined.
注意: 可選參數 `opt_value` 被聲明成 `{Object=}`, 而不是 `{Object|undefined}`. 這是因為可選參數可能是 undefined. 雖然直接寫 undefined 也并無害處, 但鑒于可閱讀性還是寫成上述的樣子.
最后, 屬性的非空和可選并不矛盾, 屬性既可是非空, 也可是可選的. 下面的四種聲明各不相同:
```
/**
* Takes four arguments, two of which are nullable, and two of which are
* optional.
* @param {!Object} nonNull Mandatory (must not be undefined), must not be null.
* @param {Object} mayBeNull Mandatory (must not be undefined), may be null.
* @param {!Object=} opt_nonNull Optional (may be undefined), but if present,
* must not be null!
* @param {Object=} opt_mayBeNull Optional (may be undefined), may be null.
*/
function strangeButTrue(nonNull, mayBeNull, opt_nonNull, opt_mayBeNull) {
// ...
};
```
{% endraw %}