JavaScript for geeks (Part III)
November 11th, 2003
In which I will talk about object oriented programming and other “serious” techniques.
Pretty much everything in JavaScript is an object. But since it’s a scripting language, it’s mostly used to quickly solve a very specific problem that just needed a little bit of code.
Most people don’t write more than 10 lines of JS code at a time. For those people, creating their own objects doesn’t make much sense.
But if you plan to do anything half serious, or anything remotely reusable (as in remote in time or posibility, not space in the networking sense), learning to use and create objects in JavaScript might be the best thing to do.
I won’t explain object oriented programming here. So if you don’t know a class from an object from an instance, or a superclass from a subclass from an inherited method, I suggest you go read something on that subject first.
The basics of objects
We already said that Hashmaps and objects are the same thing in JS. We said that functions are objects themselves, so they can be “stored” inside another object. And that when you call a function, they always get a pointer, called this, to the object that contains them.
bc. var obj1 = new Object(); obj1.val = 2; var obj2 = new Object(); obj2.val = 5; function test() { return this.val + 1; } obj1.test = test; obj1.test() 3; obj2.pp = test; obj2.pp() 6;
The this pointer is also the “default context” for the function, so you don’t have to use it explicitly. We could have written the test function in the previous example as follows:
bc. function test() { return val + 1; }
However, I recomend using it all the time, because you never know when someone (even yourself) adds an unexpected local variable and your previously unambiguous val is not the same as this.val anymore.
Classes and constructors
To create an instance of a specific class, all we need to do is set the right attributes to the functions and properties we want. However, if we want plan to have more than one instance of our class, we need to define an object constructor to make our lifes easier. That’s what the new operator is for.
bc. var obj = new ClassName();
is equivalent to:
bc. var obj = new Object(); obj.constructor = ConstructorFunction(); obj.constructor(); delete(obj.constructor);
So to define your own object classes, all you need to do is create a new function with the class name you want to use:
bc. function ExampleClass(arg) { this.test = function() { return this.val + 1; }; this.val = arg; } var obj1 = new ExampleClass(5);
The construtor function is not really stored in an attribute called constructor, but there is something similar to that going on behind the scenes.
Classes
JavaScript doesn’t really have classes. Really, it doesn’t, at least not in the sctrict sense of OOP. But it has a set of language constructions that let us do something that looks so much like classes that it doesn’t really matter.
So far, what we’ve actually done with our constructor is to create a Hashmap with some attributes. We can’t really call that a class. For one, it is a waste of memory, since we need to add a pointer for each and every method we want our class instances to have. That’s a lot of redundancy. JavaScript offers the concept of “prototypes”.
Each object has something like a hidden attribute that points to a “prototype object”. If a method cannot be found in an object, it is looked inside it’s prototype. The value for that hidden attribute comes from the prototype attribute of the constructor function object.
bc. function MyClass() { this.test = function() { return 1; }; } MyClass.prototype.test2 = function() { return 2; }; var obj = new MyClass(); obj.test() 1; obj.test2() 2;
Of course, now that we know about prototypes, we wouldn’t have defined test as we did here. We just did it for comparison’s sake.
But at the same time, that example shows the fact that you can always override methods on an object, so JS classes aren’t really the final word.
bc. obj.test = function() { return 3; }; obj.test() == 3;
Inheritance
Since the prototype object is the place to store all your class methods, and since the prototype object is, of course, an object, it can have it’s own prototype.
bc. function SuperClass() {} SuperClass.prototype.init = function() {this.a = 1; };
function MyClass(v) { this.init(v); } MyClass.prototype = new SuperClass(); MyClass.prototype.init(v) { this.b = v; };
Actually, subclass initializers usually should call their superclass initializers too. For that, we use a “trick”, since there is nothing like java’s super() in JS .
bc. MyClass.prototype.init(v) { SuperClass.prototype.init.call(this, v); this.b = v; }
Constructors revisited
There’s a catch to the way JS uses constructors and prototypes. Unlike other OO languages, the superclass constructor is not called for each subclass instance. That’s because the constructor is more of a “prototype setup” that “instance initialization” kind of thing.
So you need to define your own initialization mechanism. Something like this might work:
bc.
More JavaScript for geeks
Part I covers the basics of JavaScript syntax.
Part II deals with variables, contexts, using objects, using functions, function pointers and other related items.
Part IV is a collection of links and other resources about JavaScript.
Deja tu respuesta