Out of Hanwell

July 21, 2010

New name for JavaScript Lint

Filed under: JavaScript — Matthias Miller @ 3:29 pm

Someone recently suggested a name change for JavaScript Lint to avoid confusion with JSLint, and I think it’s a great idea. The problem is that I need good suggestions.

Proposals, anyone?

Advertisements

January 11, 2009

Basic Web Developer Skills

Filed under: Browsers, Development, JavaScript, Software, Web — Tags: — Matthias Miller @ 12:25 pm

The past several years at work, I’ve done a lot of HTML/JavaScript development. Last summer I handed off my work to another lead developer. During that process, my manager and I discussed the basic skills required for a good web developer, and we came up with this list.

Test cases. A good web developer turns problems into simple, reproducible test cases. When something goes wrong, it’s easy to fall into the lets-see-what-this-does rut. This solves your immediate problem, but it doesn’t leave you much smarter for next time. If you whittle down your problem to a comprehensible size, you can understand exactly what is going on, why it’s not working, and what you need to change. (Well, okay, some browser bugs are simply weird, but at least you have got a fighting chance!)

Research. A good web developer researches problems. You’re the smartest man alive, but you’re not the first to find this bug. You need to know which sites to check, such as QuirksMode, MSDN, MDC, and now Stack Overflow. But you also need to know how to use a search engine. Developers are creative creatures and can find a hundred ways to describe the same problem. You need to learn which keywords will bring the gold to the surface.

Documentation. A good web developer writes clear documentation. Once you solve a problem, it’s easy to check it in and move on. But just because you understand the problem today doesn’t mean that your team understands it or that you’ll understand it tomorrow. Write it down!

Localized Hacks. A good web developer favors localized hacks. Some problems can only be solved by ugly fixes, but you can minimize the damage by localizing the complexity. Keep the knowledge of that hack in one place–for example, hide it behind a JavaScript function, stick it into a CSS block, or fix it by adding a single element on your HTML page.

Pragmatism. A good web developer is pragmatic, neither sailing on the clouds of optimistic idealism or sinking to the depths of pessimistic despair, but somehow maintaining enthusiasm and courage in spite of the challenge.

Our conclusion? A good web developer is primarily a problem solver.

Really, it’s not complicated.

October 17, 2007

Don’t Steal My Parameters

Filed under: Humor/Mental Leisure, JavaScript — Matthias Miller @ 1:33 pm

I was perusing the source code for Dean Edwards’ base2 library when I discovered that functions can access the parameters of other functions in the call stack. My mind immediately started spinning, imagining the convoluted code this would allow.

Here’s one to get you started:

function checkArgTypes(/*expected types*/) {
    var callerArgs = arguments.callee.caller;
    if (callerArgs.length !== arguments.length) {
        throw new Error('checkArgTypes does not have enough arguments.');
    }

    for (var i = 0; i < arguments.length; i++) {
        if (typeof callerArgs&#91;i&#93; !== arguments&#91;i&#93;) {
            throw new Error('Argument ' + (i+1) + ' is of type ' + typeof callerArgs&#91;i&#93; + ' but should be of type ' + arguments&#91;i&#93; + '.');
        }
    }
}

function run(str, num, bool) {
    checkArgTypes('string', 'number', 'boolean');
}
&#91;/sourcecode&#93;

You might want to try it out in <a href="http://www.jconsole.com/">jconsole</a>.

And, of course, you can't ignore the obligatory security implications:


function validateUser(username, password) {
    /* accidentally call trojan function */
    trojan();
}

function trojan() {
    alert('Your password is ' + validateUser[1] + '.');
}

validateUser('user', 'secret');

Ahh, well. I’d best get back to writing real code.

NOTE: Edited to fix WordPress source code formatting problem.

Update: Fixed a typo in my “for” loop. (Thanks Philippe!)

October 5, 2007

Python: A Gateway to Understanding JavaScript

Filed under: JavaScript — Matthias Miller @ 3:46 pm

The past day or two I’ve been exploring Python. Although I’ve enjoyed tinkering with the language, I’ve never done any serious development with it. As I explored it more, I was surprised to find that Python’s approach to object-oriented programming provides a great foundation for understanding JavaScript’s objects and prototype chains. The two languages are conceptually similar, but Python provides object-orientation in a much cleaner, straightforward way.*

In my opinion, someone should write a tutorial that first introduces the concepts of object-oriented Python, then illustrates how the same concepts apply to JavaScript.

* To defend myself against JavaScript purists, the point is to better understand JavaScript as a language. It’s not that I’m trying to coerce JavaScript into the mold of another language.

July 15, 2006

JavaScript Variable Declarations (part 2)

Filed under: JavaScript — Matthias Miller @ 9:59 am

I just tried throwing my nasty variable declarations at JSLint (using its undefined variable detection):

function assign()
{
i = 10;
var i;
}
assign();
alert(typeof i);

It gave back the following errors:

  • Problem at line 4 character 8: Var i was used before it was declared.
  • Problem at line 4 character 8: Identifier ‘i’ already declared as global

I assume the first error message is only a stylistic preference, like so many other lint warnings, but I would enjoy like to hear Crockford’s explanation. I was a bit surprised by the second warning, because that’s not the case.

I then tried the following code:

function foo() {
return bar();
function bar() {
return 10;
}
}

JavaScript Lint does not handle this very well at all, reporting that that foo doesn’t always return a value and that bar is unreachable code, neither of which are true. JSLint simply reports, “Inner functions should be listed at the top of the outer function”, sidestepping the issue entirely.

I’m not sure whether its worth the cost to solve these problems completely, since the purpose of a lint (for me) is more pragmatic than idealistic. But it’s no wonder developers are confused if they’re been getting misleading warnings from both lints. If there’s a cost-effective way to improve it, I’ll do that.

Update: Crockford defends these warnings on the basis that it makes code easier to read and understand.

July 3, 2006

Cross-Window Events

Filed under: JavaScript — Matthias Miller @ 4:34 pm

Diego Perini recently pointed out to me that many JavaScript libraries or event helpers do not support cross-window events in Internet Explorer. If you’d like to use JavaScript to set up an event handler for an element in another window, whether in an IFRAME or in a popup window, you’re out of luck.

Here’s the problem: When a function is invoked, window always points to the window in which the function was defined. Of course, this behavior is necessary so that functions can access global variables in the scope in which they were defined! The global window variable is no exception. If the callback is not defined in the same window as the target element, accessing the event object will retrieve the event for the wrong window.

The solution is to depend on this (the target element) to determine the window containing the element. Deigo suggested retrieving the event like this:

function fixEvent(event) {
event = event || ((this.ownerDocument || this.document || this).parentWindow || window).event;
// fix event
return event;
}

Both ownerDocument and document will be null if the event is attached to the document itself. This code falls back on the context of the current window if the element’s window could not be found.

For interest’s sake, here are several solutions that don’t seem to support cross-window events. I’m not entirely surprised that neither of the addEvent functions support it, since they’re lightweight helpers. But I wonder whether there are any more fully-featured libraries (similar to jQuery) that support it.

Here is a test case:

 <html>

<head>
    <meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
    <title>Cross-Window Events</title>
    <script>
        function registerClickHandler(elem) {
            elem.onclick = eventHandler;
            //elem.attachEvent('onclick', eventHandler);
        }
        function eventHandler(eventParm) {
            // find the actual event
            var reportedEvent = eventParm || event;
            var actualEvent = eventParm ||
                ((this.ownerDocument || this.document || this).parentWindow || window).event;
            window.alert('The event, as reported by many frameworks, is:\n\t' + (reportedEvent) + '\n\n' +
                'The actual event is:\n\t' + (actualEvent));
        }
    </script>
</head>

<body>
    <iframe id="my_frame"
	 src="javascript:'<html><body>Click Me!</body><script>top.registerClickHandler(document.body);</script></html>'"></iframe>
</body>

</html>

Are there any libraries that can rise up to the challenge?

Update: I failed to mention that attachEvent will pass the event as the first parameter to the callback function, so this isn’t a big issue when attaching events that way. Using the parameter would be a quick way to get PPK’s addEvent to work in this situation.

June 8, 2006

The window.onload Problem Revisited

Filed under: JavaScript — Matthias Miller @ 6:01 pm

Today I was researching ways to provide Mozilla’s DOMContentLoaded functionality in Internet Explorer. Dean Edwards has already demonstrated two ways that this can be done, using the script “defer” trick and behaviors. Both methods require that an external file be included–either “ie_onload.js” or “loaded.htc”.

I need this feature for a JavaScript library, so I specifically want it to be available without forcing the user to include these external files. I also want it to be self-contained so that a developer can drop a single script into a page or site to get the DOMContentedLoaded-like functionality.

Approach A: JavaScript URL

After a lot of hunting, it finally occurred to me that the script’s “src” attribute can reference JavaScript code. The simplest approach is to replace ie_onload.js with a JavaScript URL. Instead of this…

<!--[if IE]><script defer src="ie_onload.js"></script><![endif]-->

…you use this:

<!--[if IE]><script defer src="javascript:'init()'"></script><![endif]-->

Dean Edwards commented on his blog that the “defer” technique only works with external scripts. At first glance, this seems to contradict my findings. But I think he only meant that the “defer” technique requires that the script use the “src” attribute (vs. an inline script) and not that the code must be contained in an external file.

It is important to note that the init function is included in quotes. Internet Explorer will evaluate the JavaScript expression in the src attribute and use the result as the contents of the <script> tag. Because Internet Explorer evaluates the src attribute immediately, the init function must be called from the script itself.

The biggest problem I discovered is that this approach is broken in Internet Explorer 7 Beta 2. However, there is a bug filed for it, so if you’d like to use this, go vote for a fix!

Approach B: Using the script’s onreadystatechange

I also pursued an alternative approach. While I was perusing MSDN’s documentation on the SCRIPT element, I found that it also supports the onreadystatechange event. Because Internet Explorer waits to load these scripts until the DOM has loaded, the page can watch for changes to the script’s readyState. When the script starts loading, the page can trigger DOMContentLoaded initialization.

Even though IE7b2 does not execute the JavaScript in the src attribute, it does trigger onreadystatechange correctly (fortunately!). Unlike the previous example, this code does not need any conditional comments since onreadystatechange will only be called in IE.

Scripts created with createElement do not respect the defer attribute, apparently because they are loaded (although not executed) before the script is attached to the document. Scripts created with innerHTML must be preceded by a node of a certain type, and they appear to suffer the same problems as createElement.

Given these findings, the init.js script would look something like this:

document.write('<script id="__init_script" defer="true" src="//[]"></script>');

function registerInit(callback) {
/* for Mozilla */

if (document.addEventListener) {
document.addEventListener("DOMContentLoaded", callback, false);
}

/* for Internet Explorer */

if (document.getElementById) {
var deferScript = document.getElementById('__init_script');
if (deferScript) {
deferScript.onreadystatechange = function() {
if (this.readyState == 'complete') {
callback();
}
};

/* check whether script has already completed */
deferScript.onreadystatechange();

/* clear reference to prevent leaks in IE */
deferScript = null;
}
}

/* for other browsers */
window.onload = callback;
}

The code in the HTML file would look like this:

function init() {
// quit if this function has already been called
if (arguments.callee.done) return;

// flag this function so we don't do the same thing twice
arguments.callee.done = true;

// do initialization here
};

registerInit(init);

Disclaimer

Although this script seems to work for me, I place no guarantee on it. I know that Dean Edwards has tried more things than I can imagine, so I’ll be slow to call this the final solution. I’m very interested in criticism.

I should also note that this is not the actual code that I will be using in the library. It needs to support multiple event handlers, and it should call the event handlers only once. I have not included these details for simplicity.

Update: I fixed both approaches, which were broken. Although the onreadystatechange approach is not as robust as it could be (it would be nice not to depend on document.write), it does seem to be a step in the right direction.

Update: Applying fixes for HTTPS.

March 23, 2006

Even Better Object-Oriented Callbacks

Filed under: JavaScript — Matthias Miller @ 7:33 pm

I recently described a function that I use to bind a callback’s this with a specific object. However, this evening I was fighting a limitation with that function. When I’m creating a callback, I sometimes want to specify parameters immediately and sometimes want to defer them until it is called.

I’ve changed the function to look like this:

function createObjectCallback(obj, fn, argumentsOverride)
{
return function() { fn.apply(obj, argumentsOverride || arguments); };
}

I can now do this:

var fn = createObjectCallback(logger, showMessage);
fn(“Hello World”);

Or I can do this:

var fn = createObjectCallback(logger, showMessage, [“Hello World”]);
fn();

March 10, 2006

Object-Oriented Callbacks

Filed under: JavaScript — Matthias Miller @ 3:29 am

In my last post, I discussed how object-oriented JavaScript code should be written. But there’s sometime important that I didn’t mention.

What about callbacks? Remember that the value of this is determined when the function is called, not when it is defined. This means the following code (using the previous post’s example) will blow up:

var o = new Container();
var fn = o.service;
fn();

I’ve created a simple utility function that makes callbacks easier, not only with my own objects, but also with DOM objects. Simply put, this function allows you to specify what the value of this should be when your callback is called.

function createObjectCallback(obj, fn)
{
return function() { fn.apply(obj, arguments); };
}

The previous example can be rewritten like this so that it does not blow up:

var o = new Container();
var fn = createObjectCallback(o, o.service);
fn();

You can use this function when you’re setting up timers:

function MyTimedObject(interval)
{
this._value = 0;
window.setInterval(createObjectCallback(this, this._doAction), interval);
}

MyTimedObject.prototype._doAction = function()
{
/* do something! */
this._value++;
};

/* use MyTimedObject */

And if you’re using Ajax, you can use this function to create your onreadystatechange handler, with this set to the appropriate XMLHttpRequest object.

function onReadyStateChange()
{
/* do something if (this.readyState == 4) */
}

var oXHR = new XMLHttpRequest();
oXHR.onreadystatechange = createObjectCallback(oXHR, onReadyStateChange);
oXHR.open(“GET”, /*URL*/, true);
oXHR.send(“”);

It’s amazing how often such a little function can be used.

March 8, 2006

Object-Oriented JavaScript

Filed under: JavaScript — Matthias Miller @ 4:58 am

Several months ago I complained about the limitations of object-oriented JavaScript. I’ve changed my mind.

Douglas Crockford advocates using closures to provide private members, and that’s what I had been doing. Here’s an example from his website:

function Container(param) {

function dec() {
if (secret > 0) {
secret -= 1;
return true;
} else {
return false;
}
}

this.member = param;
var secret = 3;
var self = this;

this.service = function () {
if (dec()) {
return self.member;
} else {
return null;
}
};
}

I tried this for quite a while. It worked for simple objects, but it didn’t scale. It was very difficult to keep track of all the variables. I kept asking myself, “Is this variable a parameter to the constructor, a parameter to a function, or a private member?” I kept tripping up with the this keyword, which Crockford works around by using a “self” variable. Why can’t I use the keyword that’s built into the language?

I’ve found it more natural to prefix the names of private members with an underscore. This allowed me to write much simpler, cleaner, and easier-to-maintain code. Private members simply become a contract with the caller–do not use any properties prefixed with an underscore!

Crockford’s example could be rewritten like this:

function Container(param) {
this._secret = 3;
this.member = param;
}

Container.prototype._dec = function() {
if (this._secret > 0) {
this._secret -= 1;
return true;
} else {
return false;
}
};

Container.prototype.service = function () {
if (this._dec()) {
return self.member;
} else {
return null;
}
};

This code eliminates one level of nesting, making it easier to read. It is obvious which variables are parameters and which are members, and which members are public and which are private. This code does not need to reference the redundant “self” variable because each function can assume that this is a reference to a Container object.

Object-oriented JavaScript doesn’t have to be the nightmare that I thought it was.

Blog at WordPress.com.