.NET Daily Quiz archive — week 6

.NET Daily Quiz #026

Welcome to Javascript week! This week it's all JS, which is good for me because coming up with Javascript gotchas is like shooting fish in a barrel.

Let's start with a softball. What does this function return?

function helloThere(name) {
    return
    {
        theName: name
    };
}

Answer

The function returns 'undefined'.

In Javascript the expression to return must start on the same line as the return keyword. In the example I gave the expression started on the next line. As a result, the Javascript language requires a semicolon insertion on return. The resulting code looks like

return;
{
    theName:name
};

and the returned value is undefined. The solution is to write the statement like so:

return {
    theName:name
};

You should know the rules for semicolon insertion by heart - not because you are relying on the interpreter to insert your semicolons, but so that you can explicitly use semicolons in every case. Never rely on semicolon insertion. If you follow this rule then any time you do spot a case of semicolon insertion in your JS you can assume it's a bug and fearlessly change it.

Semicolon insertion rules:
http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf (PDF warning, page 26)

7.9.1 Rules of Automatic Semicolon Insertion
There are three basic rules of semicolon insertion:

1. When, as the program is parsed from left to right, a token (called the offending token) is encountered that is not allowed by any production of the grammar, then a semicolon is automatically inserted before the offending token if one or more of the following conditions is true:
- The offending token is separated from the previous token by at least one LineTerminator.
- The offending token is }.

2. When, as the program is parsed from left to right, the end of the input stream of tokens is encountered and the parser is unable to parse the input token stream as a single complete ECMAScript Program, then a semicolon is automatically inserted at the end of the input stream.

3. When, as the program is parsed from left to right, a token is encountered that is allowed by some production of the grammar, but the production is a restricted production and the token would be the first token for a terminal or nonterminal immediately following the annotation "[no LineTerminator here]" within the restricted production (and therefore such a token is called a restricted token), and the restricted token isseparated from the previous token by at least one LineTerminator, then a semicolon is automatically inserted before the restricted token.

However, there is an additional overriding condition on the preceding rules: a semicolon is never inserted
automatically if the semicolon would then be parsed as an empty statement or if that semicolon would become
one of the two semicolons in the header of a for statement (see 12.6.3).


.NET Daily Quiz #027

There’s a major problem with this function. Do you know what it is?

function getDocument(txt, abstr) {
    var c = "lower";
    for (var i = 0; i < txt.length; i++)
        if (txt.charAt(i) == txt.charAt(i).toUpperCase()) c = "mixed";
    return {
        text: txt,
        abstract: abstr,
        native: true,
        case: c,
        export: function () {
            // export to .zip'd JSON
            return zip;
        }
    };
}
var doc = getDocument("This is my document", "brief abstract");

Warning: this will work in some implementations, but it’s broken according to the spec.

Answer:

Believe it or not, the following names from the example are reserved words in Javascript: abstract, native, case, export

In fact, Javascript has reserved a whole slew of words that are not used in the language and are illegal if used as identifiers. Following is the complete list of reserved words in JS.

abstract 	else  		instanceof	super
boolean  	enum  		int  		switch
break  	 	export  	interface 	synchronized
byte  	 	extends  	let  		this
case  	 	false  		long  		throw
catch  	 	final  		native  	throws
char  	 	finally  	new  		transient
class  	 	float  		null  		true
const  	 	for  		package  	try
continue 	function  	private  	typeof
debugger 	goto  		protected 	var
default  	if  		public  	void
delete   	implements  return  	volatile
do  	 	import  	short  		while
double   	in  		static  	with  

http://www.javascripter.net/faq/reserved.htm


.NET Daily Quiz #028

This Javascript program works perfectly:

(function () {
    function printArgs(arr) {
        for (var i = 0; i < arr.length; i++) {
            console.log(arr[i]);
        }
    }
    function getLastTwoValues(arr) {
        return arr.slice(-2);
    }
    var arr = [1, 2, 3, 4, 5];
    printArgs(arr);
    console.log(getLastTwoValues(arr));
})();

Does this one behave the same? If yes, how? If not, why not?

(function () {
    function printArgs() {
        for (var i = 0; i < arguments.length; i++) {
            console.log(arguments[i]);
        }
    }
    function getLastTwoValues() {
        return arguments.slice(-2);
    }
    printArgs(1, 2, 3, 4, 5);
    console.log(getLastTwoValues(1, 2, 3, 4, 5));
})();

Note: I’m aware that the console object is not cross-browser compatible. Unless otherwise specified you can always assume my JS quizzes target the latest mainstream version of Chrome. V8 Engine is best engine.

Answer:

The second program will fail to execute inside of getLastTwoValues(), and here's why:

Every function call supplies two extra arguments additional to what it declares - this and arguments. this is dependent on scope (we'll get into this in a future quiz) and arguments is an "array" representing all of the arguments passed into a function, even if no arguments are declared in the function signature.

The problem is that arguments isn't actually an Array - it looks and acts like one in some cases, but has Object prototype and happens to contain a length property. Calling slice() (or any other Array methods) on arguments will fail.

If you really need to apply Array methods on your arguments parameter you can convert arguments to an array. The most common way of doing this is using the following idiom:

var actualArray = Array.prototype.slice.apply(arguments);

This is kind of hacky, but it seem to be common enough (Crockford uses it fairly extensively in his famous book, Javascript: the Good Parts).

Array.prototype.slice is a function that returns a subarray. The apply method is on the Function prototype and applies a given function, using the first argument as the this variable and subsequent arguments as function arguments. slice always returns an array, even when no arguments are supplied, so when we apply slice to arguments the returned value is an array with every element from arguments.

The complete code for our function becomes:

function getLastTwoValues() {
    var slice = Array.prototype.slice;
    return slice.apply(arguments).slice(-2);
}

In my opinion using Array.prototype.slice.apply is hackish and relies on implementation details of Array.slice() that we shouldn't be aware of. However, so much code now relies on this behaviour that it's unlikely to change in the near future. I'll use it, but I'll shower afterwards.


.NET Daily Quiz #029

My program is not behaving as expected. What is the console output and why? How can I fix it?

var myValue = 0;
(function () {
    for (; myValue < 10; myValue++) {
        console.log(myValue);
    }
    var myValue = 0;
    console.log(myValue);
}());

Answer:

The output look liks

0

The issue here is a concept called variable hoisting. Because we're prefixing myValue inside the function with var we are creating a new inner variable that hides the outer myValue (a variable that is never actually used). This inner myValue is then hoisted to the top of the function and assigned an undefined value, as per the Javascript specification. The resulting code looks something like:

var myValue = 0;
(function () {
    var myValue;
    for (; myValue < 10; myValue++) {
        console.log(myValue);
    }
    myValue = 0;
    console.log(myValue);
}());

Here the loop immediately terminates because "myValue < 10" evaluates to "undefined < 10" which is always false.

As an addendum, here’s the correct code if you really want myValue to remain in the global namespace (or the current function scope if my entire program happened to be wrapped in a function of its own):

var myValue = 0;
(function () {
    for (; myValue < 10; myValue++) {
        console.log(myValue);
    }
    myValue = 0;
    console.log(myValue);
}());

The only change I have made here is removing the var from the inner reference to myValue. This prevents the creation of a shadowed copy which prevents the hoisting of myValue to the top of the function. The program now behaves as expected.


.NET Daily Quiz #030

Can you explain the behaviour of this program?

(function () {
    var MyObject = function (id) {
        this.id = id;
        this.printId = function () {
            console.log("My id is " + id);
        }
    }
    var obj1 = new MyObject(123);
    var obj2 = {
        id: 123,
        printId: function () { console.log("My id is " + this.id); }
    };
    obj1.printId();              // prints "My id is 123"
    obj2.printId();              // prints "My id is 123"
    setTimeout(obj1.printId, 1); // prints "My id is 123"
    setTimeout(obj2.printId, 1); // prints "My id is undefined"
}());

Answer:

As usual with Javascript it comes down to the behaviour of the this variable. What’s happening here is that setTimeout uses the Function.apply (or maybe Function.call) method to apply the given function. Function.apply takes as its first argument a variable to set to the this context (see quiz #028). Because the id field is not set on the this supplied (the global object) it is undefined.

The reason obj1 is behaving “correctly” is because there’s a bug in the constructor function! We are binding the id argument to this.id but this is not the field we are using in printId() — we are using the captured id argument in a closure! Changing the id field on obj1 has no effect because we are not closed over that field. We can fix the MyObject constructor by writing it as

var MyObject = function (id) {
    this.id = id;
    this.printId = function () {
        console.log("My id is " + this.id);
    }
}

And make out code work correctly by calling the function in setTimeout like this:

setTimeout(function () { obj1.printId(); }, 1); // prints "My id is 123"

Javascript is a subtle language. There were two bugs (intentional) in the original code, but those bugs appeared to make the broken object work correctly and the correct object look broken.