闭包和CoffeeScript的范围

时间:2015-02-23 09:28:55

标签: javascript coffeescript

以下代码定义了两个函数linescircles,它们分别返回一个函数fg。函数fg相等(() -> size)仅为了简单起见,但通常它们是变量size的不同函数。

lines = () ->
    size = 10 # default value
    f = () -> size
    f.size = (_) ->
      size = _
      f
    f

circles = () ->
    size = 15 # default value
    g = () -> size
    g.size = (_) ->
      size = _
      g
    g

在控制台上,上面的代码产生了以下模式,这就是我需要的:

> lines()() # 10
> lines().size(20)() # 20
> circles()() # 15
> circles().size(30)() #30

您可能会注意到,f.sizeg.size方法是闭包,linescircles上的方法相同。然后我的问题是:如何避免复制size方法的代码?(使用coffeescript或javascript)

我尝试了不同的解决方案,但我找不到正确的方法。为了复制闭包,size方法中的size变量应该引用size上第一行定义的lines变量(同样适用于{ {1}})。

2 个答案:

答案 0 :(得分:2)

您可以定义工厂函数来生成单独的“构造函数”:

shape = (defaultSize, calculate = (size) -> size) ->
    () ->
        size = defaultSize
        f = () -> calculate size
        f.size = (_) ->
            size = _
            f
        f

lines = shape(10)

circles = shape(15, (size) -> size * size * Math.PI)

这编译为:

var circles, lines, shape;

shape = function(defaultSize, calculate) {
  if (calculate == null) {
    calculate = function(size) {
      return size;
    };
  }
  return function() {
    var f, size;
    size = defaultSize;
    f = function() {
      return calculate(size);
    };
    f.size = function(_) {
      size = _;
      return f;
    };
    return f;
  };
};

lines = shape(10);

circles = shape(15, function(size) {
  return size * size * Math.PI;
});

console.log(lines()());

console.log(lines().size(20)());

console.log(circles()());

console.log(circles().size(30)());

答案 1 :(得分:2)

您无法在代码中使用辅助函数,因为它无法按预期访问闭包变量。但是,您可以将整个代码包装在一个函数中,以便它分别返回linescircles函数:

make = (def, accessor) ->
    () ->
        size = def
        f = () -> accessor size
        f.size = (_) ->
           size = _
           f
        f

lines = make 10, (size) -> size
circles = make 15, (size) -> size