{% 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 %}