如何让闭包编译器正确检查 javascript 中构造函数的属性
我无法理解如何让 javascript 的 google 闭包编译器正确识别构造函数的属性。例如,在下面的代码中,我不知道第 27 行中的 'cls' 是什么类型,这样编译器就不会产生以下(我认为是错误的)错误:
foo.js:29: WARNING - Property say从未在 cls 上定义 cls.say(); ^
从阅读文档看来我应该像 25 中那样做。有人可以帮忙吗?谢谢,
1 /**
2 * @interface
3 **/
4 function Sayer() {}
5 Sayer.prototype.say = function() {};
6 Sayer.say = function() {};
7
8 /**
9 * @constructor
10 * @implements {Sayer}
11 **/
12 function A() {}
13 A.say = function() { console.log('A factory'); };
14 A.prototype.say = function() { console.log('Am an A'); }
15
16 /**
17 * @constructor
18 * @implements {Sayer}
19 **/
20 function B() {}
21 B.say = function() { console.log('B factory'); };
22 B.prototype.say = function() { console.log('Am an B'); };
23
24 /**
25 * @param {function(new:Sayer)} cls
26 **/
27 function makeSayer(cls) {
28 var obj = new cls();
29 cls.say();
30 obj.say();
31 }
32
33 makeSayer(A);
34 makeSayer(B);
I can't understand how to get the google closure compiler for javascript to properly recognize properties of a constructor. For example, in the code below, I don't know what type to give 'cls' in line 27 so that the compiler does NOT produce the following (erroneous in my opinion) error:
foo.js:29: WARNING - Property say never defined on cls
cls.say();
^
From reading the documentation it seems that I should be doing it as I do in 25. Can someone help please? Thanks,
1 /**
2 * @interface
3 **/
4 function Sayer() {}
5 Sayer.prototype.say = function() {};
6 Sayer.say = function() {};
7
8 /**
9 * @constructor
10 * @implements {Sayer}
11 **/
12 function A() {}
13 A.say = function() { console.log('A factory'); };
14 A.prototype.say = function() { console.log('Am an A'); }
15
16 /**
17 * @constructor
18 * @implements {Sayer}
19 **/
20 function B() {}
21 B.say = function() { console.log('B factory'); };
22 B.prototype.say = function() { console.log('Am an B'); };
23
24 /**
25 * @param {function(new:Sayer)} cls
26 **/
27 function makeSayer(cls) {
28 var obj = new cls();
29 cls.say();
30 obj.say();
31 }
32
33 makeSayer(A);
34 makeSayer(B);
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
问题在于接口上定义的方法 (
A.say
) 与接口原型上定义的方法 (A.prototype.say
) 之间的区别。在 Closure 的类型系统中,@interface< /code> 标签
提供以下保证:
请注意,它只关心原型上的方法。它不关心接口本身的方法。
假设您创建一个新类
C
,它实现Sayer
。闭包将确保您定义了C.prototype.say
。不过您可以跳过C.say
。您不需要实施它。以下是完全有效的Sayer
。由于这是一个有效的
Sayer
,因此我们应该可以安全地调用makeSayer(C)
。现在很清楚为什么您的makeSayer
定义不正确。它假定已定义 cls.say,但 Closure 不提供此类保证。关闭会发现问题并给出适当的错误消息。那么你应该做什么呢?
如果您想遵循标准的面向对象方法,那么您可能需要两个接口,一个用于工厂
SayerFactory
,另一个用于它创建的Say
对象。您的所有方法都将成为原型中定义的方法,并且 Closure 将为您完成所有检查。但是,如果您喜欢在构造函数上使用
say
方法的想法,那么您可以尝试使用鸭子类型来强制工厂方法的存在。例如:当然,如果您需要定义多个方法,鸭子类型方法的扩展性不会很好。对于定义的每个方法,类型签名会变得越来越大。
祝你好运!
The issue is the distinction between a method defined on a interface (
A.say
) vs a method defined on an interface's prototype (A.prototype.say
). In Closure's type system the@interface
tag provides the following guarantee:Notice it only cares about methods on the prototype. It doesn't care about methods on the interface itself.
Suppose you make a new class,
C
, that implementsSayer
. Closure will make sure you defineC.prototype.say
. However you can skipC.say
. You are not required to implement it. The following is a perfectly validSayer
.Since this is a valid
Sayer
, we should be safe to callmakeSayer(C)
. Now it is clear why your definition ofmakeSayer
is incorrect. It assumes thatcls.say
is defined, but Closure makes no such guarantee. Closure spots the problem and gives you the appropriate error message.So what should you do?
If you want to follow a standard object-oriented approach then you probably need two interfaces, one for the factory
SayerFactory
and one for the objects it createsSay
. All of your methods will become methods defined in prototypes and Closure will do all your checking for you.But if you like the idea of having a
say
method on your constructors then you could try using duck typing to enforce the presence of the factory method. Something like:Of course the duck typing approach won't scale very well if you need to define more than one method. The type signature would grow larger and larger for each method defined.
Good luck!
接口上的“Sayer.say”将被忽略。
您是否正在尝试为 Closure 的高级模式做准备?在高级模式中,“A.say”和“B.say”被重命名为“A$say”和“B$say”,类型检查期望这一点并适当地抱怨它(不会有方法 A.say )。
您可以通过间接添加它来避免崩溃:
我想您可以通过添加如下行来避免类型警告:
但我不确定这是否是您想要的。
您可以避免麻烦并将其添加到原型中并调用它:
"Sayer.say" on the interfaces is ignored.
Are you trying to prepare this for Closure's advanced mode? In advanced mode "A.say" and "B.say" are renamed to "A$say" and "B$say", the type check expects this and complains about it appropriately (there won't be a method A.say).
You can avoid collapsing by have it added by it indirectly:
I suppose you could avoid the type warning by adding a line like:
But I'm not sure you this is what you want.
You can avoid the hassle and add it to the prototype and call that instead: