"Simplicity" aka Maks's guide to Javascript for Java programmers Part I
Javascript (hence forth JS) in its current v1.5 (Ecma262 ) incarnation is a great small, powerful scripting language. A lot of Java developers seem to now be realising this (I'm a convert of about a year now) and given the similarities between the 2 languages might get tripped up.
Also its very easy for new comers to get confuse between what's in the JS language and what is provided by the web browsers that host the JS runtime that most people use JS in (but not all! Actionscript in Flash is a implementation of Ecmascript and you can use JS very nicely on the server-side)
So here is my attempt at slightly damping down the learning curve.
Lets start with the basics:
BUT objects do have a prototype. An objects prototype is really just a special key in the object that points to another object, where the JS interpreter will look for a property requested for the current object but not found in the current object. If this sounds a bit a simple form of inheritance - it is, BUT just don't get carried away and start thinking its the same as inheritance in Java.
In fact the truth is that JS is a "new" operator that will create a new "plain" object and then pass it to the function you give it as the argument to "new", calling that function with the newly created object as its context (which just means the newly created object is set to "this" for the function call)
So a line of JS like this:
in psuedo code is something like:
make a new object
call a function named "Person" with the "this" reference set to the new object
set the prototype property of the new object to point to the Person function object
assign the new object to the variable "me"
So really there is nothing special about the function Rectangle except that we have written it with a view to using as a constructor but any function object can be called as an argument to the new operator - its just that it only makes sense for those that actually do something useful with their "this" reference - like initialising some properties, eg:
Lexical scope just means scope of where functions are defined, not where they are called. Ok that doesn't help much, so maybe this will:
Remember that call object I just talked about? well its actually the start of a "chain" (ie. ordered list) of objects that gets passed to a function to set its scope. So when you try to reference a variable in a function, JS looks through this chain to find the variable you are referring to. So what other objects are in this chain after the call object? Well its all the previous call objects.
So for a function defined in the global scope, its just the Global object.
And for a function called from with another function its just the Global object! That's right, because as I said at the start, lexical scope is about where the function is defined not where its called from. This means that this magic "scope chain" is set-up when the JS interpreter sees the definition of a function and is not changed when a function is actually called somewhere down the track!
Which brings us to:
Well see if this helps:
But if you remember that b()'s scope chain is setup at "definition time" it all makes perfect sense! Since at definition time b() got a()'s call object added to its scope chain (which contains the property/value "x = 2") and it keeps that scope chain forever (or at least til we reload the web page :-)
Now to finish off belabouring this point, keep in mind that the objects in the scope chain (for the most part) are just JS objects. So for instance there's no reason why we can't change the values of their properties, say by using var x as a counter...
So essentially var x in the call object of b()'s scope change is a lone "relic" of a()'s existence when the definition of b() was first processed but because all references to a() function object are gone, the x that b() is seeing in its scope chain is its own "private" variable, which brings us to:
Yep you read that right, since JS looks up property names it can't find in the current object, in the object assigned to its prototype property (and then if it can't find it there, in its prototype object, and so on) and at the time the property is used, you can assign properties to a prototype and all the objects which reference that object as their prototype will see the new property.
And since JS is intended to be used as an embedded scripting language its assumed that the host environment (eg, web-browser, web-server) will provide the required objects with lots of useful methods defined.
Well that's about it for quick run through, of course there's lots more and the best place to find it is the JS book, with the big rhino on the front.
Also its very easy for new comers to get confuse between what's in the JS language and what is provided by the web browsers that host the JS runtime that most people use JS in (but not all! Actionscript in Flash is a implementation of Ecmascript and you can use JS very nicely on the server-side)
So here is my attempt at slightly damping down the learning curve.
Lets start with the basics:
- Almost everything is an Object.
- Objects are essentially Maps (i.e. collections of name, value pairs)
- The name, value pairs are an objects properties.
- There are NO classes.
BUT objects do have a prototype. An objects prototype is really just a special key in the object that points to another object, where the JS interpreter will look for a property requested for the current object but not found in the current object. If this sounds a bit a simple form of inheritance - it is, BUT just don't get carried away and start thinking its the same as inheritance in Java.
- There are only a few built-in data types: Object, Array, Number, String, Function.
- Objects have methods
- Everything (almost) is an object. Hence there are no "primitives" like Javas int, bool, etc. This means that is if you have a numeric literal, its a literal Number object and you can do stuff like:
(42.1).toFixed(1) - Objects can have a constructor function.
In fact the truth is that JS is a "new" operator that will create a new "plain" object and then pass it to the function you give it as the argument to "new", calling that function with the newly created object as its context (which just means the newly created object is set to "this" for the function call)
So a line of JS like this:
var me = new Person();
in psuedo code is something like:
make a new object
call a function named "Person" with the "this" reference set to the new object
set the prototype property of the new object to point to the Person function object
assign the new object to the variable "me"
So really there is nothing special about the function Rectangle except that we have written it with a view to using as a constructor but any function object can be called as an argument to the new operator - its just that it only makes sense for those that actually do something useful with their "this" reference - like initialising some properties, eg:
function Rectangle (firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}- Global variable are really just properties of the Global object
- Functions can have local variables.
- Functions have lexical scope.
Lexical scope just means scope of where functions are defined, not where they are called. Ok that doesn't help much, so maybe this will:
Remember that call object I just talked about? well its actually the start of a "chain" (ie. ordered list) of objects that gets passed to a function to set its scope. So when you try to reference a variable in a function, JS looks through this chain to find the variable you are referring to. So what other objects are in this chain after the call object? Well its all the previous call objects.
So for a function defined in the global scope, its just the Global object.
And for a function called from with another function its just the Global object! That's right, because as I said at the start, lexical scope is about where the function is defined not where its called from. This means that this magic "scope chain" is set-up when the JS interpreter sees the definition of a function and is not changed when a function is actually called somewhere down the track!
Which brings us to:
- Function can be defined within other functions.
Well see if this helps:
function a() {
var x = 2;
function b() {
var y = 3;
return y + 2;
}
return b;
}
var func = a();
a = null;
alert("The answer is:"+ func());
Whack that in a html page and what do you think you will get? Yep 5! But stop and think about it for a second - b() is defined inside a() but it uses a property belonging to a when its called in the alert box after a() has already returned and after we set a to null, so it not even defined in the global scope any more !But if you remember that b()'s scope chain is setup at "definition time" it all makes perfect sense! Since at definition time b() got a()'s call object added to its scope chain (which contains the property/value "x = 2") and it keeps that scope chain forever (or at least til we reload the web page :-)
Now to finish off belabouring this point, keep in mind that the objects in the scope chain (for the most part) are just JS objects. So for instance there's no reason why we can't change the values of their properties, say by using var x as a counter...
function a() {
var x = 0;
function b() {
return x++;
}
return b;
}
var func = a();
a = null;
alert("The first answer is:"+ func());
alert("The second answer is:"+ func());
So essentially var x in the call object of b()'s scope change is a lone "relic" of a()'s existence when the definition of b() was first processed but because all references to a() function object are gone, the x that b() is seeing in its scope chain is its own "private" variable, which brings us to:
- Functions are closures
- Because functions are actually objects they can themselves have properties.
function Person() {
...
}
mrJS = new Person("Brendan", "Eich");
Person.fullName = function() { return (this.firstName+" "+this.lastName);}
alert("JS Creator: "+mrJS.fullName());
Yep you read that right, since JS looks up property names it can't find in the current object, in the object assigned to its prototype property (and then if it can't find it there, in its prototype object, and so on) and at the time the property is used, you can assign properties to a prototype and all the objects which reference that object as their prototype will see the new property.
- There are some handy predefined objects, with handy methods: eg. Date, Math
And since JS is intended to be used as an embedded scripting language its assumed that the host environment (eg, web-browser, web-server) will provide the required objects with lots of useful methods defined.
Well that's about it for quick run through, of course there's lots more and the best place to find it is the JS book, with the big rhino on the front.
Labels: helma, javascript

1 Comments:
Maks, thanks for writing this! I've been thinking that the Helma projects needs different introductions like this for people coming from a different background, much like you've done here for Javascript and Java people.
Post a Comment
<< Home