3

要使用默认值初始化对象,我使用的是 Underscore 的默认函数。根据文档,它的工作原理如下:

var foo = _.defaults(object, *defaults)

它被描述为:

使用默认对象中的值填充对象中未定义的属性,并返回该对象。一旦属性被填充,进一步的默认值将无效。

虽然它基本上工作正常,但我总是偶然发现一件事:操纵原始对象的副作用。

如果我跑

var foo = { bar: 'baz' };

然后说

var bar = _.defaults(foo, { dummy: 23 });

不仅bar有一个名为 的属性dummy,原始foo对象也已更改。我目前的解决方法是:

var bar = _.defaults({}, foo, { dummy: 23 });

不幸的是,你很容易忘记这一点。我认为defaults函数更改输入参数并将结果作为返回值返回是一种非常奇怪的行为。应该是或。

你如何处理这种情况?有没有更好的方法来处理这个问题?

4

3 回答 3

4

该函数正在执行它记录的操作。修改传递给函数的对象并不少见,返回它们也不少见。返回是一件方便的事情,因此您可以编写与您的“解决方法”完全相同的代码。

您的“解决方法”是正确的方法。

另一种选择是制作foo新对象的原型:

var bar = _.defaults(Object.create(foo), { dummy: 23 });

...但我只知道通过查看下划线的带注释的源 (该链接可能会腐烂,但它会在附近)起作用,因为文档没有指定在复制默认值时是否只查找“拥有”的属性。(它没有,它使用in.)

另请注意,这Object.create是 ES5,可能需要在旧浏览器上使用 shim。上面的用法是可调整的(因为我没有使用Object.create' 的第二个参数)。


我刚刚重新阅读了您的标题:

Underscore.js默认功能无副作用版?

如果你不喜欢你的解决方法,一个无副作用的版本很容易创建:

function myDefaults() {
    var args = [{}];
    args.push.apply(args, arguments);
    return _.defaults.apply(_, args);
}

这会创建一个空白对象并将其放在参数的开头,然后链接到_.defaults.

于 2013-08-26T07:34:25.140 回答
1

我只需为它编写一个包装函数:

function defs (template_obj, additions) {
    return _.defaults({},template_obj,additions);
}

然后像这样简单地使用它:

var bar = defs(foo, { dummy: 23 });

如果您愿意,您甚至可以将函数添加到下划线本身(我相信通过 _.mixin)。

于 2013-08-26T07:52:46.617 回答
1

在我看来,文档是正确的。

在构造函数中,您可以完全跳过使用返回值。就像是:

function(options) {
    _.defaults(options, defaults);
   // you can now continue to use options instead of a new object
}

如果那不是您想要的,我认为您的解决方法非常好。

于 2013-08-26T07:35:48.180 回答