Q:

javascript new explained for c++ programmers

Background
I am struggling to create a function that takes a timestamp in ms from JSON and to convert it to a human-readable format. I attempted alert(Date(jsonData.timestamp).toISOString()), which resulted in "Date(...).toISOString is not a function".
But in the example for timeformating that I had looked up it worked, soon enough I noted that the pattern to be used is let myDate=new Date(...); alert(myDate.toISOString()). I tried and got an Invalid Date. So for some reason Date() and new Date() interpret the arguments differently.
I thought maybe the value I get from JSON which is a string should be passed in as a Number when I do that I end up with two different dates:
new Date(1594720804236643));    // result differs from thjsut calling Date, without new
new Date("1594720804236643")); //does not work

I figured that surly copy construciton would work and ended up with:
let myDate=Date(jsonData.timestamp);
let myDateObject=new Date(myDate);
alert(myDateObject.toISOString());

While I have a (horrible, ugly) solution, I would like to understand the nuances of new
Actual Question
Where is the difference between MyClass() and new MyClass(), a C++ programming background suggests that the difference is the only whether the object is allocated on the stack or heap. In Javascript, clearly the rules are different. On the one hand the interpretation of arguments changes, on the other hand, the set of functions available on the resulting object is different.

A:

Here's a common pattern for a constructor that, for its own design reasons, wants to behave the same way whether it's invoked with new or not:
function NewIsOptional() {
  if (this == null || !(this instanceof NewIsOptional))
    return new NewIsOptional();
  // normal constructor work
}

That trick works by checking this. If it's not bound (as would be the case if new were missing) or if it's bound to something of the wrong type, the code makes a recursive call via new. That pass through the constructor will see this properly bound to a new object, so it'll proceed to do its normal thing.
Now, not all constructor functions do that. I'm not sure I've ever written one, and I've typed in a lot of code. Some constructors throw an exception if they're not invoked via new.  Some, for example the Symbol "constructor", throw an exception if they are invoked with new. Some constructors (like Date or Boolean) do completely different things when they're not invoked with new.
Basically there are no rules. A constructor is a function, and the code in the constructor can do whatever it wants. It can type check the parameter values and decide on different behaviors or decide to throw errors. It can call other functions, manipulate its closure if it was created inside one, and of course do mundane things like initialize object properties (which is the most usual thing to do).
Also, note that how a particular constructor function interprets its arguments, and how it behaves when it is or isn't invoked via new, are two completely orthogonal things.  There are no rules for that either. A constructor is free to interpret arguments exactly the same with or without new, or it can interpret them completely differently. There are no fundamental language rules behind any of this.

