2013-08-26 55 views
3

使用默認值初始化對象我正在使用Underscore的default函數。根據該文件,它的工作原理是這樣的:Underscore.js默認功能的副作用免費版本?

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函數更改輸入參數並將結果作爲返回值返回。它應該是或者。

你如何處理這種情況?有沒有更好的方法來處理這個問題?

+1

我完全同意你的看法。一般而言,變更參數是一種反模式,因爲它會產生非明顯的副作用。我很驚訝這種行爲是由許多框架如下劃線和lodash選擇的。我相信它誘使開發人員編寫錯誤的代碼。 –

回答

4

該功能正在做它記錄下來的事情。修改傳入函數的對象並不罕見,並且返回它們並不罕見。退貨是一件非常方便的事情,所以您可以編寫完全符合您的「解決方法」的代碼。

您的「解決方法」是正確的方法。

另一種選擇將是使foo新對象的原型:

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

...但我只知道通過看annotated source(該鏈接會爛的作品,但它會在那附近) Underscore,因爲文檔沒有指定當複製默認值時,它只查找「自己的」屬性。 (它不會,它使用in。)

另請注意,Object.create是ES5,並且可能需要在舊版瀏覽器上使用墊片。上面的使用是可調的(因爲我沒有使用Object.create的第二個參數)。


我只是重新閱讀您的標題:Underscore.js默認功能

無副作用的版本?

如果你不喜歡你的解決方法,無副作用的版本是相當容易的創建:

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

,創建一個空對象,並把它在參數的開始,然後連鎖到_.defaults

+1

不,該行爲完全符合「副作用」的定義,請參見[維基百科定義](http://en.wikipedia.org/wiki/Side_effect_(computer_science)):「在計算機科學中,函數或表達式如果除了返回一個值之外,還會修改某個狀態或者與外部世界的調用函數進行可觀察的交互,這被稱爲有副作用。「 – c089

+0

@ c089:好的,對於術語來說是夠公平的。 –

+1

我的downvote來自最初的術語問題,很高興將其刪除。 – c089

1

在我看來,文檔是正確的。

在構造函數中,您可以跳過使用返回值。喜歡的東西:

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

如果這不是你想要的你的解決方法是相當不錯的,我認爲。

1

我乾脆寫一個包裝上的作用:

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

然後,只需使用它像:

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

你甚至可以添加功能,以強調自己(通過_.mixin我相信)如果你願意。