1

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.

Saeed Hassanvand
  • 783
  • 1
  • 9
  • 27
ted
  • 4,457
  • 5
  • 30
  • 76
  • I feel that https://stackoverflow.com/questions/1646698/what-is-the-new-keyword-in-javascript is a good start but why the arguments passed in are treated differntly is still unclear to me. – ted Jul 15 '20 at 13:14
  • [`new Date("...")`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/Date) expects a string in ISO8601 format – Andreas Jul 15 '20 at 13:17
  • Because arguments are not typed, you can pass anything you want to any function. It may not *work*, but that's the function's problem at run time. The Date constructor responds to the actual parameter type on its own. – Pointy Jul 15 '20 at 13:17
  • Also that number you're using to construct a Date gives a date instance in September of the year 52504. – Pointy Jul 15 '20 at 13:19
  • 1
    Similarly, constructor functions can tell whether they've been invoked with `new` by checking the value of `this` explicitly. Some constructors detect that they were not called with `new` and respond by doing that themselves, others don't. JavaScript is truly a vastly different language from C++; it's best to not try and apply C++ reasoning to JavaScript coding. – Pointy Jul 15 '20 at 13:21
  • This is actually two examples of very different things. Date constructor's handling of strings with Date.parse, and numbers as timestamps is more like an overloaded constructor. It doesn't really connect with your question. And then you've additionally mixed in the topic of prototypal inheritance and functions and objects. So I guess you're actually asking about 3 different topics that don't really correlate well, which ends up making the whole thing difficult to explain. This definitely needs focus. – user120242 Jul 15 '20 at 15:06
  • @ted if your actual question is your actual question, can you remove all the talk about `Date`? Because that's not related to how the `new` keyword changes things (effecting constructor calls rather than plain function calls). Also, if that _really_ is your actual question: searching SO will already find you the answer for that. – Mike 'Pomax' Kamermans Jul 15 '20 at 15:12
  • @Pointy Regarding "Because arguments are not typed": I am well aware that I can pass any type in and the function may or may not work, what gets me is that `Constructor(X)` and `new Constructor(X)` do interpret `X` differently. – ted Jul 16 '20 at 07:35
  • @Andreas or a time in Miliseconds sine 1970 (second variant), but valid point. (I pass us instead of ms) – ted Jul 16 '20 at 07:44
  • @ted Any constructor *can* do two things: behave differently based on the type of argument passed (simply by checking the types), and behave differently based on whether `this` is bound to an object in the appropriate way. It's just code. Constructors don't *have* to do anything in particular; again, it's **just code**. – Pointy Jul 16 '20 at 12:18

1 Answers1

1

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.

Pointy
  • 371,531
  • 55
  • 528
  • 584
  • This is very helpful to me I think. If I understand correctly `new X()` creates an Instance binding `this` and then executing function `X` on it, while I could think of a plain `X()` as a static method call if I would like to project Javascript onto classical object oriented programming (Which I now understand to be a bad idea...). – ted Jul 16 '20 at 13:34
  • Is there a general rule of thumb when `new` should be used and when it is better to omit it, or is there no consense and one has to check for every class one wants to use? – ted Jul 16 '20 at 13:35
  • Well that's a good question. There are people with much stronger opinions about it than I maintain. Personally I *like* using `new` because I think it adds clarity. Lots of Java people *don't* like it for, well, reasons I don't really get. – Pointy Jul 16 '20 at 13:38
  • Also, the JavaScript world moves really fast compared with most other languages I'm familiar with. Attitudes change along with the language. – Pointy Jul 16 '20 at 13:39