I'll walk you through it.
if (a === b) return true;
We check if these are the same thing, we'll come back to here later.
if (a == null || typeof a != "object" ||
b == null || typeof b != "object")
return false;
We check if one or neither of these things are objects are defined. We'll come back here too.
Keep these first two snippets in mind, they don't come into play until we call the function recursively.
var propsInA = 0, propsInB = 0;
These will be used to keep track of the number of properties in object A and B
for (var prop in a)
propsInA += 1;
for (var prop in b) {
propsInB += 1;
if (!(prop in a) || !deepEqual(a[prop], b[prop]))
return false;
}
return propsInA == propsInB;
}
We have two for loops. The first one just loops through all properties in A (look up For...in syntax if you're unfamiliar), and for each it increments the variable propsInA.
The second loop does the same for B, but here it gets more complicated. First it checks if that property exists in A, or if deepequal returns true. This is where the first two snippets we examined come into play. The first snippet is used here to return true if the properties we give it are the same. The second snippet says "if we passed properties instead of functions, stop here". This is important because this function only needs to go on past here if its the initial invocation. All recursive invocations only need to use the first part. If either of these two return false, we return false to the initial invocation, because we know there was a difference between A and B.
return propsInA == propsInB;
We can't return true here, because we don't actually know if there is just less properties in B. Even though everything else appeared the same, we can't assume that they have the same amount of properties. This assures, as a final check, that we will only return true if the number of properties in A is equal to the number in B
Feel free to ask me to explain further.