2015-11-19 3 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 на обоих объектах и ​​сравнить их просто как строки. – 1cgonza

+0

Вы можете попробовать это 'if ((! NewState || newState) && (! OldState || oldState) && (newState && oldState)) { if (newState.name! == oldState.name) { triggerEvent() ; } } ' –

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

Давайте разберем это вниз (я использовал n и o Shorthands, чтобы соответствовать больше на линии, чтобы сделать его легче увидеть, что гои нг на - не предполагая использовать эти лаконичные конвенции):

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

Это выражение можно упростить до просто: n !== o.

Это работает, потому что, если он является нулевым, а не другим, выражение будет оценивать true. Если объекты указывают на идентичные адреса памяти, это также вернет false (это хорошо, поскольку их поля также совпадают, и мы не хотим запускать события в этом случае).

Так что заставляет нас здесь:

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

Для упрощения за это, как правило, требуют введения функции. Было бы неплохо, если бы вы делали такие вещи, чтобы обеспечить метод равенства для этих состояний, который сравнивает эти поля age и name. Это также сделает код менее подверженным ошибкам, если вы добавите новые состояния.

Null Сменный Trick

Другой трюк, который иногда может быть полезно при стоимости нескольких циклов является нулевой своп между парами. Пример:

// 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

Да, включение их в функцию - хорошая идея. Использование трюков с нулевым свопом было бы слишком для меня на этом этапе, так как я уверен, что не смогу понять их через 2 недели: Спасибо! – fantasticsid

Смежные вопросы