It doesn't matter. One is enough.
Ok, there's no need to critique my choice libraries.
You would do well to listen. It's not just the odd $ function that I
dislike about it. The fact is that the code throughout is of very
poor quality.
Thanks. The same
would apply if I had said:
this.myfield = document.getElementById('id_myfield');
But that's totally different as gEBI returns a host object reference.
The jQuery thing returns an Object object. See how using a library at
a point where you don't understand the basics can be confusing? Along
the same lines, you are likely not ready to judge the quality (or lack
thereof) of the libraries either.
Because of closures the clickHandler scope keeps the this.myfile in
context.
You are confused. The - this - keyword is not part of the scope
chain. There is no reference to a host object in the scope of your
listener function and furthermore, the library is unlikely to attach
that function as the listener (more likely it wraps it, but again
there's no telling without delving into jQuery). Until you understand
these concepts, libraries will just make such potential issues harder
to spot.
Of course I just realized that the 'this' keyword would be
overridden in the actual call of the click event.
Very likely it will reference the element, but that doesn't matter.
When the event is
called 'this' will be the myfield instance.
There are no instances in JS and "myfield" is the name of a property
of your constructed object, which references another Object object
(not a host object). That's if you are using jQuery. If it is
Prototype or MooTools, it will reference a host object, but it still
won't matter as the - this - keyword is not part of the scope chain.
The following is a better
example:
function Widget(){
var myfield = $('#id_myfield');
var clickHandler = function(event){ //do something };
myfield.bind('click', clickHandler);
}
Here the myfield DOM object has a circular reference to itself via the
myfield variable.
If the myfield variable references an element (host object) rather
than some sort of wrapper (Object object) then this could possibly be
a leaky pattern. But I find it extremely unlikely that the bind
method attaches your clickHandler function as the listener (more
likely it wraps it in another function). Again, it's hard to say
without looking into the library code (which is likely what you are
trying to avoid by using a library). By using such a library, you
have created problems for yourself, as well as for anyone who would
try to debug the code (e.g. me).
It's more correct because the myfield var goes out of scope after use
because the clickHandler can't see it.
That indicates some understanding of the problem; but again, it is
unclear whether there was a problem in the first place.
And why not do this:-
function Widget() {
var el = document.getElementById('id_myfield');
el.onclick = function() {
// Do something
};
el = null;
}
It should be clear that without the last line, there would be a
circular reference involving a host object (and therefore it would
leak in some versions of IE). Also, the - this - keyword will
reference the element, so you don't need to preserve it.
If your listener will need a reference to the constructed object,
add:-
var that = this;
If you don't need a reference to your constructed object, you could do
this:-
function clickListener() {
// Do something
}
function Widget() {
var el = document.getElementById('id_myfield');
el.onclick = clickListener;
}
Hard to say from your examples, but assuming you do need such a
reference:-
function createClickListener(that) {
return function() {
// Do something
};
}
function Widget() {
var el = document.getElementById('id_myfield');
el.onclick = createClickListener(this);
}
I was caching the reference to the DOM object id_myfield in
this.myfield, of course var myfield would accomplish the same goal
without making it a public property.
I didn't see how you considered that caching as every call to the
constructor would repeat that operation. But I see what you are
getting at now.
My goal is to not have to use
getElementById or any other querying mechanism every time I want to
use a field.
You haven't posted any examples that use the element (or wrapped
element) reference, so it is hard to follow what you are trying to do.
Ok, you are correct. I didn't add them explicitly, I figured people
could envision what I was referring to.
There are few mind-readers here.
Here's an example:
function Widget(){
this.myfield = $('#id_myfield');
var clickHandler = function(event){ //do something };
this.myfield.bind('click', clickHandler);
this.setField = function(txt){
this.myfield.val(txt); // Yes it's jQuery syntax
}
}
And there are very few who care to dig through jQuery to determine
whether your assumptions about its methods are correct. But
regardless, the above has no circular reference (with or without
jQuery). The - this - keyword is not part of the scope chain and
jQuery's "$" method does not return host objects anyway. The only
thing that could create leaks here is jQuery and therefore the only
way to know for sure whether leaks will occur is to read jQuery's
code, which negates the benefit of using the library.
Consider this more readable alternative, which does not require any
odd patteners or an additional 70K of junk code:-
function createClickListener(that) {
return function() {
// Do something with this and that
};
}
function Widget(){
el = document.getElementById('id_myfield');
el.onclick = createClickListener(this);
this.setField = function(txt) {
el.value = txt;
};
}
In your listener - this - will refer to the element and - that - will
refer to the widget object.
That's much faster, more readable and obviously much less code to pore
over and maintain.
The document you directed me to explains exactly the situation I'm
referring to.
But apparently you did not understand it.
This is directly from that page:
Closures are extremely good at forming circular references. If a
function object that forms a closure is assigned as, for example, and
event handler on a DOM Node, and a reference to that Node is assigned
to one of the Activation/Variable objects in its scope chain then a
circular reference exists. DOM_Node.onevent -> function_object.
[[scope]] -> scope_chain -> Activation_object.nodeRef -> DOM_Node. It
is very easy to do, and a bit of browsing around a site that forms
such a reference in a piece of code common to each page can consume
most of the systems memory (possibly all).
Yes, I've read it. But pasting snippets here will not help you
understand why - this - is not part of the scope chain.
Ok, so what you just did was answer the next part of my question. I
may need to manually dereference the individual references, using the
delete command.
Not in the case of your examples as - this - is not part of the scope
chain.
They are in a circular reference as described by the page you
referenced.
Which you have failed to understand completely.