The Blurb: This is mostly just a bit of fun and in form of some rough notes as I’ve been sticking my head into a few JavaScript books and thought I’d write down what strikes me as odd/interesting along the way. Of course, I’ve written some bits of JavaScript but I’ve never really sat down and read up on it. I’m not trying to be definitive and nor am I trying to take a particular view – just poking around
OMG #6 – The Global Object
You’ll think I’m an idiot (fair comment ) but I’d no idea that when I was working with JavaScript and defining global variables and global functions and so on that I was actually mutating the global object. I’d never appreciated that there was a global object and so I’d been living in a place of ignorance and so now I know (or at least I think I do) that when I’m writing;
var myVariable = "some value"; // this console.log(myVariable); // is just like this console.log(this.myVariable); // is just like this console.log(this["myVariable"]); // and this is true console.log("myVariable" in this);
then I’ve more of an appreciation that what I’m doing is adding to the properties of the global object which I can reach via its this reference.
Reference: Flanagan, “JavaScript The Definitive Guide”, Page 42
OMG #7 – “Expando Objects”
JavaScript has the very powerful/scary system which allows you to just expand objects with new properties as/when you feel like it unless those objects have been marked to disallow it. So, I can just go ahead and make myself a new object and then start to add things to it;
var myObject = { }; // just add whatever I want to this thing... myObject.x = 10; myObject.y = 20; myObject.add = function() { return(this.x + this.y); } console.log(myObject.add()); // arrays are also objects var myArray = [1,2,3]; myArray.sum = function() { // no attempt to require numbers here. var sum = 0; for (var i = 0; i < this.length; i++) { sum += this[i]; } return(sum); }; console.log(myArray.sum()); // functions are also objects var square = function(x) { return(x * x); }; square.y = 100; console.log(square.y + square(5));
This is all a little bit mind-blowing and it’s hard to thing of anything similar in the .NET world although there are ExpandoObject types that might get you somewhere near to it and especially when coupled with dynamic in C# 5;
dynamic expando = new ExpandoObject(); expando.x = 10; expando.y = 10; expando.Add = new Func<int>(() => expando.x + expando.y); Console.WriteLine(expando.Add()); // can't really do the array/function variant in the same spirit // I don't think...
I suspect that this will take a little getting used to
Reference: Flanagan, “JavaScript The Definitive Guide”
OMG #8 – Wrappers
Wrapper objects feel a little to me like the process of “boxing” in .NET. In an ideal world, it’d be nice to treat everything in an object-oriented language as an object but it’s impractical to do so for primitive types generally because your performance goes straight out of the window and so languages come up with this idea of object-when-needs-to-be like .NET has with boxing. In JavaScript, this seems to called “Wrapper Objects” and it allows me to treat a primitive like an object when I want to.
// pure primitives var n = 1; var s = "this is a string"; var b = false; console.log(typeof(n)); // number console.log(typeof(s)); // string console.log(typeof(b)); // boolean // wrapped primitives var nW = new Number(1); var sW = new String("this is a string"); var bW = new Boolean(false); console.log(typeof(nW)); // object console.log(typeof(sW)); // object console.log(typeof(bW)); // object console.log(n == nW); // true console.log(s == sW); // true console.log(b == bW); // true console.log(n === nW); // false console.log(s === sW); // false console.log(b === bW); // false
and I guess this doesn’t really seem that different from the C# world;
// string omitted because it's a ref type in .NET int n = 1; bool b = false; Console.WriteLine(n.GetType()); Console.WriteLine(b.GetType()); object nW = n; object nB = b; Console.WriteLine(nW.GetType()); // .NET still says int Console.WriteLine(nB.GetType()); // .NET still says bool // .NET requires the explicit cast to the primitive type Console.WriteLine(n == (int)nW); Console.WriteLine(b == (bool)nB);
although that short sample does already highlight differences and, combined with OMG 7 above about “Expando Objects” I was particularly struck by the example given in Flanagan around;
var myNumber = 1; myNumber.myProperty = "ABC"; // "box" the primitive once. console.log(myNumber.myProperty); // "box" again, different wrapper, undefined
Reference: Flanagan, “JavaScript The Definitive Guide”, Page 43
OMG #9 – Type Conversions
Generally speaking, I hate type conversions much as I hate precedence rules I can never learn tables containing rules so for me an ideal programming language would be one that made everything explicit so I never had to learn any conversion rules or precedence rules – I’m not saying that I’m typical here
JavaScript has a pretty complex list of type conversions that it’s prepared to bring into play on your behalf. Most of them I found pretty intuitive. The way I decided whether they were intuitive or not run down the conversion table with my finger over the results and see if I could just “guess” how it would work.
Here’s the ones that I got wrong and/or found a bit trickier to guess;
var minusZero = new String(-0); console.log(minusZero); // logs 0, not -0 var undefinedNumber = new Number(undefined); console.log(undefinedNumber); // logs NaN var numbers = new Number([1]); console.log(numbers); // this logs 1, not so surprising numbers = new Number([1,2,3]); console.log(numbers); // this logs NaN, a little surprising
but others did seem largely do what I’d expect them to do with the possible caveat that I’d have to remember;
var b = false; var o = new Boolean(b); if (o) { console.log("a little unexpected but, true"); }
Reference: Flanagan, “JavaScript The Definitive Guide”, Page 46/49.
OMG#10 – Object to Primitive Conversions
This feels like a bit of a minefield. Objects convert to booleans very naturally by converting to true for every value that’s not null or undefined so that’s easy enough to “get”.
Converting objects to strings seems simple in that it seems to go via toString() and then if that isn’t appropriate (i.e. doesn’t give some primitive value that can be converted to a string or doesn’t exist) then it goes via valueOf() to try and get to some primitive value;
var o = { x:10 }; o.toString = function() { return("ToString Value is " + this.x); } // logs "ToString Value is x" console.log(o); // break toString by having it return a non-primitive o.toString = function() { return(this); } o.valueOf = function() { return("ValueOf Value is " + this.x); } // logs "ValueOf Value is x" console.log(o);
and so that seems relatively simple as does the conversion to a number which sort of goes the other way around;
var o = { x:10 }; o.valueOf = function() { return(this.x); } // logs this.x ( 10 ) via valueOf console.log(Number(o)); // take valueOf away delete o.valueOf; o.toString = function() { return(String(this.x)); }; // allow toString to kick in // logs "10" via toString console.log(Number(o));
but then there appears to be some built-in behaviours to certain operators (e.g. +) which have their own way of working – need to do a little more digging to understand that fully.
Reference: Flanagan, “JavaScript The Definitive Guide”, Page 50/51.
To be continued – you can find the rest of these “JavaScript OMG!!” entries here.