2015-11-19 47 views
0

我正在寫一個JavaScript程序,程序狀態的一部分是一個對象。我想定期計算狀態,並將其與當前的一個決定,如果一個事件應觸發,這裏的一些僞代碼:Javascript對象值平等測試?

var newState = calculateState(); 

if (newState !== oldState) { 
    triggerEvent(); 
} 

但是因爲狀態是一個對象,我需要做的值相等檢查以及防止空引用檢查。也就是說,如果狀態變爲非空值或周圍的其他方法無效,我也需要觸發事件:

if (newState === null && oldState !== null || // non null -> null 
    newState !== null && oldState === null || // null -> non null 
    (newState !== null && oldState !== null && // both non null, check members 
    (newState.age !== oldState.age || 
     newState.name !== oldState.name))) { 
    triggerEvent(); 
} 

正如你所看到的代碼是非常的混亂和醜陋。

有沒有一種方法可以在JavaScript中重構這個?

謝謝!

+0

從我的頭頂開始,您可以嘗試在兩個對象上使用'JSON.stringify'並將它們簡單地作爲字符串進行比較。 ((newState || newState)&&(!oldState || oldState)&&(newState && oldState)){if(newState.name!== oldState.name){ triggerEvent(){ – 1cgonza

+0

可以試試這個 ' ; } }' –

+0

@ 1cgonza但'JSON.stringify'是否會說出關於'Object'中的鍵的順序?而且即使在ES6中按鍵排序的時候,你是否真的希望「{a:1,b:2}」和「{b:2,a:1}」不相等? –

回答

2

如果它的清潔代碼的緣故,我建議處理,像這樣在單獨的函數兩個對象之間的比較:

ar newState = calculateState(); 

// areEqual() takes the two objects as parameters 
if (areEqual(oldState, newState)) { 
    triggerEvent(); 
} 

然後決定是否兩個對象在函數等於或不

// This function compares two state objects and returns true if they are valid and different 
function areEqual(oldState, newState){ 
    return (newState === null && oldState !== null || // non null -> null 
     newState !== null && oldState === null || // null -> non null 
     (newState !== null && oldState !== null && // both non null, check members 
     (newState.age !== oldState.age || newState.name !== oldState.name))); 
} 
1
if (n === null && o !== null || // non null -> null 
    n !== null && o === null || // null -> non null 
    (n !== null && o !== null && // both non null, check members 
    (n.age !== o.age || 
     n.name !== o.name))) { 
    triggerEvent(); 
} 

讓我們打破這(我用no速記,以適應更多的線,使其更容易,看看有什麼GOI納克上 - 不是建議使用這種簡潔約定):

n === null && o !== null || 
n !== null && o === null 

此表達式可以僅僅簡化:n !== o

這是有效的,因爲如果一個爲null而不是另一個,則表達式將評估true。如果對象指向相同的內存地址,這也將返回false(這是一件好事,因爲它們的字段也將匹配,並且在這種情況下我們不希望觸發事件)。

這樣可以讓我們在這裏:

if (n !== o || 
    ((n !== null && o !== null) && 
    (n.age !== o.age || n.name !== o.name))) { 
    triggerEvent(); 
} 

爲了簡化超出了通常需要引入的功能。如果你爲這些狀態提供了一種平等方法,比較這些agename字段,可能會很不錯。如果你添加了新的狀態,它也會使代碼更容易出錯。

空交換技巧

另一個技巧,有時可以在幾個週期的成本是有用的對之間的空掉。例如:

// if 'a' is null: 
if (!a) 
{ 
    // swap it with 'b'. 
    a = [b, b = a][0]; 
} 

// Now if 'a' is still null, both values are null. 
// If 'b' is not null, both values are not null. 

我們可以利用它在上面的代碼如下所示:

local state1 = oldState 
local state2 = newState 
if (!state1) 
    state1 = [state2, state2 = state1][0]; 

if (state1) { 
    // If only one of these is not null or their fields don't match: 
    if (!state2 || state1.age !== state2.age || state1.name !== state2.name) { 
     triggerEvent(); 
    } 
} 

很多,這是否可以簡化或complexifies將根據你如何經常使用這種簡短交換單的襯墊。如果非常罕見,那可能只會增加混亂。但是這種交換技術可以讓你編寫稍微冗長的代碼來交換可能更直接的代碼,並且不會讓你的大腦堆棧淹沒(有時候更簡單的代碼比一些非常複雜的東西更需要嵌套非常人性的解析)。

+0

是把它們放入函數是一個好主意。在這個階段使用空置交易技巧對我來說太過分了,因爲我確信從現在開始兩週後我無法瞭解它們:謝謝! – fantasticsid