According to Wikipedia, JavaScript is:JavaScript is a scripting language most often used for client-side web development. It was the originating dialect of the ECMAScript standard. It is a dynamic, weakly typed, prototype-based language with first-class functions.
What is interesting in the previous definition is that there is no mention of object orientation. While there is nothing that says that you must write OO programs, it definitely one of the most common ways the programs are built these days. While there are other paradigms (functional programming, logic programming, structural programming, ...), JavaScript is nowadays mostly used in either simple imperative/structural or more complex OO-like ways. OO-like and not OO because JavaScript is not OO-capable language. For example, it doesn't support any protection mechanisms - everything is public. It supports something called prototype-based development. However, most people still call it OO - I suppose it's just "good enough".
Classes
Let's take a look at it. I will assume you are using JavaScript from within a standard browser. This is what it is:
function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype.display = function() {
alert('My name is ' + this.name + ' and I am ' + this.age);
}
function main() {
var person = new Person('Foo Bar', 33);
person.display();
}
If you somehow run method 'main' (e.g. by having it in your body onload event), you would see:
My name is Foo Bar and I am 33in a dialog that pops up.
Although there is nothing even resembling a class in the above code if you compare it to e.g. Java classes, the above code actually is a basic example of a JavaScript class. The class is called Person.
Multiple constructors
In JavaScript, you cannot have multiple constructors as in other languages (e.g. C++, Java, C#, Ruby, Scala, ...). The reason for this is that classes are represented as functions. JavaScript doesn't have a concept of method overloading, as e.g. Java has. For example, in Java you can write:
public class MethodOverload {
public void method(int a) {}
public void method(String b) {}
public void method(double[] c) {}
}
The above code means that every instance of MethodOverload class have three methods with the same name. Which one gets called depends on the input parameters. If you would do the following:
MethodOverload mo = new MethodOverload();
mo.method(1);
mo.method("Hi");
mo.method(new double[]{ 1.0d, 2.0d });
then the above three calls would call the methods in order as given in the class definition. method(1) would call method(int a), method("Hi") would call method(String b) and method(new double[]{ 1.0d, 2.0d }) would call method(double[] c).
JavaScript, however, doesn't have this capability. In fact, in JavaScript, you can define multiple functions with the same name, but only the last one will "stick". To demonstrate this, try running the following:
function fun(a) {
alert('first: ' + a);
}
function fun(a) {
alert('second: ' + a);
}
fun(55);
The above code would display 'second: 55'. The interpreter will not even complain - the above code is valid. As if the first function hadn't even existed. You can circumvent this by using either optional named arguments or unnamed arguments. Optional named arguments means that you have one constructor which does all the work, while all other constructors are just the utility constructors for the user to be able to write the shorter code. For example:
function Person(firstName, lastName, sex, age, email, socialSecurityNumber, personalPhone, businessPhone, personalAddress, businessAddress, blogPage) {
this.firstName = firstName;
this.lastName = lastName;
if(typeof(sex) == 'undefined') {
// sex is not given.
this.sexDefined = 'no';
} else {
// sex is given.
this.sexDefined = 'yes';
}
// The same for all other optional arguments.
}
Assume that only firstname and lastName are required. You could instantiate it by:
var person = new Person('Foo', 'Bar');
alert([person.firstName, person.lastName, person.sexDefined]);
var person = new Person('Foo', 'Bar', 'male');
alert([person.firstName, person.lastName, person.sexDefined]);
The above would display 'Foo,Bar,no' and 'Foo,Bar,yes'. For the above two lines, you would accomplish the same thing in Java by writing two constructors:
public class Person {
private String firstName;
private String lastName;
private String sex;
public Person(String firstName, String lastName, String sex) {
this.firstName = firstName;
this.lastName = lastName;
this.sex = sex;
}
public Person(String firstName, String lastName) {
this(firstName, lastName, null);
}
}
The constructor would have to check whether all other things are undefined or not. A small digression - it is not enough to check for null in this case, for example:
function f(a) {
alert([a == null, typeof(a), typeof(a) == 'undefined']);
}
f(1);
f(null);
The above would display:
- f(1) => false, number, false
- f(null) => true, object, false
To check whether the argument is defined, always use typeof, except if you are sure that you will not have nulls as inupts.
The other option for multiple constructors is to use variable arguments:
function f() {
var s = '';
for(var i = 0; i < arguments.length; i++)
s += (i == 0 ? '' : ', ') + i + ': ' + arguments[i];
alert(s);
}
f('a')
f('b', 888)
The above would display:
- f('a') => 0: a
- f('b', 888) => 0: b, 1: 888
Using the above you could make the constructor take any parameter, decide what to do based on the length and types of the arguments, etc. Both options require checking whether the arguments are defined. The variable arguments is even more obscure, since you don't know how to call the constructor, except if you put a comment before it. That is maybe the reason why you don't see too much of these in real life, i.e. one constructor classes are the most common in JavaScript. For that reason, I will stick to one-constructor classes and occasionally use the optional arguments constructors.
Instance variables and methods
Back to the first example:
function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype.display = function() {
alert('My name is ' + this.name + ' and I am ' + this.age);
}
function main() {
var person = new Person('Foo Bar', 33);
person.display();
}
variables are used directly on an object, similar to way you do it in e.g. Java. When you say this.name, it refers to 'name' variable in the current instance. Note, however, that using of 'this' is obligatory, contrary to many situations in Java. When you say person.display(), it calls the method 'display' on the 'person' object, which happens to be the instance of the Person class.
JavaScript is both dynamically and weakly typed. This means that it resolves the type of the object in the runtime and you never supply it in the code. When you say
var person = new Person('Foo Bar', 33);
person.display();
it doesn't say anywhere in the code what person is - this is determined at runtime. You could do, for example, the following:
var person = new Person('Foo Bar', 33);
person = new SomeOtherClass();
person.display();
Depending whether SomeOtherClass has 'display' method, this will either call that method or raise an 'undefined function'-kind of error in JavaScript interpreter.
The same way you can have object methods, you can have object variables defined. This is something similar to class-level initialization in Java:
function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype.display = function() {
alert('My name is ' + this.name + ' and I am ' + this.age + '. I am from ' + this.planet);
}
Person.prototype.planet = 'Earth';
function main() {
var person = new Person('Foo Bar', 33);
person.display();
}
Note that 'planet' is the object-level, not class-level variable. To demonstrate that, try the following in main():
var person1 = new Person('Foo Bar', 33);
person1.planet = 'Mars';
person1.display();
var person2 = new Person('Baz Geez', 22);
person2.display();
person1.planet = 'Jupiter';
person2.planet = 'Neptune';
person1.display();
person2.display();
The output will be:
My name is Foo Bar and I am 33. I am from MarsAs you can see, changing planet of person1 did not have any effect on planet of person2 and vice versa.
My name is Baz Geez and I am 22. I am from Earth
My name is Foo Bar and I am 33. I am from Jupiter
My name is Baz Geez and I am 22. I am from Neptune
Class-level (a.k.a. static) methods and variables
You can have static methods and static variables in JavaScript - just omit the 'prototype' from the definition and that's it. For example:
function Person(name, age) {
this.name = name;
this.age = age;
}
Person.findOldest = function(persons) {
if(persons.length == 0)
return null;
var oldest = persons[0];
for(var i = 1; i < persons.length; i++)
if(persons[i].age > oldest.age)
oldest = persons[i];
return oldest;
}
var persons = [
new Person('Very Young', 10),
new Person('Just Right', 25),
new Person('Middle Age', 50),
new Person('Very Old', 70)
];
var oldest = Person.findOldest(persons);
alert([oldest.name, oldest.age]);
Person class now has 'findOldest' method. This method is a static method. You call it by giving the name of the class: Person.findOldest.
To comment, the previous, this is just a convention. This is again just a consequence that JavaScript is really not OO language. There is nothing wrong if you define the method as:
Person.prototype.findOldest = function(persons) {
...
}
I use the first convention since:
- In the second case, every object would have findOldest, so you couldn't really distinguish what is a static method and what is not
- More typing if you follow another convention (which I do) - static methods should be called with the name of the class instead of the object instance name.
In fact, you could have noticed that '
Person.staticMethods = {};
Person.staticMethods.findOldest = function(persons) {
...
}
Try it - works the same. I omit everything both prototype, staticMethods or whatever else you could put there. It is clear without these qualifications that this is a static method if you always follow this convention (not hard).
The same way works for static variables:
function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype.isAdult = function() {
return this.age >= Person.adultAge;
}
Person.adultAge = 18;
var persons = [
new Person('Very Young', 10),
new Person('Just Right', 25),
new Person('Middle Age', 50),
new Person('Very Old', 70)
];
for(var i = 0; i < persons.length; i++)
alert(persons[i].isAdult());
'adultAge' is a static variable in Person class. The above will output: false, true, true, true, since only 'Very Young' is not adult.
Hope this helped a little. In the next part, I'll write about inheritance.
2 comments:
JS doesn't have classes, it has constructors instead. A little difference :D
This momentousdecree warcraft leveling came as a great beacon light wow lvl of hope to millions of negroslaves wow power level who had been seared power leveling in the flames of power leveling withering wrath of the lich king power leveling injustice.wrath of the lich king power leveling it came as a WOTLK Power Leveling joyous daybreak to end the long WOTLK Power Leveling night ofcaptivity.WOTLK Power Leveling but one hundred years wlk power leveling later, we must face aoc gold the tragic fact thatthe age of conan power leveling negro is still not free. aoc power leveling one hundred years later,age of conan power leveling the lifeof the negro ffxi gil is still sadly crippled by the final fantasy xi gil manacles ofsegregation guild wars gold and the chains of discrimination. one hundred yearslater, maplestory mesos the negro lives on a lonely island of poverty in themidst of a vast ocean of material prosperity.dog clothes one hundred yearslater, the negro is still languishing in the corners of americansociety and finds himself an exile in his own land.
Post a Comment