2

我正在编写一个库,希望在高级模式下与 Closure Compiler 兼容。库中的大多数对象都维护一个内部属性对象,这些属性通常是 API 的一部分,这导致我的源文件充满了很多这样的函数。

/*
 * Get name.
 */
Layer.prototype.getName = function() {
    return this.attrs.name;
}
/*
 * Set name.
 */
Layer.prototype.setName = function(name) {
    this.attrs.name = name;
}

我可以想出十亿种方法来优化它,以稍微整理一下我的代码。一个例子:KineticJS,根据这个相关的问题,做了一些像这样的事情:

Global.addGettersSetters = function(obj, property) {
    obj['get'+property] = function() { return this.attrs[property] }
    obj['set'+property] = function(val) { this.attrs[property] = val }
}

// Later that day, in our original object, we have:

Global.addGettersSetters(Layer, 'name');

我的理解是,这对于 Closure Compiler 是一个禁忌——名称不会被缩短,函数也不会被优化,因为我将 Layer 的属性指定为字符串。

那么,有没有一种方法可以让我完全正确地定义接口而不会弄乱我的代码?也许我忽略了闭包库中的某些东西?

另一种解决方案:有没有办法在现代 JS 中实现 C# 风格的属性?Closure Compiler 在某种程度上认为是允许的?我有幸针对 Webkit 并且只有带有这个库的 Webkit,所以还没有完全实现的东西很好。

4

4 回答 4

3

如果 getter/setter 无论如何都是公开的,那么您需要它们不要在缩小的 js 中重命名。这意味着让他们使用字符串作为名称很好 - 它们不会被缩小,但这就是你想要的。

是的,现代 JS 有 getters/setters

于 2013-04-23T00:54:39.203 回答
1

您不能动态添加一个函数,然后该函数可以由 Closure Compiler 编译(并缩小/混淆),因为该动态“addGettersSetters”函数只能在运行时使用,因此编译器不知道它可以创建什么。使用编译器的缺点是有很多重复的预编译代码,但好处是大多数使用 getter 和 setter 的地方要么被缩小,要么只是更改为对变量的内联引用。

此外,通过放入显式 getter/setter 并使用 JsDoc 注释正确地注释它们:

 /*
 * Set name.
 * @param {string} name
 */
Layer.prototype.setName = function(name) {
    this.attrs.name = name;
}

您可以在代码中添加某种级别的类型安全,以确保在有人调用“setName(5)”时在编译期间收到警告。

否则我会遵循 Chris 的建议并研究 JS getter/setter(此处的其他参考)。虽然我没有将它们与闭包编译器一起使用,所以我不能保证它们。

于 2013-04-25T13:02:07.890 回答
0

不是原始问题的完整答案,只是添加一些信息。

您可以看到各种 JavaScript OOP 框架如何处理 getter/setter,例如:jsPerf.com - JavaScript Object Oriented Libraries Benchmark with getter and setter

有没有办法让我在不弄乱我的代码的情况下完全正确地定义接口?

Tan Nhu(基准的原始作者)创建了自己的 OOP 库jsface,可在以下网址获得:https ://github.com/tnhu/jsface

我喜欢它,我正是出于这个原因使用它

编辑:例如在 SO 文章get and set in TypeScript中提到了如何在 TypeScript 中解决 getters/setters 生成器

有关其他框架的更完整列表及其编码 getter/setter 的方式,您可以查看编译为 JS 的语言列表 · jashkenas/coffeescript Wiki · GitHub

于 2014-05-28T06:39:57.530 回答
0

抱歉,我没有得到 ne8il 答案以及为什么它被标记为正确答案。

你可以做你想做的事,只需像这样在和.prototype之间添加:obj[

function addGettersSetters(obj, property) {
    // You can also add this if you don't want to declare attrs = {} each time
    // if (!("attrs" in obj.prototype)) obj.prototype.attrs = {};
    obj.prototype['get'+property] = function() { return this.attrs[property] }
    obj.prototype['set'+property] = function(val) { this.attrs[property] = val }
}

并且还要用大写字母写属性名称。然后你可以像这样使用它:

var Layer = function() { this.attrs = {}; };
// Or just: 'var Layer = function(){};' if you use the line commented above

addGettersSetters(Layer, 'Name');

var layer = new Layer();
layer.setName("John");
alert(layer.getName()); // "John"
于 2013-12-09T15:48:05.857 回答