firefox global variables woes

I

inigo.villalba

Hi,
I hope someone can point out my error because I'm starting to lose my
hair over this. It's probably a very straigh forward error but after
only 4 hours sleep it's doing my head in. It's to do with global
variables in Firefox 1.

The following code works no problems and generates a whole bunch of
numbers

<script type="text/javascript">


function createCal(){
var dateObj = new Date();


for(var i=0;i<32;i++){
date = dateObj.getDate();

set_date = dateObj.setDate(i);
document.write(date);

}

}
</script>

but when I try to place the dateObj variable outside the function (with
or without the preceding "var") it tells me dateObj is not defined.
Aren't variables declared outside of a function supposed to be global?
It all works fine in IE 5 btw

<script type="text/javascript">

var dateObj = new Date();
function createCal(){



for(var i=0;i<32;i++){
date = dateObj.getDate();

set_date = dateObj.setDate(i);
document.write(date);

}

}
</script>

Interestingly when I replace the document.write() with an alert
everything works as it should.

Thanks

barabis
 
L

Lee

(e-mail address removed) said:
but when I try to place the dateObj variable outside the function (with
or without the preceding "var") it tells me dateObj is not defined.
Aren't variables declared outside of a function supposed to be global?
It all works fine in IE 5 btw

<script type="text/javascript">

var dateObj = new Date();
function createCal(){



for(var i=0;i<32;i++){
date = dateObj.getDate();

set_date = dateObj.setDate(i);
document.write(date);

}

}
</script>

Interestingly when I replace the document.write() with an alert
everything works as it should.

It's a matter of how/when your function createCal() is being called.
If it's called after the page has been rendered, the first invocation
of document.write() clears the current page, destroying your global
variables.
 
B

barabis

It's funny that it doesnt affect IE. No wonder a lot of the dhtml calendars
don't work in firefox tho.
 
R

RobG

Hi,
I hope someone can point out my error because I'm starting to lose my
hair over this. It's probably a very straigh forward error but after
only 4 hours sleep it's doing my head in. It's to do with global
variables in Firefox 1.

No, it's what Lee said.

Manipulating strings is a lot faster than date objects. Have a
look at the code below, it generates dates for any month given a
year and month. It times methods using date objects and plain
string methods. On my ancient laptop, the date object method
consistently took 60 to 70ms, the string method took around 10ms.

I got the idea to try this from Dr. J's site where he compares
methods of validating user-entered date strings:

<URL:http://www.merlyn.demon.co.uk/js-date4.htm#TDVal>

Whilst the code is somewhat longer, the overall effect is a
3-fold increase in speed.


<script type="text/javascript">
function createCal0(sMonth){

var o = document.getElementById('writeSpan');
var m = sMonth.split(/\D+/);
m[1]--; // Adjust month number
var dateObj = new Date(m[0],m[1]);
var t; // Only used 'cos appendChild line was too long

while (m[1] == dateObj.getMonth()){
t = addZ(dateObj.getDate());
o.appendChild(document.createTextNode(t + ','));
dateObj.setDate(dateObj.getDate()+1)
}
}

function createCal1(sMonth){
var o = document.getElementById('writeSpan');
var m = sMonth.split(/\D+/);
var limit;
var ds = [];
if ( m[1]==4 || m[1]==6 || m[1]==9 || m[1]==10) {
limit = 30;
} else if (m[1]==1 || m[1]==3 || m[1]==5
|| m[1]==7 || m[1]==8 || m[1]==10 || m[1]==12){
limit = 31;
} else {
limit = 28;
if ( m[0]%4 == 0 ) limit = 29;
if ( m[0]%100 == 0 ) limit = 28;
if ( m[0]%400 == 0 ) limit = 29;
}
for (var i=1; i<=limit; i++) {
ds.push(addZ(i));
}
o.innerHTML = ds.join(',');
}

function addZ(x){
return (x<10)?'0'+x:x;
}
</script>
<form>
<input name="ym" value="2005-02">Enter a year
and month (yyyy-mm)<br>
<button onclick="
var s = new Date();
createCal0(this.form.ym.value);
var f = new Date();
var t = f - s;
alert('That took ' + t + ' ms');
return false;
">write dates 0</button>
<br>
<button onclick="
var s = new Date();
createCal1(this.form.ym.value);
var f = new Date()
var t = f - s;
alert('That took ' + t + ' ms');
return false;
">write dates 1</button>
<br>
</form>
<span id="writeSpan"></span>
 
L

Lee

barabis said:
It's funny that it doesnt affect IE. No wonder a lot of the dhtml calendars
don't work in firefox tho.

Yes. There is a lot of bad code out there.
 
D

Dr John Stockton

JRS: In article <420a2052$0$10200$5a62ac22@per-qv1-newsreader-
01.iinet.net.au>, dated Thu, 10 Feb 2005 00:33:22, seen in
news:comp.lang.javascript said:
function createCal1(sMonth){
var o = document.getElementById('writeSpan');
var m = sMonth.split(/\D+/);
var limit;
var ds = [];
if ( m[1]==4 || m[1]==6 || m[1]==9 || m[1]==10) {
limit = 30;
} else if (m[1]==1 || m[1]==3 || m[1]==5
|| m[1]==7 || m[1]==8 || m[1]==10 || m[1]==12){
limit = 31;
} else {
limit = 28;
if ( m[0]%4 == 0 ) limit = 29;
if ( m[0]%100 == 0 ) limit = 28;
if ( m[0]%400 == 0 ) limit = 29;
}
for (var i=1; i<=limit; i++) {
ds.push(addZ(i));
}
o.innerHTML = ds.join(',');
}


Probably quicker to declare var limit=31 and then overwrite it if
(Apr Jun Sep Nov) / Feb ; avoids 7 tests.

You have half-transferred a day from Oct to Nov - that is an Emperor-of-
Rome grade decision!

I'd try changing to M = m[1] ; ... if (M==4 || M==6 || ... to reduce
indexing.

To avoid all that pushing and joining, you could try a substring
operation on "01,02,03,04, ... ,31". Or start ds="01,02, ... ,28" .

Your Leap Year test tries all three divisors every time, which is
readily avoidable.

The month lengths can be computed, except for Feb, by adapting Zeller's
Congruence <URL:http://www.merlyn.demon.co.uk/zeller-c.htm>; or, for
Martin Honnen &c., <URL:http://www.merlyn.demon.co.uk/zel-86px.htm>.

Or global var ML = [31,0,31,30, ...,31]
and limit = ML[m[1]] ; if (!limit) limit = <28 or 29>.
 
R

RobG

Dr said:
JRS: In article <420a2052$0$10200$5a62ac22@per-qv1-newsreader-
01.iinet.net.au>, dated Thu, 10 Feb 2005 00:33:22, seen in
news:comp.lang.javascript said:
function createCal1(sMonth){
var o = document.getElementById('writeSpan');
var m = sMonth.split(/\D+/);
var limit;
var ds = [];
if ( m[1]==4 || m[1]==6 || m[1]==9 || m[1]==10) {
limit = 30;
} else if (m[1]==1 || m[1]==3 || m[1]==5
|| m[1]==7 || m[1]==8 || m[1]==10 || m[1]==12){
limit = 31;
} else {
limit = 28;
if ( m[0]%4 == 0 ) limit = 29;
if ( m[0]%100 == 0 ) limit = 28;
if ( m[0]%400 == 0 ) limit = 29;
}
for (var i=1; i<=limit; i++) {
ds.push(addZ(i));
}
o.innerHTML = ds.join(',');
}



Probably quicker to declare var limit=31 and then overwrite it if
(Apr Jun Sep Nov) / Feb ; avoids 7 tests.

You have half-transferred a day from Oct to Nov - that is an Emperor-of-
Rome grade decision!

I'd try changing to M = m[1] ; ... if (M==4 || M==6 || ... to reduce
indexing.

To avoid all that pushing and joining, you could try a substring
operation on "01,02,03,04, ... ,31". Or start ds="01,02, ... ,28" .

Your Leap Year test tries all three divisors every time, which is
readily avoidable.

The month lengths can be computed, except for Feb, by adapting Zeller's
Congruence <URL:http://www.merlyn.demon.co.uk/zeller-c.htm>; or, for
Martin Honnen &c., <URL:http://www.merlyn.demon.co.uk/zel-86px.htm>.

Or global var ML = [31,0,31,30, ...,31]
and limit = ML[m[1]] ; if (!limit) limit = <28 or 29>.

Great, thanks for the tips.

Given that Zeller's Congruence twisted my brain somewhat and
code should be maintainable (I'm not sure anyone reading that
stuff as code would understand it) and that the following
consistently ran in less than 15ms on page load and 0ms after
that, further optimisation is gilding the lilly.

I've used push to "top up" the days of the month rather than
create separate arrays for 28, 29, 30 & 31 day months.

It's noted however that Zeller's stuff for day-of-week looks
pretty handy.

function createCal1(sMonth){
var o = document.getElementById('writeSpan');
var m = sMonth.split(/\D+/);
var Y = m[0];
var M = m[1];
var limit = 31;
var MD = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,
18,19,20,21,22,23,24,25,26,27,28];

if ( M==4 || M==6 || M==9 || M==10) {
MD.push(29,30);
} else if (M == 2){
if ((Y%4==0 && Y%100!=0) || (Y%4==0 && Y%400==0)) {
MD.push(29);
}
} else {
MD.push(29,30,31);
}
o.innerHTML = MD.join(' ');
}
 
D

Dr John Stockton

JRS: In article <[email protected]>, dated Thu, 10
Feb 2005 06:56:57, seen in RobG
Dr John Stockton wrote:
Given that Zeller's Congruence twisted my brain somewhat and
code should be maintainable (I'm not sure anyone reading that
stuff as code would understand it) and that the following
consistently ran in less than 15ms on page load and 0ms after
that, further optimisation is gilding the lilly.

But the exercise helps develop skills.
I've used push to "top up" the days of the month rather than
create separate arrays for 28, 29, 30 & 31 day months.

It's noted however that Zeller's stuff for day-of-week looks
pretty handy.

I have empirically found the following way of calculating the lengths of
the months, except February; January must be entered as 13 :-

function GMLen() { var A = [], m
for (m=3; m<14; m++) A[m] = 30 + ((3*m+1)%5 < 3)
document.write(A) }

,,,31,30,31,30,31,31,30,31,30,31,31

Can it be improved?

It's worth remembering that wherever one has a sequence of integers that
maintains a non-integer average, something Zellerish can compute the
integers and/or their sum; and, the regrettable Augustan intervention
notwithstanding, the month-lengths Mar..Jan more or less do so.


else if (M == 2){
if ((Y%4==0 && Y%100!=0) || (Y%4==0 && Y%400==0)) {
MD.push(29);
}
}


else if (M == 2 && Y%4==0) {
if (Y%100!=0 || Y%400==0) {
MD.push(29);
}
} // <G>
 
R

rh

Dr said:
JRS: In article <[email protected]>, dated Thu, 10
Feb 2005 06:56:57, seen in RobG

I have empirically found the following way of calculating the lengths of
the months, except February; January must be entered as 13 :-

function GMLen() { var A = [], m
for (m=3; m<14; m++) A[m] = 30 + ((3*m+1)%5 < 3)
document.write(A) }

,,,31,30,31,30,31,31,30,31,30,31,31

Can it be improved?

Excluding February:

function GMLen2() { var A = [], m
for (var m=1; m<13; m++) A[m] = 30 | (m>>3^m);
document.write("<P>"+A) }

(with improvement by Richard Cornford).

Including February:

function GMLen3() { var A = [], m, y=2005
for (var m=1; m<13; m++) A[m] = 29 + (m>>3^m&1)
+ (m != 2 || -(y&3 || y&15 && !(y%25)));
document.write("<P>"+A) }

Leap year calculation courtesy of JRS/Gabor in this group.

Regards,

.../rh
 
M

Mick White

rh wrote:

[snip]
Including February:

function GMLen3() { var A = [], m, y=2005
for (var m=1; m<13; m++) A[m] = 29 + (m>>3^m&1)
+ (m != 2 || -(y&3 || y&15 && !(y%25)));
document.write("<P>"+A) }

Leap year calculation courtesy of JRS/Gabor in this group.


Why not hard code it?
function GMLen(m,yyyy){//m 0-11
return [31,yy%4==0?new
Date(yyyy,m+1,0).getDate():28,31,30,31,30,31,31,30,31,30,31][m]
}

Mick
 
R

rh

Mick said:
rh wrote:

[snip]
Including February:

function GMLen3() { var A = [], m, y=2005
for (var m=1; m<13; m++) A[m] = 29 + (m>>3^m&1)
+ (m != 2 || -(y&3 || y&15 && !(y%25)));
document.write("<P>"+A) }

Leap year calculation courtesy of JRS/Gabor in this group.


Why not hard code it?
function GMLen(m,yyyy){//m 0-11
return [31,yy%4==0?new
Date(yyyy,m+1,0).getDate():28,31,30,31,30,31,31,30,31,30,31][m]
}

First of all, what you've presented doesn't fit my definition of "hard
code". Secondly, it wouldn't appear to have been tested. And thirdly,
it doesn't account for leap years properly.

Implementation approaches are usually chosen based on taking into
account correctness, simplicity and efficiency. Often trade-offs in the
latter two are weighed in making a decision.

This is a case where efficiency happened to be predominant in the
choice, particularly given the context in which the response was made.

Moreover, it was coded to parallel the example given by JRS. Obviously
it would be structured differently if the intent was to produce a date
utilility.

Regards,

../rh
 
M

Mick White

rh said:
Mick said:
rh wrote:

[snip]
Including February:

function GMLen3() { var A = [], m, y=2005
for (var m=1; m<13; m++) A[m] = 29 + (m>>3^m&1)
+ (m != 2 || -(y&3 || y&15 &&
!(y%25)));
document.write("<P>"+A) }

Leap year calculation courtesy of JRS/Gabor in this group.


Why not hard code it?
function GMLen(m,yyyy){//m 0-11
return [31,yy%4==0?new
Date(yyyy,m+1,0).getDate():28,31,30,31,30,31,31,30,31,30,31][m]
}


First of all, what you've presented doesn't fit my definition of "hard
code". Secondly, it wouldn't appear to have been tested. And thirdly,
it doesn't account for leap years properly.

oops, typo:
function GMLen(m,yyyy){//m 0-11
return [31,yyyy%4==0?new
Date(yyyy,m+1,0).getDate():28,31,30,31,30,31,31,30,31,30,31][m]
}
Implementation approaches are usually chosen based on taking into
account correctness, simplicity and efficiency. Often trade-offs in the
latter two are weighed in making a decision.

This is a case where efficiency happened to be predominant in the
choice, particularly given the context in which the response was made.

Moreover, it was coded to parallel the example given by JRS. Obviously
it would be structured differently if the intent was to produce a date
utilility.

You're right, but you come off sounding a little pompous. My point is
that we need only to calculate February length since it is the only
month whose length varies, in that sense 11/12 may be hard coded.
Semantics.
Mick
 
R

rh

You're right, but you come off sounding a little pompous. My point is
that we need only to calculate February length since it is the only
month whose length varies, in that sense 11/12 may be hard coded.
Semantics.

Quite right, a more patient response would have been appropriate -- you
have my apology.

Regards,

../rh
 
M

Mick White

rh wrote:
[snip]
need only to calculate February length since it is the only
Quite right, a more patient response would have been appropriate -- you
have my apology.

No problem
y=2004
feblen=[28,29][+(new Date(y,1,29).getMonth()==1)]

Inspiration from Dr. JS (How appropriate)
Mick
 
R

rh

Mick said:
rh wrote:
[snip]
need only to calculate February length since it is the only
Quite right, a more patient response would have been appropriate -- you
have my apology.

No problem
y=2004
feblen=[28,29][+(new Date(y,1,29).getMonth()==1)]

<...>

Which is a fine example of how to get the most out of the built-in Date
function, but doesn't really pertain the earlier question posed by JRS
in this thread. Nor, necessarily did my response, as he may have been
looking for the possibility an algorithmic improvement, or a range
improvement, or both, to the example he provided.

Nonetheless, here's yet another predominantly bitwise-operation/logic
approach for m = 0..11, February included:

daysInMo = 28 | ( m^1 && ++m>>3^m|2 || !(y&3 || y&15 && !(y%25)) );

../rh
 
D

Dr John Stockton

JRS: In article <[email protected]>
, dated Thu, 10 Feb 2005 13:38:29, seen in rh
Mick White wrote:
Why not hard code it?
function GMLen(m,yyyy){//m 0-11
return [31,yy%4==0?new
Date(yyyy,m+1,0).getDate():28,31,30,31,30,31,31,30,31,30,31][m]
}
First of all, what you've presented doesn't fit my definition of "hard
code". Secondly, it wouldn't appear to have been tested. And thirdly,
it doesn't account for leap years properly.

It has a couple of missing 'y's; but, with that fixed, it handles
Gregorian leap year properly AFAICS.

This is a case where efficiency happened to be predominant in the
choice, particularly given the context in which the response was made.

ISTM that the above constructs a whole 12-element array whenever called,
including the calculation of an element not wanted 11 times out of 12.

In expression yyyy%4==0?new Date(yyyy,m+1,0).getDate():28 the %4 does
optimise 3 out of 4 years; but

Y%4 != 0 ? 28 : Y%100 !=0 ? 29 : Y%400 != 0 ? 28 : 29

seems easy enough and must be cheaper than a Date Object.


For aesthetic but presumably inefficient expressions,

28 + (y%4==0) ^ (y%100==0) ^ (y%400==0)
or 28 + (!(y%4)) ^ (!(y%100)) ^ (!(y%400))
or 28 | !(y%4)^!(y%100)^!(y%400)


But I was asking whether = 30 + ((3*m+1)%5 < 3) could be improved,
not whether any better routines existed; in other words, I was after
something generating the lengths arithmetically, as Zeller would.

That = 30 | (m>>3^m) is indeed good, covering 1,3-12 as it does.
 
D

Dr John Stockton

JRS: In article <[email protected]>, dated Fri, 11
Feb 2005 20:56:48, seen in Mick White
rh wrote:
[snip]
need only to calculate February length since it is the only
Quite right, a more patient response would have been appropriate -- you
have my apology.

No problem
y=2004
feblen=[28,29][+(new Date(y,1,29).getMonth()==1)]

feblen = new Date(y, 2, 0).getDate()

should beat that; moreover, it works for all values of 2.

It might not work in NS4, in which case

feblen = new Date(y, m+1, 1, -9).getDate()

could be better.
 
D

Dr John Stockton

JRS: In article <[email protected]>
, dated Thu, 10 Feb 2005 11:26:50, seen in rh
function GMLen3() { var A = [], m, y=2005
for (var m=1; m<13; m++) A[m] = 29 + (m>>3^m&1)
+ (m != 2 || -(y&3 || y&15 && !(y%25)));
document.write("<P>"+A) }

Gives 27 for Feb 2006.
 
R

rh

Dr said:
JRS: In article
, dated Thu, 10 Feb 2005 11:26:50, seen in rh
function GMLen3() { var A = [], m, y=2005
for (var m=1; m<13; m++) A[m] = 29 + (m>>3^m&1)
+ (m != 2 || -(y&3 || y&15 && !(y%25)));
document.write("<P>"+A) }

Gives 27 for Feb 2006.

And so it does. It appears that the coercion to Boolean got dropped
when introducing the subtraction. The continued line would better read:

+ (m != 2 || -!!(y&3 || y&15 && !(y%25)));

However, the expression I prefer is the subsequent, with range m=
0...11:

daysInMo = 28 | ( m^1 && ++m>>3^m|2 || !(y&3 || y&15 && !(y%25)) );

or for range m= 1...12:

daysInMo = 28 | ( m^2 && m>>3^m|2 || !(y&3 || y&15 && !(y%25)) );

which is leaves the % as the single dependence on direct arithimetic
operation.

By the way, you may also recall that Lasse provided a concise
expression that used a shift and mask in a pre-coded integer to
effectively do the lookup for the tail-length of non-February months.

<url:http://groups-beta.google.com/group..._frm/thread/ce9c9637ac5e2034/9f4c440664c393ff>

Regards,

../rh
 
D

Dr John Stockton

JRS: In article <[email protected]>,
dated Sat, 12 Feb 2005 18:06:26, seen in rh
However, the expression I prefer is the subsequent, with range m=
0...11:

daysInMo = 28 | ( m^1 && ++m>>3^m|2 || !(y&3 || y&15 && !(y%25)) );

or for range m= 1...12:

daysInMo = 28 | ( m^2 && m>>3^m|2 || !(y&3 || y&15 && !(y%25)) );

which is leaves the % as the single dependence on direct arithimetic
operation.


It would be more readable, and might be better, to work along the lines
of (/* ++ */ implies conversion of range 1..12 to 0..11)

daysInMo = /* ++ */ m==2 ? expression(y) : expression(m)

++m==2 ? 28 + !(y&3 || y&15 && !(y%25)) : 28 | m>>3^m|2 }
or 28 | ( ++m==2 ? !(y&3 || y&15 && !(y%25)) : m>>3^m|2 ) }

which seem slightly faster than

28 | ( m^1 && ++m>>3^m|2 || !(y&3 || y&15 && !(y%25)) )
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,432
Messages
2,571,680
Members
48,796
Latest member
Greg L.

Latest Threads

Top