In my previous post we looked at creating classes by literal notation, there are other ways to create classes. One other way is FUNCTIONS
In this post we will take a look at more traditional approach. In addition we will also see mysteries around prototype. I'd rather say PROTOTYPE as a hidden treasure in JavaScript. Once you get a hang of prototype, you'll see how easy it is for you to do OO development. Magic by which your code will be super awesome.
Lets start by creating a simple class. Notice upper case letter for function name. It conveys, it is a constructor. Sure you'll get used it as you do more code.
The way we instantiate this class is with "new" keyword. That's something all of us know of. Is it not how we allocate space for our instances in other high level programming languages. Phew! For once JavaScript struck to something we now of from our earlier programming lessons. Now you wonder, what happens if you miss "new" keyword? In that case name and age get to have a global scope and you assign values to a global scope variable, and not to class scope variables.
A good framework developer would not allow such cracks in his framework. We can fix that by following some good practices in code. Will show you how in later posts, for now, lets not digress. Focus right back on OOP
We defined properties name and age without specifying how they will behave, are they writable, enumerable or configurable. If you need finer control, here's another way do it.
We created 2 properties, added getters and setters. Look into the output. We see all items defined in the class.
My 5 cents, care to hear? One reason I prefer creating classes the non-function way is, with the above definition, the following lines may surprise you
You'd have expected the last line to say [object], given that your conventional wisdom from other high level programming languages dictate this to be a class. Since the constructor we defined is a Function, prototype of Person comes back as Function.
Adding more functionality
So far we defined a simple class, added properties to it. How about adding functionality or functions? In comes 'prototype'. Every instance of a class in JavaScript has a proverbial property "prototype". This property points to the prototype of current instance. What else can that be, other than its class definition.
From our sample code above, person1's prototype will be Person. Every definition in Person will be available to all its instances through prototype property. Each time we invoke a method on an instance, JavaScript uses a familiar recursive pattern to locate method definition, starting from current class. Search begins for the prototype property on current instance, if found, search operation is terminated. Else, looks for the prototype property on it base class, cycle continues, until property/method is located or it has reached top of hierarchy i.e. Object. This functionality and resolution is akin to how inheritence pattern works in high-level programming languages.
Alright, back to our prototype story. Every function defined on Person prototype will be available to all instances of Person class. Think of prototype property as a pointer. person1's prototype pointer does not contain all the definition, it rather points to where the definition will be. That can be nothing but location of Person class. This also means, any changes to Person's prototype will impact on all Person instances. With power, also comes responsibility.
As as many instances as we have on Person, all of them will have access to "printInformation". Next obvious question is, can I add more functions in one go with this syntax or within this code block?
ABSOLUTELY, you can, but with a gotcha. Lets start with what we have and then come back to gotcha in a bit.
You did add multiple functions with ease, one thing to note is constructor parameter. In our earlier declarations, we added to prototype, but in here we are redefining prototype. Hence we have to make sure constructor property is defined. That's the only way we can have inheritance hierarchy defined or stop it from breaking (That's the gotcha.). Try removing that parameter and see what happens. You may be in for some surprise. In the worst case, it well tell you something more about JavaScript classes and objects.
Have fun working on prototype, our next hop will be inheritence
In this post we will take a look at more traditional approach. In addition we will also see mysteries around prototype. I'd rather say PROTOTYPE as a hidden treasure in JavaScript. Once you get a hang of prototype, you'll see how easy it is for you to do OO development. Magic by which your code will be super awesome.
Lets start by creating a simple class. Notice upper case letter for function name. It conveys, it is a constructor. Sure you'll get used it as you do more code.
function Person(name, age) {
this.name = name;
this.age = age;
}
var person1 = new Person("Krishnan", 35);
console.log(person1.name + ", " + person1.age);
The way we instantiate this class is with "new" keyword. That's something all of us know of. Is it not how we allocate space for our instances in other high level programming languages. Phew! For once JavaScript struck to something we now of from our earlier programming lessons. Now you wonder, what happens if you miss "new" keyword? In that case name and age get to have a global scope and you assign values to a global scope variable, and not to class scope variables.
A good framework developer would not allow such cracks in his framework. We can fix that by following some good practices in code. Will show you how in later posts, for now, lets not digress. Focus right back on OOP
We defined properties name and age without specifying how they will behave, are they writable, enumerable or configurable. If you need finer control, here's another way do it.
function Person(name, age) {
this._name = name;
this._age = age;
Object.defineProperty(this, "name", {
get: function() {
return name;
},
set: function(newValue) {
name = newValue;
},
configurable: true,
enumerable: true
});
Object.defineProperty(this, "age", {
get: function() {
return age;
},
set: function(newValue) {
age = newValue;
},
configurable: true,
enumerable: true
});
}
var person = new Person("Krishnan", 35);
console.log(person.name + ", " + person.age);
for(property in person) {
console.log(Object.getOwnPropertyDescriptor(person, property));
}
OUTPUT
Krishnan, 35
_name
{ value: 'Krishnan',
writable: true,
enumerable: true,
configurable: true }
_age
{ value: 35,
writable: true,
enumerable: true,
configurable: true }
name
{ get: [Function],
set: [Function],
enumerable: true,
configurable: true }
age
{ get: [Function],
set: [Function],
enumerable: true,
configurable: true }
[Finished in 0.1s]
We created 2 properties, added getters and setters. Look into the output. We see all items defined in the class.
My 5 cents, care to hear? One reason I prefer creating classes the non-function way is, with the above definition, the following lines may surprise you
console.log(typeof(person1));
console.log(person1 instanceof Person);
console.log(Object.getPrototypeOf(Person));
OUTPUT
object
true
[Function]
You'd have expected the last line to say [object], given that your conventional wisdom from other high level programming languages dictate this to be a class. Since the constructor we defined is a Function, prototype of Person comes back as Function.
Adding more functionality
So far we defined a simple class, added properties to it. How about adding functionality or functions? In comes 'prototype'. Every instance of a class in JavaScript has a proverbial property "prototype". This property points to the prototype of current instance. What else can that be, other than its class definition.
From our sample code above, person1's prototype will be Person. Every definition in Person will be available to all its instances through prototype property. Each time we invoke a method on an instance, JavaScript uses a familiar recursive pattern to locate method definition, starting from current class. Search begins for the prototype property on current instance, if found, search operation is terminated. Else, looks for the prototype property on it base class, cycle continues, until property/method is located or it has reached top of hierarchy i.e. Object. This functionality and resolution is akin to how inheritence pattern works in high-level programming languages.
Alright, back to our prototype story. Every function defined on Person prototype will be available to all instances of Person class. Think of prototype property as a pointer. person1's prototype pointer does not contain all the definition, it rather points to where the definition will be. That can be nothing but location of Person class. This also means, any changes to Person's prototype will impact on all Person instances. With power, also comes responsibility.
Person.prototype.printInformation = function() {
console.log("Name: " + this.name + ", Age: " + this.age);
}
console.log(person1.printInformation());
As as many instances as we have on Person, all of them will have access to "printInformation". Next obvious question is, can I add more functions in one go with this syntax or within this code block?
ABSOLUTELY, you can, but with a gotcha. Lets start with what we have and then come back to gotcha in a bit.
function Person(name, age) {
this.name = name;
this.age = age;
};
Person.prototype = {
constructor: Person,
printInformation : function() {
console.log("Name: " + this.name + ", Age: " + this.age);
},
canDrinkBeer: function() {
return (this.age > 18);
}
};
You did add multiple functions with ease, one thing to note is constructor parameter. In our earlier declarations, we added to prototype, but in here we are redefining prototype. Hence we have to make sure constructor property is defined. That's the only way we can have inheritance hierarchy defined or stop it from breaking (That's the gotcha.). Try removing that parameter and see what happens. You may be in for some surprise. In the worst case, it well tell you something more about JavaScript classes and objects.
Have fun working on prototype, our next hop will be inheritence
No comments:
Post a Comment