I know this has been answered but I would like to comment anyway.
The way I handled it is by passing Keys and Values as string and recreating the Map in apex.
Here is an excerpt:
So if I were to pass a map through JS, I would send the keys and values as separate JS Array types. Now, note that remoting lets us pass the List(array) of sObject, so the values can be a List Visualforce.remoting.Manager.invokeAction('{!$RemoteAction.jsRemotingControllerv1.createAccountsMap}', keys, accounts_values);
Over at the contoller side, I'd recreate the map like this:
Map<String,Account> accountMap = new Map<String,Account>();
for (Integer i = 0 ; i < keys.size(); i++) {
accountMap.put(keys[i],a[i]);
}
This example may not be depicting a real lide scenario but it gives an alternative when we no choice but to pass a Map around.
For the complete code, you can see my post here
https://salesforcemann.wordpress.com/2016/11/16/javascript-remoting-create-account-record-using-single-sobject-list-map/