javascript "with" structure produce undefined vars - javascript

I have an object called totalRevenue which is responsible for storing stacked revenue of company on a monthly basis.
var totalRevenue = {
jan : 147,
feb : 290,
mar : 400
};
Not all month names are present in totalRevenue object & they are created dynamically when populating/estimating their respective values.
In the beginning of every month, we estimate revenue of that month using an algorithm. sth like this:
with(totalRevenue){
mar = mar - feb; // here we calculate pure mar revenue
feb = feb - jan; // here we calculate pure feb revenue
apr = mar - feb; // this is part one of the algo.
}
(I'm using with construct to avoid repetition.)
Now I'm using totalRevenue.apr for the rest of algo computations. But after some challenge, I got that totalRevenue.apr = undefined !!
Does anyone know why?! As I expected it to have a value equal to mar - feb.

If apr isn't a property of totalRevenue then it's not brought into scope by with and your code will create a new global named apr. There would be no way for the interpreter to know if a given name refers to a global or was intended to refer to a heretofore undefined property of the nearest with block so the assumption is it's a global. You can either ensure that totalRevenue has a property for every month or avoid using the with statement entirely. Using with is discouraged MDN has this to say:
Use of the with statement is not recommended, as it may be the source of confusing bugs and compatibility issues. See the "Ambiguity Contra" paragraph in the "Description" section below for details.

Related

Javascript - Why time in ISO8601 format shows in 2 different formats at console.log?

I have date in ISO8601 format, e.g. '2021-01-01T00:00:00.000Z'. I try console.log it as part of string and as variable - I get two different results:
2021-01-01T00:00:00.000Z - when I show it as variable
Fri Jan 01 2021 01:00:00 GMT+0100 (Central European Standard Time) - when I show it as part of string
How could I show date in ISO8601 format '2021-01-01T00:00:00.000Z' as part of string?
let date = new Date(2021, 0, (1 + (1 - 1) * 7), 1);
console.log('Show as variable: ', date);
console.log(`Show as part of string: ${date}`);
edited: set proper date format.
My guess is that it depends on each runtime's implementation of console.log. The template literal (your second example) would do the interpolation of the template before passing the whole thing to console.log, hence it will be a string already when logging (and it would use the same value as date.toString()), whereas the first variant passes a string literal and then an object, which isn't necessarily a string as well (and it's up to the console to decide how to display it; think of how you usually have more convenient display options for arrays, objects and so on).
Chrome seems to not care and shows both variants the same, whereas Firefox shows the first one as a Date instance. Node's CLI kind of behaves like Firefox and shows them differently, but doesn't show that the type is Date.

Converting moment.js to JSON shows incorrect time

I have a method which sets the created property of my token, like so:
const token = new Token();
console.log(moment().toDate());
token.created = moment().toDate().toJSON();
There's something I just can't get my head around and it's really confusing me.
The line console.log(moment().toDate()); prints Tue Sep 01 2020 14:11:39 GMT+0100 but when I check the property created on debugger although it's using the same moment object and methods (except from calling toJSON()) it produces a date time which is an hour behind like so: 2020-09-01T13:11:39.179Z
I store the moment date as a string in the created property because this will be stored in localStorage.
Does anyone know the reason for this?
The times are the same. Look closely.
One marks the time zone as Z, the other as GMT+1.
Those time zones are 1 hour apart.
You can specify the time zone

Javascript dates: a nightmare

I understand that dealing with dates, in any environment, could be quite confusing, but I'm in a nightmare with a function that should be a trivial job.
I want to manipulate in different ways some dates, but I get errors or wrong results.
I report hereafter a very simple example made to test the execution; the goal here is to get the current month beginning date, just to show what happens:
function DateAdjust() {
var newdate = new Date(); //1: 2018-12-12T21:00:20.099Z
newdate = newdate.setDate(1); //2: 1543698020099
newdate=Date(newdate); //3: Wed Dec 12 2018 21:01:43 GMT+0000 (Ora standard dell’Europa occidentale)
var d = newdate.getDate(); //4: newdate.getDate is not a function
}
4 lines, 3 unexpected results (as shown by Firefox's debugger):
1. the starting date has no day-of-week and no timezone
2. setting the day, result is transformed in milliseconds (why?); I do not know if it is correct.
3. reconverting in string gives the original date, unmodified (why?) but with week day and timezone
4. trying to get the day value an error is thrown (why?)
My environment:
Win 7 32bits SP1
Firefox 63.0.3 (32 bit)
jquery-2.2.4.min.js
I know these questions are boring, but hope someone will find few minutes to clear my mind.
Regarding line 1, the Z at the end is the timezone designation for UTC in ISO 8601 (see Wikipedia).
If the time is in UTC, add a Z directly after the time without a space. Z is the zone designator for the zero UTC offset. "09:30 UTC" is therefore represented as "09:30Z" or "0930Z". "14:45:15 UTC" would be "14:45:15Z" or "144515Z".
Regarding line 2 see the MDN article on setDate (emphasis mine):
The number of milliseconds between 1 January 1970 00:00:00 UTC and the given date (the Date object is also changed in place).
So you can see the 'correct' behavior you probably expect simply by ignoring the return value:
var newdate = new Date(); //1: 2018-12-12T21:00:20.099Z
newdate.setDate(1); //2: 1543698020099
console.log(newdate); //3: 2018-12-01T21:00:20.099Z
Regarding line 3, see MDN article on Date (emphasis mine):
Note: JavaScript Date objects can only be instantiated by calling
JavaScript Date as a constructor: calling it as a regular function
(i.e. without the new operator) will return a string rather than a
Date object; unlike other JavaScript object types, JavaScript Date
objects have no literal syntax.
Regarding line 4, the above also explains this error, since newdate is now a string rather than a Date object.
For what it's worth, I agree with the other commenters. JavaScript's date functions are pretty messy compared to many other modern languages. I strongly recommend using a library like moment, luxon, or date-fns. It'll make your life much easier.
I do recommend using moment.js
But there are 2 problems with your code:
1-
newdate = newdate.setDate(1);
setDate mutates newDate in place, and return it in miliseconds, not a new Date object. If you just want to set the date, do this instead:
newdate.setDate(1);
2-
newdate=Date(newdate);
Not realy sure why you are trying to get a new Date object, but you need the new, otherwise it will just be a string
newdate= new Date(newdate);
Fixing problem 1 should eliminate the need for the code of problem 2
var newdate = new Date(); // 1
console.log(typeof newdate, newdate); // object Wed Dec 12 2018 23:00:44 GMT+0200 (Eastern European Standard Time)
newdate = newdate.setDate(1); // 2
console.log(typeof newdate, newdate); //number 1543698085383
newdate=Date(newdate); //3
console.log(typeof newdate, newdate); //string Wed Dec 12 2018 23:04:44 GMT+0200 (Eastern European Standard Time)
var d = newdate.getDate(); // 4
console.log(typeof d, d); //
Date type is assigned to the object.
number is assigned to newdate. which is ticks
returns string
string.getDate() is not defined, so undefined.
hope it helps.

Moment JS initialisation and the utc() method

I would like to understand Moment JS' initialisation of its moment object.
For example, if I would like to create a moment for the date and time:
April 1 2000, 3:25:00 am with utc offset of +8 hours from UTC/GMT.
I represent this in a javascript object:
var obj = {
year: 2000,
month: 4, //APRIL
day: 1,
hour: 3,
minute: 25,
second: 0,
utcOffset: 8 //8 hours from UTC
}
I then create a handy function I can use to create a moment with moment js:
var makemoment = function(obj){
var m = moment([obj.year, obj.month - 1, obj.day, obj.hour, obj.minute, obj.second, 0]).utcOffset(obj.utcOffset);
return m;
}
When I use this function to create moment...
e.g.
var result = moment(obj);
If I inspect the result object above I can see that it has a property _d
that I expect to have a value such as:
_d Date {Sat Apr 01 2000 03:25:00 GMT+0800 (HKT)}
But the actual value is which for me does not make sense since I specified that the time is 3:25:00 and it is already at GMT +0800 so no need to add 8 hours to the time....
_d Date {Sat Apr 01 2000 11:25:00 GMT+0800 (HKT)}
Despite of this _d value though, if I console.log(result)
I get the correct expected date:
2000-04-01T03:25:00+08:00
If I call the utc method on the moment. e.g. result.utc()
and if I inspect the object again, I can see that now the _d has changed to my originally expected value:
_d Date {Sat Apr 01 2000 03:25:00 GMT+0800 (HKT)}
However, now if I do result.format()
I get the correct UTC date and time:
2000-03-31T19:25:00+00:00
Am I not understanding something here????
How is the _d value used in Moment.js???
Should I ignore the _d value since it is just something internal to Moment.js???
I've created JSFiddle for to illustrate my point...
http://jsfiddle.net/nx2ch4ot/2/
A few things:
It's a common convention in JavaScript that fields of an object that are prefixed by an underscore are meant to be treated as private/internal and not used directly. Though it may be more user-friendly to hide them via closures, it's also slower, and thus libraries like moment.js choose to leave them exposed.
Instead of using _d, call a public function such as .format(), or any of the others shown in the documentation.
If you really want to know more about _d, take a look at this answer.
The time zone shown in a Date object will always be relative to the computer where the code is running. JavaScript's Date object doesn't have the ability to reflect other time zones. When moment uses _d, it mostly uses it just for its instantaneous value given by _d.getTime(), which reflects only UTC. (We're actually considering removing _d entirely in a future version.)
You do indeed need to adjust for the offset, but you should be starting from moment.utc instead of local time. The corrected function is:
var makemoment = function(obj){
var m = moment.utc([obj.year, obj.month - 1, obj.day, obj.hour, obj.minute, obj.second, 0]);
m.subtract(obj.utcOffset, 'hours');
m.utcOffset(obj.utcOffset);
return m;
}
The function you wrote is very similar to the one already built in to moment. You can pass an object to either moment or moment.utc. The difference with yours is that moment's uses zero-based months, and doesn't yet support passing a utcOffset field. You might just consider using that instead.
var makemoment = function(obj){
obj.month--; // switch to zero-based months
var m = moment.utc(obj);
obj.month++; // put it back
m.subtract(obj.utcOffset, 'hours');
m.utcOffset(obj.utcOffset);
return m;
}

Updating the date portion of a javascript object without changing the time portion

What is the best way in JavaScript to set the date portion of a JavaScript date object without affecting the time portion?
Lets say you have a date like this
Wed Oct 31 2012 10:15:00 GMT-0400 (EDT)
And you want to update it to be November 1st without changing the time.
At first glance, you'd think this would work,
exampledate.setFullYear(2012);
exampledate.setMonth(10);
exampledate.setDate(1);
But the result is
Sat Dec 01 2012 10:15:00 GMT-0500 (EST)
I think reason for this is that October has 31 days and November has just 30. Since this obviously doesn't work right all the time. What are my other options? Will I have to create a new date object?
JavaScript Date object setter methods often allow you to (optionally) set multiple date/time components all at once (in addition to the primary component), as appropriate for the situation --- this is what you want to do.
For your use case, the syntax for setFullYear is setFullYear(year,month,day), so in addition to explicitly setting the year (which would cause the month and date to be implicitly updated based on your initial date), you could also explicitly set the month and day while you're at it. For instance:
var d = new Date();
d.setFullYear(2020,10,3);
will return
Tue Nov 03 2020 13:10:34 GMT-0500 (EST)
See the JavaScript setFullYear() method for more details.
Because the time components of the Date object (e.g. hours, minutes, seconds, milliseconds) are not dependent on the date portions (year,month,date), your initial time components will be maintained. If you need to then update the time components, you can safely use setHours() or other methods as needed, because no implicit updates to the date components will occur.
First set the date, then the month.

Categories

Resources