Up to sync new members in replica set Let's say I have 2 nodes in my replica set with an arbiter running. Now when it comes to adding a new member to an existing replica set while it is still running for production, what steps do I need to do to make sure the data in new node will be in sync with other nodes? Especially when the new node is a fresh mongo instance without any data.

Do I just rs.add() new node to replica set and the data will be populated automatically? Or do I need mongodump latest data from current node then restore it to new node and do rs.add() to let it sync anything left behind?

I am thinking to use the same strategy when I need to upgrade the mongo machine ie. prepare 2 new machines with mongo instance, add them to replica set, let the data sync, remove mongo connection to the 2 old machines, remove 2 old machines from replica, shutdown old machines leaving me with 2 new upgraded machines. Would that be the best practice while running in production to avoid 0 downtime?
Answer to all you questions is YES. 
You can just add (rs.add()) new nodes to RS and data will be synced. Faster way to do that is create those new nodes from backup/snapshot of old node and then rs.add().

What comes to upgrade, if you are just upgrading to new version of MongoD, there is no need to prepare new nodes and then add them to RS, but of course you can do that too. Proper procedure is just upgrade software at secondary node (one node at time) and then just "step down" primary and upgrade that node too.

What ever procedure you choose, there is no downtime.