Adding events in a loop with arguments

V

Vivek

Hello I am trying to attach events in my application. These events
have dynamically created parameters. I am attaching the code for a
simple app that demonstrates something similar to what i am trying to
achieve. I expect to see 1, 2 and 3 when i click on the links, however
all i see is 3, which is the final value for i. Can someone please
explain to me how to get around this issue. Thanks much

<html xmlns="http://www.w3.org/1999/xhtml" >
<head>
<title>js test page</title>
<script type="text/javascript">

function attachEvents()
{
var ahrefs = document.getElementsByTagName("a");
for(var i=0; i<ahrefs.length; i++)
ahrefs.onclick = function(){alert(i)};
}

onload = attachEvents;
</script>
</head>
<body>
This is a test page

</body>
<ul>
<li><a href="#">One</a></li>
<li><a href="#">Two</a></li>
<li><a href="#">Three</a></li>
</ul>
 
J

Jeff North

On Tue, 4 Dec 2007 20:13:45 -0800 (PST), in comp.lang.javascript Vivek
<[email protected]>
| Hello I am trying to attach events in my application. These events
| have dynamically created parameters. I am attaching the code for a
| simple app that demonstrates something similar to what i am trying to
| achieve. I expect to see 1, 2 and 3 when i click on the links, however
| all i see is 3, which is the final value for i. Can someone please
| explain to me how to get around this issue. Thanks much

This has to do with closures. This was a recent topic within this
group. Google the groups for the word closure.
| <html xmlns="http://www.w3.org/1999/xhtml" >
| <head>
| <title>js test page</title>
| <script type="text/javascript">
|
| function attachEvents()
| {
| var ahrefs = document.getElementsByTagName("a");
| for(var i=0; i<ahrefs.length; i++)
| ahrefs.onclick = function(){alert(i)};
| }
|
| onload = attachEvents;


Should be window.onload
| </script>
| </head>
| <body>
| This is a test page

No tags surrounding text
|
| </body>

End of document. The following lines are outside the close tag.
| <ul>
| <li><a href="#">One</a></li>
| <li><a href="#">Two</a></li>
| <li><a href="#">Three</a></li>
| </ul>

Here is a working (and more practical) demo of what you want.
http://www.jeffnorth.com/newsgroup/addEvent.htm
-- -------------------------------------------------------------
(e-mail address removed) : Remove your pants to reply
-- -------------------------------------------------------------
 
D

David Mark

Hello I am trying to attach events in my application. These events
have dynamically created parameters. I am attaching the code for a

You mean listeners that are defined as function expressions.
simple app that demonstrates something similar to what i am trying to
achieve. I expect to see 1, 2 and 3 when i click on the links, however
all i see is 3, which is the final value for i. Can someone please
explain to me how to get around this issue. Thanks much

<html xmlns="http://www.w3.org/1999/xhtml" >

This is hardly XHTML. It isn't even valid HTML.
<head>
<title>js test page</title>
<script type="text/javascript">

function attachEvents()
{
var ahrefs = document.getElementsByTagName("a");
for(var i=0; i<ahrefs.length; i++)
ahrefs.onclick = function(){alert(i)};


The fact that you expect this to work indicates that you don't
understand closures.

http://www.jibbering.com/faq/faq_notes/closures.html

[snip]

Read that article and then you should be able to tell why this one
works.

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/
TR/html4/strict.dtd">
<html>
<head>
<title>Test Page</title>
<script type="text/javascript">
var global = this;
if (this.document && this.document.getElementsByTagName && this.alert)
{
this.onload = function() {
var l;
var ahrefs = global.document.getElementsByTagName("a");
l = ahrefs.length;
while (l--) {
ahrefs[l].href = '#';
ahrefs[l].tabIndex = 0;
ahrefs[l].onclick = (function(j) { return function()
{ global.alert(j); return false; }; })(l + 1);
}
};
}
</script>
</head>
<body>
<h1>Test Page</h1>
<ul>
<li><a name="one">One</a></li>
<li><a name="two">Two</a></li>
<li><a name="three">Three</a></li>
</ul>
</body>
</html>
 
R

RobG

Hello I am trying to attach events in my application. These events
have dynamically created parameters. I am attaching the code for a

You mean listeners that are defined as function expressions.
simple app that demonstrates something similar to what i am trying to
achieve. I expect to see 1, 2 and 3 when i click on the links, however
all i see is 3, which is the final value for i. Can someone please
explain to me how to get around this issue. Thanks much

This is hardly XHTML. It isn't even valid HTML.
<head>
<title>js test page</title>
<script type="text/javascript">
function attachEvents()
{
var ahrefs = document.getElementsByTagName("a");
for(var i=0; i<ahrefs.length; i++)
ahrefs.onclick = function(){alert(i)};


The fact that you expect this to work indicates that you don't
understand closures.

http://www.jibbering.com/faq/faq_notes/closures.html
[...]
<script type="text/javascript">
var global = this;


Do you have any examples of where this is required or useful?

if (this.document && this.document.getElementsByTagName && this.alert)
{
this.onload = function() {

Why set "global" then not use it above?

var l;
var ahrefs = global.document.getElementsByTagName("a");
l = ahrefs.length;
while (l--) {
ahrefs[l].href = '#';
ahrefs[l].tabIndex = 0;
ahrefs[l].onclick = (function(j) { return function()
{ global.alert(j); return false; }; })(l + 1);

Wherever possible, assigning a function expression that forms a
circular reference should be avoided else IE's famous memory leak
becomes an issue. This particular form effectively breaks the closure
with i, but creates an additional execution object on the scope chain
that exacerbates the leak.

At least variables like ahrefs should be set to null or deleted.
Other methods that don't have memory leak problems are:

1. Use a function expression:

ahrefs[l].onclick = someFunction;


2. Assign the handler outside the scope of the main function like:

assignHandler(element, event, functionRef [, paramArray]);


3. Use the built-in Function object as a constructor:

ahrefs[1].onclick = new Function('...');
 
V

Vivek

You mean listeners that are defined as function expressions.
This is hardly XHTML. It isn't even valid HTML.
<head>
<title>js test page</title>
<script type="text/javascript">
function attachEvents()
{
var ahrefs = document.getElementsByTagName("a");
for(var i=0; i<ahrefs.length; i++)
ahrefs.onclick = function(){alert(i)};

The fact that you expect this to work indicates that you don't
understand closures.
http://www.jibbering.com/faq/faq_notes/closures.html
[...]
<script type="text/javascript">
var global = this;

Do you have any examples of where this is required or useful?
if (this.document && this.document.getElementsByTagName && this.alert)
{
this.onload = function() {

Why set "global" then not use it above?
var l;
var ahrefs = global.document.getElementsByTagName("a");
l = ahrefs.length;
while (l--) {
ahrefs[l].href = '#';
ahrefs[l].tabIndex = 0;
ahrefs[l].onclick = (function(j) { return function()
{ global.alert(j); return false; }; })(l + 1);

Wherever possible, assigning a function expression that forms a
circular reference should be avoided else IE's famous memory leak
becomes an issue. This particular form effectively breaks the closure
with i, but creates an additional execution object on the scope chain
that exacerbates the leak.

At least variables like ahrefs should be set to null or deleted.
Other methods that don't have memory leak problems are:

1. Use a function expression:

ahrefs[l].onclick = someFunction;

2. Assign the handler outside the scope of the main function like:

assignHandler(element, event, functionRef [, paramArray]);

3. Use the built-in Function object as a constructor:

ahrefs[1].onclick = new Function('...');


Thanks for your suggestions, I'll look into closures and of course
memory leak issues in IE. As suggested in 3 above, this is how it's
working now.
for (var i = 0; i < ahrefs.length; i++) {

ahrefs.onclick = new Function("alert('" + i + "');");

}
 
F

Fu Cheng

Hello I am trying to attach events in my application. These events
have dynamically created parameters. I am attaching the code for a
You mean listeners that are defined as function expressions.
simple app that demonstrates something similar to what i am trying to
achieve. I expect to see 1, 2 and 3 when i click on the links, however
all i see is 3, which is the final value for i. Can someone please
explain to me how to get around this issue. Thanks much
<html xmlns="http://www.w3.org/1999/xhtml" >
This is hardly XHTML. It isn't even valid HTML.
<head>
<title>js test page</title>
<script type="text/javascript">
function attachEvents()
{
var ahrefs = document.getElementsByTagName("a");
for(var i=0; i<ahrefs.length; i++)
ahrefs.onclick = function(){alert(i)};
The fact that you expect this to work indicates that you don't
understand closures.
http://www.jibbering.com/faq/faq_notes/closures.html
[...]
<script type="text/javascript">
var global = this;

Do you have any examples of where this is required or useful?
Why set "global" then not use it above?
var l;
var ahrefs = global.document.getElementsByTagName("a");
l = ahrefs.length;
while (l--) {
ahrefs[l].href = '#';
ahrefs[l].tabIndex = 0;
ahrefs[l].onclick = (function(j) { return function()
{ global.alert(j); return false; }; })(l + 1);
Wherever possible, assigning a function expression that forms a
circular reference should be avoided else IE's famous memory leak
becomes an issue. This particular form effectively breaks the closure
with i, but creates an additional execution object on the scope chain
that exacerbates the leak.
At least variables like ahrefs should be set to null or deleted.
Other methods that don't have memory leak problems are:
1. Use a function expression:
ahrefs[l].onclick = someFunction;
2. Assign the handler outside the scope of the main function like:
assignHandler(element, event, functionRef [, paramArray]);
3. Use the built-in Function object as a constructor:
ahrefs[1].onclick = new Function('...');

Thanks for your suggestions, I'll look into closures and of course
memory leak issues in IE. As suggested in 3 above, this is how it's
working now.
for (var i = 0; i < ahrefs.length; i++) {

ahrefs.onclick = new Function("alert('" + i + "');");

}



Using Function constructor is a bit slower, you should consider using
ahrefs.onclick = someFunc;
 
D

David Mark

You mean listeners that are defined as function expressions.
This is hardly XHTML. It isn't even valid HTML.
<head>
<title>js test page</title>
<script type="text/javascript">
function attachEvents()
{
var ahrefs = document.getElementsByTagName("a");
for(var i=0; i<ahrefs.length; i++)
ahrefs.onclick = function(){alert(i)};

The fact that you expect this to work indicates that you don't
understand closures.
http://www.jibbering.com/faq/faq_notes/closures.html
[...]
<script type="text/javascript">
var global = this;

Do you have any examples of where this is required or useful?


See below.
Why set "global" then not use it above?

It is used right there.
l = ahrefs.length;
while (l--) {
ahrefs[l].href = '#';
ahrefs[l].tabIndex = 0;
ahrefs[l].onclick = (function(j) { return function()
{ global.alert(j); return false; }; })(l + 1);

And there.
Wherever possible, assigning a function expression that forms a
circular reference should be avoided else IE's famous memory leak
becomes an issue. This particular form effectively breaks the closure
with i, but creates an additional execution object on the scope chain
that exacerbates the leak.

This can be avoided by setting ahrefs to null at the end. It was an
oversight that I left this out.
At least variables like ahrefs should be set to null or deleted.
Other methods that don't have memory leak problems are:

1. Use a function expression:

ahrefs[l].onclick = someFunction;

That wouldn't work in this case.
2. Assign the handler outside the scope of the main function like:

assignHandler(element, event, functionRef [, paramArray]);

Then you have to rely on Function.prototype.apply, which raises
compatibility issues.
3. Use the built-in Function object as a constructor:

ahrefs[1].onclick = new Function('...');

That is an alias for eval.
 
D

David Mark

You mean listeners that are defined as function expressions.
This is hardly XHTML. It isn't even valid HTML.
<head>
<title>js test page</title>
<script type="text/javascript">
function attachEvents()
{
var ahrefs = document.getElementsByTagName("a");
for(var i=0; i<ahrefs.length; i++)
ahrefs.onclick = function(){alert(i)};

The fact that you expect this to work indicates that you don't
understand closures.
http://www.jibbering.com/faq/faq_notes/closures.html
[...]
<script type="text/javascript">
var global = this;

Do you have any examples of where this is required or useful?


Perhaps this does need a more detailed explanation. The "global"
variable stores a reference to the global object. It isn't used in
the global context as it isn't needed (the "this" identifier works
fine there.) In this example, which uses a non-standard approach to
binding the load event listener, you could get away with using the
"this" identifier throughout. However, if you ever decide to switch
to a more standard approach, you will have a problem. Consider this
variation:

var global = this;
if (this.document && this.document.getElementsByTagName && this.alert
&& this.addEventListener) {
this.addEventListener('load', function() {
var l;
var ahrefs = global.document.getElementsByTagName("a");
l = ahrefs.length;
while (l--) {
ahrefs[l].href = '#';
ahrefs[l].tabIndex = 0;
ahrefs[l].onclick = (function(j) { return function()
{ global.alert(j); return false; }; })(l + 1);
}
ahrefs = null; // Added to break circular reference
}, false);
}

Here you need to have a reference to the global object as the "this"
identifier in the listener's context will not necessarily refer to the
global object. In some standards-based browsers (e.g. Opera 9),
adding a listener to the global object will actually bind it to the
document node. This makes sense as the global object is not part of
the DOM. So unless a reference to the global object is available to
the listener (e.g. the "global" variable), there is no reliable way
for it to reference the global object. Often scripts will simply
refer to the global window property (e.g. window.alert(j)), which
typically refers back to the global object, but it is a bad idea to
assume such a property exists.

Why attach listeners to the global object at all if it is not part of
the standard DOM? I have always done it that way and have tested it
successfully in a wide variety of agents. Clearly there are limited
choices for scripts that reside in the head of the document.
Technically this would be less ambiguous:

var global = this;
if (this.document && this.document.getElementsByTagName && this.alert
&& this.document.addEventListener) {
this.document.addEventListener('load', function() {
var l;
var ahrefs = global.document.getElementsByTagName("a");
l = ahrefs.length;
while (l--) {
ahrefs[l].href = '#';
ahrefs[l].tabIndex = 0;
ahrefs[l].onclick = (function(j) { return function()
{ global.alert(j); return false; }; })(l + 1);
}
ahrefs = null;
}, false);
}

In that version, you should only need to reference the "global"
variable in the alert call as "this" should always refer to the
document node. I wouldn't assume anything about how this version
might behave as I have tested it in only a handful of modern browsers.

Then there are those who favor the inline method:

<body onload="init();">

In this case, you still need the "global" variable as "this" will
refer to the body element in the inline handler. And of course, you
need to introduce a second global property (init function) to house
the logic that previously resided in the anonymous listener. This
method introduces other maintenance headaches, but that is another
topic.
 
T

Thomas 'PointedEars' Lahn

RobG said:
Do you have any examples of where this is required or useful?

var _global = this;
var foo = 42;

function bar()
{
var foo = null;
return _global["foo"];
}

I use _global frequently in my code. It avoids the error-prone proprietary
`window' approach.
Why set "global" then not use it above?

Because the Global Object should be a built-in object, and `window' should
be a reference to a host object. It does not make sense and is error-prone
to use `this' like `window', though.
1. Use a function expression:

ahrefs[l].onclick = someFunction;

Provided `someFunction' is an identifier, that is _not_ a function
expression. It is a simple assignment expression instead.


PointedEars
 
D

David Mark

Do you have any examples of where this is required or useful?

var _global = this;
var foo = 42;

function bar()
{
var foo = null;
return _global["foo"];
}

I use _global frequently in my code. It avoids the error-prone proprietary
`window' approach.
Why set "global" then not use it above?

Because the Global Object should be a built-in object, and `window' should
be a reference to a host object. It does not make sense and is error-prone
to use `this' like `window', though.

Define using 'this' like 'window'. In browsers the global window
property refers to the global object by convention, so in a global
context using the "this" identifier makes perfect sense.
Alternatively, you could use this.window, but that would be redundant.
1. Use a function expression:
ahrefs[l].onclick = someFunction;

Provided `someFunction' is an identifier, that is _not_ a function
expression. It is a simple assignment expression instead.

PointedEars
 
R

RobG

It is used right there.

Which is below where I asked the question about the code above.

l = ahrefs.length;
while (l--) {
ahrefs[l].href = '#';
ahrefs[l].tabIndex = 0;
ahrefs[l].onclick = (function(j) { return function()
{ global.alert(j); return false; }; })(l + 1);

And there.


Wherever possible, assigning a function expression that forms a
circular reference should be avoided else IE's famous memory leak
becomes an issue. This particular form effectively breaks the closure
with i, but creates an additional execution object on the scope chain
that exacerbates the leak.

This can be avoided by setting ahrefs to null at the end. It was an
oversight that I left this out.

It breaks the cirulcar reference (and hence a common cause of memory
leaks) but not the closure that each function expression assigned as
a handler forms with the enclosing function - therefore a potential
source of leaks remains.

It may be significant or not, it depends on the particular case.
At least variables like ahrefs should be set to null or deleted.
Other methods that don't have memory leak problems are:
1. Use a function expression:
ahrefs[l].onclick = someFunction;

That wouldn't work in this case.

It is an alternative method of attaching a handler that doesn't have
memory leak issues and doesn't form a closure.

2. Assign the handler outside the scope of the main function like:
assignHandler(element, event, functionRef [, paramArray]);

Then you have to rely on Function.prototype.apply,

Not necessarily, the OP's example does not require it so "it's not an
issue in this case". :)

which raises compatibility issues.

Only if call or apply are required and are not supported by the host,
but that can be solved anyway by conditionally assigning an
appropriate function to the Function.prototype.call and apply
properties.

<URL:
http://groups.google.com.au/group/c...&lnk=gst&q=winter+apply+call#22e0f921fe3043d0
3. Use the built-in Function object as a constructor:
ahrefs[1].onclick = new Function('...');

That is an alias for eval.

The use of eval is not necessarily evil, using the built-in Function
object as a constructor is perfectly reasonable, though I'm not
suggesting it is always (or even often) the best approach.

In cases where the function body is simple and small, it makes a lot
of sense to use it.
 
D

David Mark

Which is below where I asked the question about the code above.

It was unclear to me what you were after. I posted a more detailed
explanation later.
l = ahrefs.length;
while (l--) {
ahrefs[l].href = '#';
ahrefs[l].tabIndex = 0;
ahrefs[l].onclick = (function(j) { return function()
{ global.alert(j); return false; }; })(l + 1);
And there.
This can be avoided by setting ahrefs to null at the end. It was an
oversight that I left this out.

It breaks the cirulcar reference (and hence a common cause of memory
leaks) but not the closure that each function expression assigned as

Of course it doesn't "break" the closure. I don't know what that
means and the closures are necessary for the example.
a handler forms with the enclosing function - therefore a potential
source of leaks remains.

I don't see that at all. Closures are not inherently leaky. That is
a myth that was spread by Microsoft because they didn't understand why
their own code leaked.
It may be significant or not, it depends on the particular case.

The case that is significant is when a circular reference is created,
involving a DOM element or ActiveX object. That's why I added the
extra line to stop that case from occurring.
At least variables like ahrefs should be set to null or deleted.
Other methods that don't have memory leak problems are:
1. Use a function expression:
ahrefs[l].onclick = someFunction;
That wouldn't work in this case.

It is an alternative method of attaching a handler that doesn't have
memory leak issues and doesn't form a closure.
Yes.
2. Assign the handler outside the scope of the main function like:
assignHandler(element, event, functionRef [, paramArray]);
Then you have to rely on Function.prototype.apply,

Not necessarily, the OP's example does not require it so "it's not an
issue in this case". :)

I don't know what you mean. Do you have an example of this
hypothetical assignHandler function that handles arguments (as the OP
requires) and does not use use call or apply?
Only if call or apply are required and are not supported by the host,

Those are the issues.
but that can be solved anyway by conditionally assigning an
appropriate function to the Function.prototype.call and apply
properties.

A function to do what?

I glanced at that briefly. Looks like a mess to me.
3. Use the built-in Function object as a constructor:
ahrefs[1].onclick = new Function('...');
That is an alias for eval.

The use of eval is not necessarily evil, using the built-in Function

Obviously not. There are some rare cases where it is unavoidable and
appropriate.
object as a constructor is perfectly reasonable, though I'm not
suggesting it is always (or even often) the best approach.

All I am suggesting is that it would not be appropriate to use for
code like this example. It is too slow.
In cases where the function body is simple and small, it makes a lot
of sense to use it.

I can think of only one time I have ever used it and it was an odd
case indeed.
 
T

Thomas 'PointedEars' Lahn

David said:
Define using 'this' like 'window'.

Using `this' to access a property of the object that `window' refers to.
In browsers the global window property refers to the global object
by convention,
Wrong.

so in a global context using the "this" identifier makes perfect sense.

Non sequitur.
Alternatively, you could use this.window, but that would be redundant.

`this.window' would not be redundant but a qualified and valid reference for
the object `window' refers to. `window' is implemented as a host-defined
property of the Global Object in many HTML UAs, as mentioned in (but not
specified by) the ECMAScript Specification.

Please trim your quotes.


PointedEars
 
D

David Mark

Using `this' to access a property of the object that `window' refers to.

As "this" in the global context refers to the global object and the
window property (if present) refers to the same object (in browsers),
it makes perfect sense.

I disagree. Can you give an example of one browser where it doesn't.
Non sequitur.


`this.window' would not be redundant but a qualified and valid reference for
the object `window' refers to. `window' is implemented as a host-defined

Which is the global object in browsers.
property of the Global Object in many HTML UAs, as mentioned in (but not
specified by) the ECMAScript Specification.

And in what HTML UA does it not refer to the global object? If you
can come up with one, perhaps I will re-think this, but otherwise it
seems like defining another global variable set to this.window would
be needless clutter.
Please trim your quotes.

PointedEars
--

Please fix your signature.
 
V

VK

Using Function constructor is a bit slower, you should consider using
ahrefs.onclick = someFunc;


Function constructor is almost always quicker - by fractions - on IE
and random slower/quicker by fractions on Gecko.

The rumor that functions over Function constructor are slower is an
ancient city legend based on the idea that function(){} creates an
object in the memory while Function gets stored as a string and being
eval(uated) on each invocation. I once tried to find the original
source of the legend and it seems it is originated from the first
JScript Help for IE 3.0 Even if it ever was true for IE3.0 it is not
anymore for the longest time now: at least starting from NN4/IE4


<html>
<head>
<title>Untitled Document</title>
<meta http-equiv="Content-Type"
content="text/html; charset=iso-8859-1">
<script>
function f1(n) {
for (var i=0;i<n;i++) {
new Date;
}
}

var f2 = new Function('n','for (var i=0;i<50000;i++) {new Date;}');


function test() {
var t = (new Date).getTime();
f1(50000);
window.alert((new Date).getTime() - t);
t = (new Date).getTime();
f2(50000);
window.alert((new Date).getTime() - t);
}

window.onload = test;
</script>
</head>
<body>
</body>
</html>
 
D

David Mark

Using Function constructor is a bit slower, you should consider using
ahrefs.onclick = someFunc;


Function constructor is almost always quicker - by fractions - on IE
and random slower/quicker by fractions on Gecko.


I can't confirm that, but it sounds wrong to me. The Function
constructor evaluates code, so for most functions it would likely be
slower than using a function expression.
The rumor that functions over Function constructor are slower is an

It is not a rumor.
ancient city legend based on the idea that function(){} creates an

A what?
object in the memory while Function gets stored as a string and being
eval(uated) on each invocation. I once tried to find the original

That's not how I understand it. I would think that the string is
evaluated once on assignment.
source of the legend and it seems it is originated from the first
JScript Help for IE 3.0 Even if it ever was true for IE3.0 it is not

That's an odd attribution. It seems like common sense to me.
anymore for the longest time now: at least starting from NN4/IE4

What common change occurred with the release of those two (and very
different) browsers?
<html>
<head>
<title>Untitled Document</title>
<meta http-equiv="Content-Type"
content="text/html; charset=iso-8859-1">
<script>
function f1(n) {
for (var i=0;i<n;i++) {
new Date;
}

}

var f2 = new Function('n','for (var i=0;i<50000;i++) {new Date;}');

function test() {
var t = (new Date).getTime();
f1(50000);
window.alert((new Date).getTime() - t);
t = (new Date).getTime();
f2(50000);
window.alert((new Date).getTime() - t);

}

window.onload = test;
</script>
</head>
<body>
</body>
</html>

This test indicates that I wasted my time reading what came before
it. You don't understand the issue.
 
T

Thomas 'PointedEars' Lahn

David said:
As "this" in the global context refers to the global object and the
window property (if present) refers to the same object (in browsers),
it makes perfect sense.

That is an assumption, not a fact.
I disagree. Can you give an example of one browser where it doesn't.

I have no intention of helping you to shift the burden of proof.


PointedEars
 
D

David Mark

That is an assumption, not a fact.



I have no intention of helping you to shift the burden of proof.

Well, if what you are implying were true, then code like this would
fail with an error:

if (document & document.getElementById && alert) { alert('test'); }

That's pretty conventional code and a browser developer would be
unwise to flout such convention.

I wouldn't write it quite that way. More like:

if (this.document && this.document.getElementById && this.alert)
{ this.alert('test'); }

Granted, that would not alert anything in your hypothetical user
agent, but at least it wouldn't error.

I suppose you advocate:

if (this.window.document && this.window.document.getElementById &&
this.window.alert) { this.window.alert('test'); }

I just can't picture a user agent where that would work any
differently than my version (i.e. they would both alert "test.")

There is no way I can prove my theory short of testing every user
agent in every possible configuration. You could easily disprove it
by naming just one agent and one configuration. It would make sense
to shift the burden of proof in this case. Otherwise, I guess the
court of public opinion will have to decide it. Anybody out there
agree with PointedEars on this one? I think it will save time if just
those people step forward.
 
R

RobG

David said:
Which is below where I asked the question about the code above.

It was unclear to me what you were after. I posted a more detailed
explanation later.
l = ahrefs.length;
while (l--) {
ahrefs[l].href = '#';
ahrefs[l].tabIndex = 0;
ahrefs[l].onclick = (function(j) { return function()
{ global.alert(j); return false; }; })(l + 1);
And there.
Wherever possible, assigning a function expression that forms a
circular reference should be avoided else IE's famous memory leak
becomes an issue. This particular form effectively breaks the closure
with i, but creates an additional execution object on the scope chain
that exacerbates the leak.
This can be avoided by setting ahrefs to null at the end. It was an
oversight that I left this out.
It breaks the cirulcar reference (and hence a common cause of memory
leaks) but not the closure that each function expression assigned as

Of course it doesn't "break" the closure. I don't know what that
means and the closures are necessary for the example.

No, they aren't. In fact breaking the closure to i is what this thread
is all about. The closure with the outer function is a by-product of
the function expression assignment and is a bit of a nuisance here.
I don't see that at all. Closures are not inherently leaky. That is
a myth that was spread by Microsoft because they didn't understand why
their own code leaked.

The closure makes the circular reference possible, so it's good to not
create them if they aren't needed. That doesn't mean to say they are
inherently bad, just that the OP should be aware.

[...]
2. Assign the handler outside the scope of the main function like:
assignHandler(element, event, functionRef [, paramArray]);
Then you have to rely on Function.prototype.apply,
Not necessarily, the OP's example does not require it so "it's not an
issue in this case". :)

I don't know what you mean. Do you have an example of this
hypothetical assignHandler function that handles arguments (as the OP
requires) and does not use use call or apply?

I'm sure you can do it, but that you are currently thinking of a general
function that will handle every case. If there is no need to set the
handler's this keyword to the element, and if you know how many
arguments will be called, then something like the following suits (it
will only work in browsers that support addEventListener, but could
easily accommodate attachEvent also):

<div>
<button id="b0">Button 0</button>
<button id="b1">Button 1</button>
</div>
<script type="text/javascript">

function showArg(id, i){
alert('Button ' + id + ': ' + i);
}

function assignHandler(el, event, fn, arg0, arg1) {
if (el && el.addEventListener) {
el.addEventListener(event,
function(){fn(arg0, arg1)},
false);
}
el = null;
}

(function() {
var button;
var buttons = document.getElementsByTagName('button');
for (var i=0, len=buttons.length; i<len; i++) {
button = buttons;
assignHandler(button, 'click', showArg, button.id, i);
}
button = null;
buttons = null;
})();

</script>


Now if that were to be a general function, it would need to consider
attachEvent and also probably use call or apply to both set the called
function's this keyword and to pass an unknown number of arguments.

But the OP's case doesn't require it, so such a general function isn't
necessary.

Those are the issues.


A function to do what?


I glanced at that briefly. Looks like a mess to me.

I think Mike would agree, his intention was to show that for the very
small number of browsers in use that require it, it can be done.

3. Use the built-in Function object as a constructor:
ahrefs[1].onclick = new Function('...');
That is an alias for eval.
The use of eval is not necessarily evil, using the built-in Function

Obviously not. There are some rare cases where it is unavoidable and
appropriate.
object as a constructor is perfectly reasonable, though I'm not
suggesting it is always (or even often) the best approach.

All I am suggesting is that it would not be appropriate to use for
code like this example. It is too slow.

It may not be appropriate for many reasons, but I doubt that speed is
one of them.
 
V

VK

It is not a rumor.

a rumor - "a story or statement in general circulation without
confirmation or certainty as to facts"

Exactly what it is in relevance to Function constructor.

Think of "rumor" as explained above but with more stress on "not
true": though let's skip on this local vernacular expression, "a
rumor" will suffice.
I would think that the string is
evaluated once on assignment.

Once on executing the relevant assignment statement to be exact. It is
not what most people thinks though when opposing to Function(...)
usage - I am glad that you are not one of them.
at least starting from NN4/IE4

What common change occurred with the release of those two (and very
different) browsers?

Runtime execution cache - what is also called JIT in Java - was
totally rebuilt and improved.

This test indicates that I wasted my time reading what came before
it. You don't understand the issue.

Then you might explain it better. For me the advantages/disadvantages
from the productivity point of view are:

1) Slower on instantiation: so say assignment
var foo1 = function(m){window.alert(m);};
as always and noticeable quicker then
var foo2 = new Function('m', 'window.alert(m)');

2) Slower on invocation: so say
foo1('Hello!');
is always and noticeable quicker then
foo2('Hello!');

Neither of above are true so what is the 3rd issue you are concerned
about?
 

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

Forum statistics

Threads
473,995
Messages
2,570,230
Members
46,817
Latest member
DicWeils

Latest Threads

Top