1

I'm following along the Discover Meteor tutorial and after commit 8-1 we add:

// Check that the userId specified owns the documents
ownsDocument = function(userId, doc) {
  return doc && doc.userId === userId;
}

What I don't understand is that doc and userId are not strictly equal (===), so why does this work?

For reference:

doc:

{ _id:       '1a2b3c4d',
  url:       'blahblah.com',
  title:     'blah blah',
  userId:    '0w9x8y7z',
  author:    'testuser',
  submitted: '...'}

doc.userId:

userId: 0w9x8y7z

userId:

userId: 0w9x8y7z

I get that doc.userId === userId, but why would doc && doc.userId === userId pass?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Justin
  • 57
  • 4
  • `doc` itself is evaluated as `true` (its an object; not 0, null, "" or anything else that would evaluated as `false` in a boolean context) As its true the next test following `&&` is then evaluated. (This is done as if `doc` were `null` (falsey) attempting to access a property `doc.userId ` would cause an error) – Alex K. Jan 13 '15 at 15:54
  • as @AlexK. says above, it doesn't evaluate to false, thus the statement continues to be evaluated. this is known as the short circuit technique. basically, it's a good idea to check that `doc` exists before you try and access one of its properties. if `doc` were undefined, it would return false without considering whether it (being undefined) had a property of userId and whether that is equal to the provided `userId`. – Todd Jan 13 '15 at 15:57
  • One clarification. If `doc` is `undefined`, then `undefined` will be returned, not `false`. This would be better written as `return !!doc && doc.userId === userId;`. – Sean Jan 14 '15 at 23:57

3 Answers3

2

This is a common idiom used in JavaScript, if you want to check that an object is not undefined (or otherwise falsey) before accessing one of its properties you can say:

obj && obj.prop

The && operator does not evaluate the second argument if the first argument is falsey, so this protects your code from trying to retrieve a property value from a variable whose value is undefined

So, the return statement in your example is equivalent to:

if (doc){
    return doc.userId;
} else {
    return doc;
}
codebox
  • 19,927
  • 9
  • 63
  • 81
  • Ohhhhh, so I'm checking that `doc` exists and THEN checking that `doc.userId = userId`. That makes so much more sense now. Thanks a bunch! – Justin Jan 13 '15 at 16:09
2

The root of your confusion appears to be that you interpret this:

if(doc && doc.userId === userId)

as "if both doc and doc.userId are equal to userId". This is not the case.

Each side of the && is a separate condition altogether. It is the same as:

if(doc == true && doc.userId === userId)

Secondly, the == true part on the left side is redundant, so is often not included when checking if a variable is truthy.

The reason for the truthy check is that you want to check that doc is not falsey, before you try to access a property on it. Using a logical AND, if the left side does not evaluate to true, then the right side will not be executed. Without the check, if doc was falsey then an error would be produced for trying to access a property on a none object.

Community
  • 1
  • 1
MrCode
  • 63,975
  • 10
  • 90
  • 112
1

If you check the Operator Precedence table, you will see that equality (== / ===) is of higher precedence than AND (&&), so this:

doc && doc.userId === userId

is parsed this way:

doc && (doc.userId === userId)

and not this one:

(doc && doc.userId) === userId

Then, since doc is truthy, the engine evaluates doc.userId === userId and returns that result.

Scott Sauyet
  • 49,207
  • 4
  • 49
  • 103