Sunday, December 13, 2015

Demystifying JavaScript objects - Part 1 of 3

Basics in JavaScript objects
JavaScript as fascinating as a language it is, needs some demystification when it comes to OOP. Even the best of programmers stumble when it comes to OOP in JS. Why? Language changes on a daily basis there are so many way to achieve same things and best of all, this language is in its metamorphosis to rule the world, if not already done.

People have one or the other editor for JS programming. I have had my luck with 3

  1. Sublime Text
  2. ATOM
  3. Web storm
Of the 3 Webstorm is the best. For small projects/applications, I'd say Sublime Text is easy and not bad. Traditionally, JS is executed as a part of HTML code. But for us in our work, we don't want to do that, why? we want to stay focussed on JS as much as possible. We'd like to write code like how we'd do C#/C++/Java etc. Write code, save it as .JS file, compile and execute. Read the following link, setup, if you like to proceed.


How to set up SublimeText3 for Javascript development?
http://calebgrove.com/articles/js-console-sublime-text

Let's start by creating a simple JavaScript object

 

var person = {
 name: "Krishnan",
 age: 30,
 printInformation: function() {
  return this.name + ", Age: " + this.age;
 }
};


"person" object is defined and available for usage. Object definition in this case was simple. But imagine you are consuming a class from 3rd party libraries or open source frameworks. You may want to look out for properties and methods that are exposed for usage. One way to do that is to look into JS files. But a more prudent approach will be to enumerate exposed properties.

Why not look into file and get a better picture?
JS does not have a very clear delineation for public and private methods/properties/fields. Hence you may be dissuade by what you see. When you enumerate it programmatically, you'll know what's available for you. As you will see down the line, we can define properties that can have their enumeration, configuration properties turned off. Meaning, they will be used for internal purposes. Why worry about them. Hope this explains, why you should enumerate. With that thought in mind, lets move on.

How do I enumerate object for its properties and methods. How do I know if a property I need is defined on the object or not?

console.log("name" in person);

Take a look at the output. We now know if "name" property is defined or not on the object. How do we know if "name" property is defined on person or in any of its base classes?

 console.log(person.hasOwnProperty("name"));

Next question, Are not all objects in Javascript devrived from "Object" class. What are the default methods/properties that my Person class has inherited. I am going to reserve that for another post on Javascript inheritence.

However, I'll give you one answer here. Yes, all objects in JavaScript are derived from Object.

We looked at one property "name" in person. In the real world applications your workers may have many more objects that have hundreds of properties defined on them. How can I find out all properties? More importantly, properties that are defined in the object that I am using.

console.log("Own properties");
for(property in person) {
 console.log("Property: " + property);
}

Alright, I have seen all properties, Can I add or delete properties dynamically? Let me answer delete first. Always start with low hanging fruits!!!

delete(person.age);
console.log("age" in person)

There are times when you as a framework developer will not want to developers to meddle with your object and its properties. In the sense, you don't want to let your objects be extensible or configurable. In other cases you don't want anyone to change the values too. Did I say too many things too fast. Let me slow down, every property, function defined in the object has multiple associated properties that tell us if they are configurable, enumerable or even writable. Following code will help us find that out. If you attempt to configure an object that's not configurable, behavior depends on execution context. If code is executed under strict mode, you'll error out. If its not strict mode, you'll not be able to do waht you intended to do on the object, you'll neither see an error. JS digests the error for you.

Now, how can I enquire for all the properties and its nature?

for(property in person) {
 console.log("Property: " + property);
 console.log('Value: ' + person[property]);
 console.log(Object.getOwnPropertyDescriptor(person, property));
}

OUTPUT

Property: name
Value: Krishnan
{ value: 'Krishnan',
  writable: true,
  enumerable: true,
  configurable: true }
Property: age
Value: 30
{ value: 30,
  writable: true,
  enumerable: true,
  configurable: true }
Property: printInformation
Value: function () {
  return this.name + ", Age: " + this.age;
 }
{ value: [Function],
  writable: true,
  enumerable: true,
  configurable: true }


All right, We are happy to see what is in person object. But is it not weird to find out that name and age properties can be easily manipulated from outside?. People who come from other OOP world despise that.

They are used to concept called "accessors" and "manipulators", hide original definitions under "private" clause. JS does not provide support "private" accessor directly. However, we can code in such a way that we could emulate OO abstraction and encapsulation ideals. To start with lets rename "name" and "age" properties and add getters and setters for the same. How do I define private properties. I'll explain them later in moderator design pattern. Please hold on until then.


var person = {
 _name: "Krishnan",
 get name() {
  return this._name;
 },
 set name(newValue) {
  this._name = newValue
 },
 _age: 30,
 get age() {
  return this._age;
 },
 set age(newValue) {
  this._age = newValue;
 },
 printInformation: function() {
  return this.name + ", Age: " + this.age;
 }
};

person.name = "Krishnan";
person.age = 30;
console.log("Name: " + person.name + "\nAge: " + person.age);

for(property in person) {
 console.log("Property: " + property);
 console.log('Value: ' + person[property]);
 console.log(Object.getOwnPropertyDescriptor(person, property));
}


Yeah, finally, something I always like to see in my class. "getters" and "setters" defined. That sort of helps, but we still have an issue.

Although _name and _age may not be apparent to users, they can still see it, if need be change the value directly on those properties too. Are there are ways to disable them and what are there implications?

Lets' start with making the object less or not extensible

Object.preventExtensions(person);
person.dob = "mm/dd/yyyy";
console.log("Is extensible: " + Object.isExtensible(person));
console.log("Is DOB defined: " + "dob" in person);
console.log("DOB: " + person.dob);

OUTPUT
Is extensible: false
false
DOB: undefined


As you could see, after making the object not extensible or unextensible, we were not able to add new property to person class. I see you smile on this achievement. Though you cannot add a property, we can still delete existing properties. How to curb that?

delete(person.age);
for(property in person) {
 console.log("Property: " + property);
 console.log('Value: ' + person[property]);
 // console.log(Object.getOwnPropertyDescriptor(person, property));
}


Sealing an object

Object.seal(person);

Now lets try to add a new property/function or delete an existing one. We'll not be able to.

What we can still do though is, change value for properties.

Enter the highest security zone. Freeze

Object.freeze(person);

Now we cannot delete or add or modify properties. 

No comments:

Post a Comment