简体   繁体   中英

Closures and CoffeeScript's Scoping

The following code defines two functions, lines and circles , that return a function, f and g respectively. Functions f and g are equal ( () -> size ) only for simplicity, but in general they are different functions of the variable 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

On the console, the above code results on the following pattern, which is what I need:

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

As you may note, the f.size and g.size methods are closures and they are the same on both lines and circles . Then my question is: how I can avoid to duplicate the code for the size method? (with coffeescript or javascript)

I tried different solutions, but I did not find the right way. In order to replicate the closure, the size variable inside the size method should refer to the size variable defined at the first line on lines (and the same holds for circles ).

You can define a factory function to produce your individual "constructors":

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)

This compiles to:

 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)()); 

You can't use a helper function in your code, as that won't have access to the closure variable as expected. However, you can wrap your whole code in a function so that it returns you the lines or circles function respectively:

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

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM