什么时候在闭包中使用 typedef?
When to use typedef in closure?
我对以下代码片段困惑了很长时间:
/**
* 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;
基本上我需要创建一个新类型并且非常困惑何时使用哪个?
which one to use when?
这在某种程度上是个人喜好和编码风格的问题。 Closure Compiler 更倾向于在 Java 中发现的 pseudoclassical 继承模式 以及 classes、接口、方法等,这与其他方法。请参阅 Michael Bolin 的 Inheritance Patterns in JavaScript。
另请参阅 Annotating JavaScript for the Closure Compiler,其中对各种标签进行了最简洁的定义。
对于我自己,我使用伪classical 继承模式。因此,99% 的时间我都用 @constructor
定义 classes,它们是为了与 new
关键字一起使用。这些 class 也用 @struct
标记,因此它们具有一组固定的属性和方法。我的 class 中大约 80% 的人说他们 @implement
一个 @interface
因为这允许我使用接口类型而不是绑定到特定的 class 实现。
有时我会使用 @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。
我对以下代码片段困惑了很长时间:
/**
* 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;
基本上我需要创建一个新类型并且非常困惑何时使用哪个?
which one to use when?
这在某种程度上是个人喜好和编码风格的问题。 Closure Compiler 更倾向于在 Java 中发现的 pseudoclassical 继承模式 以及 classes、接口、方法等,这与其他方法。请参阅 Michael Bolin 的 Inheritance Patterns in JavaScript。
另请参阅 Annotating JavaScript for the Closure Compiler,其中对各种标签进行了最简洁的定义。
对于我自己,我使用伪classical 继承模式。因此,99% 的时间我都用 @constructor
定义 classes,它们是为了与 new
关键字一起使用。这些 class 也用 @struct
标记,因此它们具有一组固定的属性和方法。我的 class 中大约 80% 的人说他们 @implement
一个 @interface
因为这允许我使用接口类型而不是绑定到特定的 class 实现。
有时我会使用 @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。