"this" keyword and getElementsByTagName

Hi,
I’m working through the Sitepoint book Simply Javascript and I’m having problems understanding the code execution in the section on event listeners, specifically the use of the keyword this and the results of the getElementsByTagName method.

The js code is here - most of the comments are my attempts at understanding the code. The Core methods are a library given in the book to deal with cross-browser issues regarding to event listeners.


var Tooltips = {
	init: function() {
		var links = document.getElementsByTagName("a");
		
		for (var i = 0; i < links.length; i++) {
			var title = links[i].getAttribute("title");
			
			// debug block
			targetUrl = links[i].getAttribute("href");
			alert("links[i]:" + links[i]);	// gives url - why not <a>?
			alert("target: " + targetUrl);	// gives url
			// end debug
			
			if (title && title.length > 0) {
				Core.addEventListener(links[i], "mouseover", Tooltips.showTipListener); // element?, "event", listener
				Core.addEventListener(links[i], "focus", Tooltips.showTipListener);
				Core.addEventListener(links[i], "mouseout", Tooltips.hideTipListener);
				Core.addEventListener(links[i], "blur", Tooltips.hideTipListener);
			}
		}
	},
	
	showTip: function(link) {
		Tooltips.hideTip(link);
		var tip = document.createElement("span");	// tip = span
		tip.className = "tooltip";		// now have span with class tooltip
		var tipText = document.createTextNode(link.title);	// create new textnode with the title text from the orig html
		tip.appendChild(tipText); // place the new textnode in the DOM as child of span
		link.appendChild(tip);	// add the whole span inside the <a>
		
		link._tooltip = tip;
		link.title = "";
		
		// fix for safari2/opera9 repaint issue
		document.documentElement.style.position =  "relative";
	},
	
	hideTip: function(link) {
		if (link._tooltip) {
			link.title = link._tooltip.childNodes[0].nodeValue;
			link.removeChild(link._tooltip);
			link._tooltip = null;
			
			// fix for safari2/opera9 repaint issue
			document.documentElement.style.position = "static";
		}
	},
	
	showTipListener: function(event) {
		//alert(this);	//		showing url
		Tooltips.showTip(this);	// 
		Core.preventDefault(event);
	},
	
	hideTipListener: function(event) {
		Tooltips.hideTip(this);
	}
	
};

Core.start(Tooltips);

The html file is:


<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html lang="en">
<head>
    <meta http-equiv="content-type" content="text/html; charset=utf-8">
    <title>Richer tooltips</title>
    <link rel="stylesheet" type="text/css" href="tooltips.css">
    <script type="text/javascript" src="../core.js"></script>
    <script type="text/javascript" src="tooltips.js"></script>
</head>
<body>
		<h1>Heading</h1>
		<p>some useful web sites are:</p>
		<ul>
			<li><a class="richTip" href="http://www.google.co.uk/" 
				title="This is more information about Google, who promised to do no evil.">Google</a></li>
			<li><a class="richTip" href="http://www.twitter.com/" 
				title="Twitter is a social networking site that allows you to waste time while occasionally receiving useful information.">Twitter</a></li>
			<li><a class="richTip" href="http://www.flickr.com" title="I have my photos on my Flickr account.">Flickr</a></li>
		</ul>

</body>
</html>


A number of points:

I understood getElementsByTagName to give an array of that element so why does links[i] refer to the url and not the <a> element. Surely the url should be retrieved in a similar way to the title?

In the init function ‘this’ would refer to the window object - yes I get this. I thought that ‘this’ referred to the parent object of the current scope so why does it refer to the url in the showTipListener function?

Can anyone point me in the right direction here?

Regards,
Duncan

getElementsByTagName doesn’t return an array, it’s something array-like called a NodeList. It’s important to be aware of the distinction, although most of the time it behaves like an array.

You’re right that alert("links[i]:" + links[i]); should give you an alert saying “links[i]: [object HTMLAnchorElement]” (at least in Firefox). It seems that for links it’s decided that providing the href attribute instead is more useful. A stupid decision, if you ask me. You can fix it by doing this:

alert("links[i]:" + links[i].constructor);

showTipListener is triggered by an event on a DOM element (e.g. mouseover). When this happens, this refers to the element the event happened on. If you called the function manually (i.e. not via an event), then this would refer to the window object again.

If you haven’t yet, I’d recommend visiting quirksmode.org and going through the Events tutorial. It’s short and very clear.

Which can be found at Introduction to Events

Thanks for that both. I’ve used quirksmode before, but not the event article.

Regards,
Duncan