elijahr

notes on javascript, linux, and more

11.19.2009

Moving

Moving blog to http://metascopic.tumblr.com

11.11.2009

typeof(null) and Pointers in JavaScript

I had a bit of an epiphany this morning when I was trying to figure out why typeof(null) === 'object' yields true. If you have some value where typeof(value) === "object" and you assign that value to a variable, that variable becomes a reference to that value. If you have some value where typeof(value) === "string" || typeof(value) === "number" || typeof(value) === "boolean", and you assign that value to a variable, that variable now contains a copy of that value rather than a reference. But sometimes, typeof(my_string_variable) === 'object', and assigning that string variable to another variable will create a reference to, not a copy of, that variable's value. Why is that, and why is typeof(null) === 'object' true?

First let's run through some examples to illustrate what I'm talking about.


var
a = 'a',
b = a

a.foo = 'bar'
alert(b.foo) // alerts 'undefined'

a = new Object()
b = a

a.foo = 'bar'
alert(b.foo) // alerts 'bar'


What if I want to create a pointer to a string, a number, or a boolean?


alert(typeof('a')) // alerts 'string'
alert(typeof(true)) // alerts 'boolean'
alert(typeof(1)) // alerts 'number'


So, assigning those values will result in a copy, not a reference. But:


alert(typeof(new String('a'))) // alerts 'object'
alert(typeof(new Boolean(true))) // alerts 'object'
alert(typeof(new Number(1))) // alerts 'object'


What does this mean? It means you can create pointers to JavaScript primitives. This answers my first question. If typeof(value) === 'object' but value is a number, a string, or a boolean value, then you've got yourself a pointer to an object. If you want to assign your object's value to a variable, sans pointer, just use value.valueOf().

You can also check whether some value is a pointer or primitive using instanceof:


alert('a' instanceof String) // alerts false
alert(true instanceof Boolean) // alerts false
alert(1 instanceof Number) // alerts false
alert(new String('a') instanceof String) // alerts true
alert(new Boolean(true) instanceof Boolean) // alerts true
alert(new Number(1) instanceof Number) // alerts true


The below function makes it easy to point to primitive values.


function point(value) { // return a pointer to some primitive value
switch( typeof(value) ) {
case 'string': case 'number': case 'boolean':
return new value.constructor(value)
}
return value
}


Use it like this:


var
my_string = point('a'),
my_string_alias = my_string

my_string.foo = 'bar'
alert(my_string_alias.foo) // alerts 'bar'


It should be noted, that if you pass a variable containing a primitive into point, you will not get a pointer to that primitive; a new object will be created with the value you passed in. Here's an example:


var
my_string = 'a',
my_string_alias = point(my_string)

my_string_alias.foo = 'bar'

alert(my_string.foo) // alerts 'undefined'


One way that this can be resolved is by a simple reassignment of the original variable to the new object:


var
my_string = 'a',
my_string_alias = my_string = point(my_string)

my_string_alias.foo = 'bar'

alert(my_string.foo) // alerts 'bar'


Ok, so now that that has been cleared up, what about my second question: why is typeof(null) === 'object' true? The only thing I can think is that null is a pointer, not a primitive value, and that when typeof returns 'object', it means that the passed in value is a pointer, not a primitive value. Perhaps when I have some time I'll download the TraceMonkey source and grep through the logic in typeof to verify this, but its the best explanation I've found thus far; many JavaScripters seem to consider typeof broken because it returns "object" when a null value is passed in. What's the use all of this information? Well, one use is that we can use this knowledge to check if some value is iterable:


function is_iterable ( value ) {
return value !== null && typeof( value ) === 'object'
}


If is_iterable returns true for some variable or value that you pass in, you are assured that for (var x in value) loops and x in value statements on that value will execute without throwing a TypeError.

I'm sure more knowledgeable JavaScripters than I might take all of this information for granted, but I was unable to find any informed resources on this particular subject in my googlings. I hope that you've found it useful.

9.06.2009

A couple of thoughts

Programming can be a poetry of logic.

An online social network will be unbalanced if there is no competition for points of entry to that social network.

5.06.2009

Multiple Class Inheritance with Prototypes in Javascript

Here is a simple example to demonstrate multiple class inheritance in Javascript. Let's say we are trying to describe a dog named Lily who is is a pit bull & black labrador mix. We can do this by combining a Dog class, a PitBull class, and a BlackLabrador class into a PitLabMix class. Prototyping splits the constructor from the class template, which allows us to inherit from several classes without having to instantiate any of them. In the end, we have an instance of the PitLabMix class named 'lily', which has all the properties of Dog, PitBull, and BlackLabrador. The script makes use of the window.console.log function in Firebug to demonstrate what the final object looks like. For non-Firefox browsers, there is also Firebug Lite.

function Dog (name) {
this.name = name;
}

Dog.prototype = {
kingdom : "Animalia",
subkingdom : "Eumetazoa",
phylum : "Chordata",
subphylum : "Vertebrata",
class : "Mammalia",
subclass : "Theria",
order : "Carnivora",
suborder : "Caniformia",
family : "Canidae",
subfamily : "Caninae",
tribe : "Canini",
genus : "Canis",
species : "C. lupus",
subspecies : "C. l. familiaris"
}

function PitBull (name) {
this.name = name;
for (var x in Dog.prototype)
this[x] = Dog.prototype[x];
}

PitBull.prototype = {
build : "Muscular",
demeanor : "Loyal"
}

function BlackLabrador (name) {
this.name = name;
for (var x in Dog.prototype)
this[x] = Dog.prototype[x];
}

BlackLabrador.prototype = {
"fur color" : "Black"
}

function PitLabMix (name) {
this.name = name;
for (var x in Dog.prototype)
this[x] = Dog.prototype[x];
for (var x in PitBull.prototype)
this[x] = PitBull.prototype[x];
for (var x in BlackLabrador.prototype)
this[x] = BlackLabrador.prototype[x];
}

var lily = new PitLabMix('Lily');
window.console.log(lily);

About Me

My Photo
elijahr
chicago, il, United States
I'm a software engineer by profession. I live with my wife Sarah and our dog Lily in Chicago.
View my complete profile

Labels