何时在闭包中使用typedef?

时间:2016-04-21 13:09:15

标签: javascript types google-closure-compiler google-closure-library

我对以下代码片段感到困惑:

/**
 * Pair of width and height.
 * @param {string} width
 * @param {string} height
 * @constructor
 * @struct
 */
var Pair = function(width, height) {
  /** @type {string} */
  this.key = key;
  /** @type {string} */
  this.value = value;
};

VS

/**
 * @typedef {{width: string, height: string}}
 */
var Pair;

基本上我需要创建一个新类型,并且在使用哪一个时非常困惑?

1 个答案:

答案 0 :(得分:2)

  

哪一个使用?

这在某种程度上是个人偏好和编码风格的问题。 Closure Compiler更倾向于使用类,接口,方法等在Java中找到的伪经典继承模式,这与其他方法不同。见Michael Bolin的Inheritance Patterns in JavaScript

另请参阅Annotating JavaScript for the Closure Compiler,其中包含各种标签的最简洁定义。

对于我自己,我使用伪经典继承模式。因此,99%的时间我使用@constructor定义了与new关键字一起使用的类。这些类也标有@struct,因此它们具有一组固定的属性和方法。我的大约80%的类声明他们@implement@interface因为这允许我使用接口类型而不是绑定到特定的类实现。

有时我会使用@typedef来定义一个具有一些最小属性集的对象。对我来说,这种类型的对象通常没有定义任何函数,它只是一种聚合某些属性的方法。

以下是我的代码中的一个示例:

/**  A regular expression and the replacement string expression to be used in a
* `String.replace()` command.
* @typedef {{regex: !RegExp, replace: string}}
* @private
*/
Terminal.regexPair;

我可以在其他地方使用typedef:

/** Set of regular expressions to apply to each command.
* @type {!Array.<!Terminal.regexPair>}
* @private
*/
this.regexs_ = [];

优点是很容易制作这种类型的东西:

/** Add regular expression and replacement string to be used by `String.replace()`
* for transforming script commands before they are executed.
* @param {!RegExp} regex regular expression for finding a name to transform
* @param {string} replace the replacement string for use with `String.replace()`
*/
Terminal.prototype.addRegex = function(regex, replace) {
  this.regexs_.push({regex:regex, replace:replace});
};

请注意,我使用{regex:regex, replace:replace}创建了一个匿名对象,而不是使用new运算符。然而,编译器正在检查此对象是否具有由Terminal.regexPair定义的所需(最小)属性集。

但是还有很多关于如何编写JavaScript代码的哲学。你当然可以定义一个需要具有指定签名的函数的typedef。