如何自动为Javascript生成良好的访问器?

时间:2013-07-29 08:10:42

标签: javascript

目前我正在以下列方式实现一些Javascript对象:

var graph = (function(){
    var width = 200;
    var height = 300;
    [...]

    var obj={
    width: function(value){
        if(value===undefined) return width;
        width=value;
        return obj;
    },
    height: function(value){
        if(value===undefined) return height;
        height=value;
        return obj;
    },[...]
    };
    return obj;
})();


graph.width(200)
    .height(graph.width()*2);

我的访问器都以非常类似的方式定义,主要是为了允许一种链式API。

像这样定义宽度和高度真的很烦人,有什么样的模式可以用来仍然能够利用闭包的东西,而不必复制粘贴相同的函数n次?

2 个答案:

答案 0 :(得分:2)

您可以编写一个生成这些函数然后调用它的函数,但我不能说它很漂亮,因为您没有对闭包变量的简洁访问。

请请不要在生产中使用它,这只是一个概念证明。

我们在这里要做的是在语言中引入,该宏将被称为generate。调用generate(propName)将生成您想要的属性的getter。我们将代码包装在一个函数中,然后自己处理宏。 这只是为了证明这个概念。

语法类似于:

var graph = Capture(function () {
    var width = 200;
    var height = 300;

    var obj = {
        width: generate(width),
        height:generate(height)
    };
    return obj;
});

首先:

Here is a working fiddle

我们的工作如下:

1)我们将IIFE包装在Capture函数中,这将处理内容

var graph = Capture(function () {
    [..]
});

我们使用字符串处理来将generate关键字与适当的内容

放在一起
function Capture(src) {
    src = src.toString()
    src = src.replace(/generate\((.*?)\)/g, function (a, b) {
        return "function(value){"+
            "if(value===undefined){ return "+b+"; } "+b+" = value; return obj;}";
    });
    console.log(src)
    return eval("("+src+")")();
}

我们匹配generate(SOMETHING)并将其替换为您想要的属性。这就是替换所做的。

3)我们评估该函数,然后将其命名为

由于我们一次评估了所有内容,因此它可以访问闭包。这给了我们想要的东西和更短的语法。

应该我们做什么?

更好的选择是使用带有_varName表示法的私有,并为这些目的完全避免使用闭包变量。这是大多数库所做的,非常清楚,并且你没有这些问题,你可以简单地使用括号表示法和bind作为语法糖。

答案 1 :(得分:2)

你也可以创造一个私人物品 - 而不是世界上最可怕的东西:

function generate(me, prop) {
    return function(value) {
        if(arguments.length === 0) return me[prop];
        me[prop] = value;
        return this;
    };
}

var graph = (function() {
    var me = {
        width:  200,
        height: 300
    };

    var obj = {
        width:  generate(me, 'width'),
        height: generate(me, 'height')
    };

    return obj;
})();