micmath blog
RecentJavaScript Constructors and Factories
One of JavaScript's peculiarities is the 'new' expression: when a function invocation is included in that expression that function behaves like a constructor. But the function, by itself, is not intrinsically a "constructor," it's still just a function, and as such any function intended to be called with new can just as easily be called without new. Of course if you, the function's author, are relying on the side-effects provided by new things may not work as intended when those effects are missing. There are however many built-in examples of functions which work equally well, if perhaps slightly differently, when invoked as a constructor or as an ordinary function:
Objects are created by using constructors in new expressions; for example, new String("A String") creates a new String object. Invoking a constructor without using new has consequences that depend on the constructor. For example, String("A String") produces a primitive string, not an object. -- ECMAScript Language Specification, 4.2.1 Objects
Constructors are not the only way to build objects, there is a similar pattern that involves a function, called a "factory." The difference is that a factory is not called with new and factories don't return their this value, as constructors do. You could say that String is an example of a function that can be invoked as a constructor to return a String object, or as a factory to return a string primitive. This design blurs the distinction between factories and constructors. What can we do in this blurry area?
One thing we can do is to create a wrapper for an existing constructor, where we add on our own extensions:
function ArrayPlus() {
var self = Array.prototype.slice.call(arguments);
self.last = function() {
if (this.length) return this[this.length-1];
};
return self;
}
var a1 = new ArrayPlus(1, 2, 3); // like a constructor
var a2 = ArrayPlus(1, 2, 3); // like a factory
// the result is the same, arrays that can last()
alert( a1.push(4), a1.last() ); // alerts 4
alert( a2.push(4), a2.last() ); // alerts 4
When we call ArrayPlus as a factory it returns an instance of an Array with an extra method added on. However the same thing happens when we call ArrayPlus as a constructor, how is that possible?
Typically when a function is invoked as a constructor it automatically returns the constructor's own this value, however in ArrayPlus we are returning our own object, named self. This is allowed under the rules of the ECMAScript Language Specification (section 13.2.2), but it is important to know what the difference is: self is an instance of an Array, not an ArrayPlus. In essense we are overriding the typical behavior of a constructor and forcing ArrayPlus to always behave like a factory, whether it is called with or without new.
I referred to the ECMAScript Language Specification a moment ago, and it does indeed allow arbitrary objects to be returned from constructors, but there is a caveat worth knowing related to this: a constructor (called with new) cannot return a non-object. For example:
function MyNumber(value) {
var self = new Number(value); // an object
return self;
}
var one = new MyNumber(1);
function Three(value) {
var self = 3; // a primitive
return self;
}
var three = new Three();
alert(one); // alerts 1
alert(three); // alerts "[object Object]"
What happened? The rules of ECMAScript say that if a constructor returns an object, as MyNumber does, then proceed as expected. But if a constructor returns a non-object, as Three does, then ignore the return statement entirely and instead return whatever the constructor's this value is. In the case of Three the this value is an instance of Three; in any case it is not the number 3, as you might think it is.
HTML DOM Manipulation with PHP
When discussing HTML DOM (Document Object Model) manipulation it is common to think JavaScript, but there are cases where you might want to do this on the server.
You, if you're like me, might think that HTML, or at least XHTML, is a job for simplexml. Loading and parsing an XHTML file is certainly possible with simplexml_load_file and you can easily use the various simplexml methods to maanipulate the DOM. You will however encounter a small problem if you need to output HTML. As simplexml is designed to deal with XML, it sees nothing wrong with outputting compacted empty tags. In other words if you give it an empty textarea, like so:
$xml = simplexml_load_string('<textarea></textarea>');
and a little while later try to get that string back again, you will find that it's taken some liberties:
echo $xml->asXML(); // <textarea />
This is perfectly fine XML but as HTML it breaks at least a few browsers. If you want to avoid this you'll need to start thinking up clever ways to circumvent what simplexml wants to do.
Or we can just not use simplexml.
The DOMDocument class is, perhaps not unsurprisingly, more feature-rich than the its simpler little brother. For example it has a a way to preserve opening and closing tags:
echo $dom->saveXML($dom, LIBXML_NOEMPTYTAG); // <textarea></textarea>
But even more usefully, it has a loadHTMLFile method and a saveHTML method, which treat HTML more like, well HTML.
Here's a quick example, we're looking to get the names of any required textareas:
$dom = new DomDocument();
$dom->loadHTMLFile($myHtmlFile);
$requireds = array();
$nodes = $dom->getElementsByTagName('textarea');
foreach ($nodes as $node) {
if ($node->hasAttribute('required')) {
array_push($requireds, $node->getAttribute('name'));
}
}
Understanding Variable Instantiation
Quick, just from examining this code (no fair testing it), what will the following alert?
var f = 1;
function f() { }
alert(f);
The fact that I consider this code intersesting (or at least instructive) may tip you to what the answer will be: it's 1. Surprised? If you are you're likely suffering from the common misconception that your JavaScript code is executed in the order you wrote it. If that were true the variable named f would first be declared, then assigned the value 1. Next the function named f would be declared, replacing that existing f and finally the alert would show us the function. But we know that's not what happens.
What really happens is explained in section 10.1.3 of the ECMAScript specification, entitled "Variable Instantiation". If you imagine there is a Variable Object and the JavaScript engine is adding properties to it based on your source code, the specification defines the following distinct steps and the order in which they must happen:
- Function declarations
- Variable declarations
- The rest
Note that when you write var f = 1; you are really doing two things together: declaring a variable named f and then assigning the value of 1 to it. So, putting all that together, effectively the code in our previous example is the same as this:
function f() { } // function declarations first
var f; // variable declarations next
f = 1; // the rest
alert(f);
Is Lightbox the New Popup Window?
Web-based advertising has always been the unloved stepson of web development. Well I say unloved but actually there are lots of people who feel a sort of passion about things like "branding", "click-through rates" and "return on investment". The fact that these things personally bore me doesn't change the fact that there has always been an understanding in this business that if we want to have free-to-view web pages, we must then have a load of ad banners all over those pages. I'm going to concede that point, at least for the sake of my bigger argument.
And I'm conceding the point even though I have no personal experience to base it on: I myself have been using the World Wide Web from it's first days and can safely say I have never, not once ever, clicked on a single web ad. Not even one. Am I living this lifestyle to make some socio-political point? Nope, I'm just still waiting to see a web ad that is interesting enough to click on.
The ad mongers obviously know about uncooperative potential-customers like me, but when they analyze the problem of "he's still waiting to see a web ad that is interesting enough to click on" they come to the wrong conclusion that the solution is to make their uninteresting ads easier to see. If the blinking banners aren't appealing, they reason, then waving a popup window about in front of the content will surely make him want to click; it's worth a try anyway, right? I mean what's the harm?
So here's the harm: Since 2004 every major web browser has had an option to "block popup windows" built-in. And if that's not enough, users can choose from a wide variety of addons and plugins to do the same. If you, wayward web developer, have ever put an uninteresting ad in an popup window, you have helped to practically remove the popup window feature from every modern web browser. Well done, I hope you're proud of yourself.
But in the arms race for greater "CPMs" and "ROIs" there can be no surrender. If the user has developed an immunity to popup windows then there are other fronts to attack.
Now, based on the title of this blog entry, you might guess that I'm suggesting that Lightbox style ads are the latest front, and you'd be right. But I don't intend to criticize the technique used by JavaScript Lightbox implementations, they are no more evil than popup windows were ten years ago. Lightboxes don't annoy people, but annoying Lightboxes do. And here we are standing at the start of yet another very predictable path: how long before we see advice on how to disable JavaScript Lightboxes?
The problem is that a JavaScript Lightbox is not as distinct and self-contained as a popup window. Probably the most practical way to disable all JavaScript Lightboxes will be to disable JavaScript. This is a race back to the 1990's in terms of web development and it should be a concern to all of us.
But it's hard to know who to address this point to: I don't have the illusion that aggressive web advertisers, working for financially-desperate companies are going to suddenly develop a long-view ethos about this issue based on my warnings. In-your-face, hard-sell, intrusive web advertising will always be around but maybe it's up to all of us to enforce a new social contract, if these offenses are offered up by people who speak in terms of dollars and "clicks", then we can give our answer: don't click on those damned things. In fact add those products to your own blacklist of bad members of our web community. Avoid the hosting web sites altogether if possible. This is a campaign for us, if you're a web developer you may be helping yourself in the long run.
Mysterious At-Sign: Extended Attributes in Mac Files
I was attempting to run an old perl script today, and doing a quick ls -la to check the permissions revealed a mysterious at-sign @ in the permissions.
-rw-r--r--@ 1 michael michael 467 8 May 13:16 cvsToSql.pl
Hi there little at-sign. What are you doing in there?
And do you know how hard it is to google the meaning of an at-sign in ls -la? Not easy. I did learn that a filename with a trailing at-sign can indicate a symbolic link on Linux. But this is Mac OS X Leopard and the at-sign is in the permissions. More googling....
The best answer is from dev.netcetera.org and Jeff Seitz’s Blog, and it is that the at-sign indicates that the file has extended file attributes. Hmmm... I want to get rid of those I think. Step one is to find out the name of the extended attribute.
$ xattr -l cvsToSql.pl
com.apple.FinderInfo:
0000 54 45 58 54 52 2A 63 68 00 00 00 00 00 00 00 00 TEXTR*ch........
0010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
Okay, so my file has some extra data attached to the "com.apple.FinderInfo" attribute. I suppose there is some important nerd-reason for that being there but I'm not interested: step two is to get it off.
$ xattr -d com.apple.FinderInfo cvsToSql.pl
And no more at-sign! All that files attributes are now of the non-extended variety.
Microsoft Mime Types
I had a problem with some more recent Microsoft document formats not being recognized when downloaded from an Apache server. Ironically it was the IE 8 having the problem -- I think it was trying to be secure -- while FireFox knew what to do just fine. Any way, here's an .htaccess addition that will help our IE 8 friends out (with thanks to mcupples):
AddType application/vnd.ms-word.document.macroEnabled.12 .docm
AddType application/vnd.openxmlformats-officedocument.wordprocessingml.document docx
AddType application/vnd.openxmlformats-officedocument.wordprocessingml.template dotx
AddType application/vnd.ms-powerpoint.template.macroEnabled.12 potm
AddType application/vnd.openxmlformats-officedocument.presentationml.template potx
AddType application/vnd.ms-powerpoint.addin.macroEnabled.12 ppam
AddType application/vnd.ms-powerpoint.slideshow.macroEnabled.12 ppsm
AddType application/vnd.openxmlformats-officedocument.presentationml.slideshow ppsx
AddType application/vnd.ms-powerpoint.presentation.macroEnabled.12 pptm
AddType application/vnd.openxmlformats-officedocument.presentationml.presentation pptx
AddType application/vnd.ms-excel.addin.macroEnabled.12 xlam
AddType application/vnd.ms-excel.sheet.binary.macroEnabled.12 xlsb
AddType application/vnd.ms-excel.sheet.macroEnabled.12 xlsm
AddType application/vnd.openxmlformats-officedocument.spreadsheetml.sheet xlsx
AddType application/vnd.ms-excel.template.macroEnabled.12 xltm
AddType application/vnd.openxmlformats-officedocument.spreadsheetml.template xltx
I Choose to Feel Thankful
I remember sitting in the backseat of Gordie's mini-van as we drove across the 59th Street Bridge towards Manhattan while on the radio there was continuing coverage of the attack on the World Trade Center a few hours earlier. We continued into Midtown along with everyone else on the bridge and went about our business the rest of the day without any other sign that the great collective spirit of New York was so much as dented by these so-called terrorists. It would take hell of a lot more than that to break the stoicism of New Yorkers.
But that was 1993, and 8 years later I would find myself heading towards that same bridge once again, looking across the East River towards the Twin Towers, this time a long trail of gray smoke was surreally suspended in a perfectly blue sky, attached, it seemed, to the North Tower. As I watched, a gleaming silver airplane flew low over the skyline towards the South Tower.
For some reason, probably that New Yorker stoicism, I continued on into my office on West 14th Street. I still couldn't conceive of the idea that New York could be stopped. As I sat at my desk (at a cable television network) I listened to the news reports covering the events as they happened, in real-time, just a short distance from the building I was in. But I maintained an internal faith that the towers, and the people in them would be okay. This was New York afterall, we'd survived this sort of thing before. But for the first time in my adult life I experienced the very real feeling of shock which comes from seeing society itself falling down around you.
My outlook on life was permanently changed that day, damaged in some ways, encouraged in others. I'm not terrorized, I'm not spending today's anniversary filled with hate or anger. Gordie, my friend who drove us into Manhatten that day in 1993, would later learn his brother Edward Felt was murdered on Flight 93. He uses that word, murdered, with a deep sense of intention: his brother was not killed, he did not perish, he was not lost. I can't begin to relate to what Gordie is feeling about what happened that day.
I'm one of those who, when the question of how to rebuild was finally discussed, felt that we should rebuild the Twin Towers, girder by girder, window by window, exactly as it was before. I remember a cartoon in one New York newspaper that went further and suggested the new buildings should be in the shape of a hand, its middle finger raised defiantly towards the ocean. I think defiant is a good word to describe New York.
So I wonder, as an American, what am I supposed to feel today, should I be mournful, angry, scared? I don't feel any of those, though I am truly sad so many completely innocent and good people were murdered, their families left to bear the unbearable. But the truth is I have no right to insert myself in their mourning--by chance it wasn't me who was hurt, it wasn't my family that was left to wonder why their father, their mom, their brother won't be coming home any more.
Instead I choose to feel thankful. A few weeks after 9/11 I felt compelled to volunteer at a Red Cross station adjacent to the still smoldering ruins of the World Trade Center. This was a station for the firefighters, police and other workers who were still searching through the wreckage, looking for the pieces of the bodies of their missing comrades. I didn't do much, I spent the afternoon cleaning the showers and distributing drawings children had sent to the Red Cross. Many of those haunted-looking men spent 24 hours a day on-site, refusing to leave while their buddies were still under the fallen buildings. The Red Cross was there to make sure they had a small bit of comfort, a warm meal, a blanket when they were too tired to carry on. So I choose today, and on every 9/11 anniversary, to be thankful that in the face of the most appalling atrocities, the most frightening violence and disaster, there are men and women who are willing to run towards the fire, the flood, the attack, and give whatever aid they can, to risk their lives to help ordinary strangers. To me that is the very definition of a hero and I truly am grateful such people exist.
I'm donating a little money to the Red Cross fund today and I'd suggest that today is the perfect day for each of us to take a moment and ask ourselves what can we can do to help those who are willing to risk their lives to help us when we most need it.
