Coffeescript 将带有默认参数的关联数组传递给函数

Coffeescript pass associative array with default parameters to the function

我想将散列(关联数组,对象)传递给 coffeescript 中的函数,当散列中定义了默认值时。将散列对象传递给函数会将这些值与默认值合并。我该如何实施?

var uiDialog = function({url = 'secret', data = 'something'}) {
  /* body of the function */
};

uiDialog({data:null,method:'GET'}); /* result arguments are { url: secret, data: null, method: 'GET' } */
uiDialog({url:'myURL',method:'GET'}); /* result arguments are { url: 'myURL', data: 'something', method: 'GET' } */

如果您可以访问 jQuery,请尝试:$.extend({}, yourDefaultsOptions, functionOptions)

如果您没有,您可以尝试手动进行。这是一个示例方法

defaults = { a: 1, b: 3 }
funcOpts = { a: 2 }
final    = {}

for key, value of defaults
  final[key] = value

for key, value of funcOpts
  final[key] = value

console.log(defaults)
console.log(funcOpts)
console.log(final)

问题

问题是Coffeescript支持默认函数参数和解构赋值,但不能同时支持。允许更多代码重用和更复杂结构的最简单解决方案是让 coffeescript 进行解构,并自己承担处理默认参数的任务。幸运的是,这很容易,多亏了 jQuery 的 extend(第一个解决方案)或该方法的 polyfill(第二个解决方案)。

jQuery 解决方案

我冒昧地稍微重写了您的代码,并且为了您的方便,我构建了一个可用的 JSFiddle:http://jsfiddle.net/scarl3tt/jkLjxyqe/

do ->
    class UiDialog
        _default =
            url: 'secret'
            data: 'something'
        constructor: (options) ->
            {@url, @data, @method} = $.extend({}, _default, options)

    dlg1 = new UiDialog
        data: null
        method:'GET' # result arguments are { url: secret, data: null, method: 'GET' }
    dlg2 = new UiDialog
        url: 'myURL'
        method: 'GET' # result arguments are { url: 'myURL', data: 'something', method: 'GET' }
        
    $('body').append("<div><h1>dlg1</h1><pre>#{JSON.stringify dlg1}</pre>")
    $('body').append("<div><h1>dlg2</h1><pre>#{JSON.stringify dlg2}</pre>")
    return

普通 JS 解决方案

然而,承认 jQuery 并不属于每个项目,一个好的解决方案是定义一个方法来做同样的事情。我在第二个示例中提供了一个,它是一个常见 extend polyfill 的 coffeescript 端口。它不是最有效的,但它很简洁:http://jsfiddle.net/scarl3tt/uq4tu6y1/

do (w=window) ->
    utils = (w.utils = w.utils || {})
    utils.extend = (target, others...) ->
        for source in others
            for name in Object.getOwnPropertyNames(source)
                target[name] = source[name]
        return target
    
    class UiDialog
        _default =
            url: 'secret'
            data: 'something'
        constructor: (options) ->
            {@url, @data, @method} = utils.extend({}, _default, options)

    dlg1 = new UiDialog
        data: null
        method:'GET' # result arguments are { url: secret, data: null, method: 'GET' }
    dlg2 = new UiDialog
        url: 'myURL'
        method: 'GET' # result arguments are { url: 'myURL', data: 'something', method: 'GET' }
        
    $('body').append("<div><h1>dlg1</h1><pre>#{JSON.stringify dlg1}</pre>")
    $('body').append("<div><h1>dlg2</h1><pre>#{JSON.stringify dlg2}</pre>")
    return

请注意,我的原始解决方案确实包含并使用了 jQuery,但这只是为了便于打印结果。它实际上不需要让它工作。

此外 - 为清楚起见 - 我将我的 extend polyfill 放在 window.utils 命名空间而不是 window.$.