JavaScript 类型

强烈建议你去使用编译器.

如果使用 JSDoc, 那么尽量具体地, 准确地根据它的规则来书写类型说明. 目前支持两种JS2和 JS1.x 类型规范.

JavaScript 类型语言

JS2 提议中包含了一种描述 JavaScript 类型的规范语法, 这里我们在 JSDoc 中采用其来描述函数参数和返回值的类型.

JSDoc 的类型语言, 按照 JS2 规范, 也进行了适当改变, 但编译器仍然支持旧语法.

名称 语法 描述 弃用语法
普通类型 {boolean}, {Window}, {goog.ui.Menu} 普通类型的描述方法.
复杂类型 {Array.<string>} 字符串数组. {Object.<string, number>} 键为字符串, 值为整数的对象类型. 参数化类型, 即指定了该类型中包含的一系列”类型参数”. 类似于 Java 中的泛型.
联合类型 {(number&#124;boolean)} 一个整数或者布尔值. 表示其值可能是 A 类型, 也可能是 B 类型 {(number,boolean)}, {number&#124;boolean}, {(number&#124;&#124;boolean)}
记录类型 {{myNum: number, myObject}} 由现有类型组成的类型. 表示包含指定成员及类型的值. 这个例子中, myNumnumber 类型, 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函数参数个数可变. 使用标记, 说明函数具有不定长参数.
函数的 缺省参数 {function(?string=, number=)} 函数带一个可空且可选的字符串型参数, 一个可选整型参数. = 语法只针对 function 类型有效. 说明函数的可选参数.
函数 可选参数 (使用 @param 标记) @param {number=} opt_argument number类型的可选参数. 使用标记, 说明函数具有可选参数.
所有类型 {*} 表示变量可以是任何类型.

JavaScript中的类型

number

1
1.0
-5
1e5
Math.PI

Number

数值对象

new Number(true)

string

字符串值

'Hello'
"World"
String(42)

String

字符串对象

new String('Hello')
new String(42)

boolean

布尔值

true
false
Boolean(0)

Boolean

布尔对象

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

函数对象

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) {
  // ...
};