JavaScript Fundamentals: Objects

JavaScript is an interesting language. It is quite different from any other language I’ve used, and it takes a while to really notice and understand the nuances if you don’t have a good way of learning. I’ve decided to start a Fundamentals series to help push the more basic knowledge out to a wider public, since I’ve noticed many non-expert JavaScript programmers frequenting the blog. Today, we’ll start with Objects.

Everything is an Object (or Acts Like One)

In just about every language there are primitive types: types that are built in that offer the building blocks. In JavaScript, these are numbers, Booleans, and strings. The other types are objects and undefined. Objects allow for composite structures containing properties that can also be any of the types, and you can access these properties using dot notation (e.g. object.property). And because the properties can be objects themselves, properties can be nested several levels deep (e.g. object.propertyLvl1.propertyLvl2.propertyLvl3). Numbers, Booleans, and strings are not objects, _but _they act like objects. By this, I mean that you can use the “dot notation” to access the properties from them, even though they do not technically have properties of their own (e.g. 2.toString()). This works because when you do this, the number is converted to a Number object and then the property is pulled from that object. Strings are converted to String objects and Booleans are converted to Boolean objects. This is a feature that can confuse newcomers but be quite useful to keep the code terse and readable.

Object Literals

There are numerous ways to create objects in JavaScript. One way of doing it that is quite common, which is the only way to create objects in JSON, is with object literals. An object literal looks like this:

1
2
3
4
5
6
7
8
object = {
numberProperty: 1,
stringProperty: "string",
functionProperty: function() {
console.log("You called a function.");
},
booleanProperty: true
}

To start an object literal, you just throw a curly brace up. Once you’re inside you just need to create key-value pairs that are separated with a colon. Then, to add more pairs just add commas between them. Any value can be used, as I said before, including another object, just like this:

1
2
3
4
5
object = {
objectProperty: {
propertyLvl2: "YAY"
}
};

It’s really simple to do, which is why the JSON standard was created from JavaScript’s object literals. People just got sick of the ridiculous number of characters required for XML. JavaScript object literals are just too easy not to use.

You can also add properties to an object later on like this: object.newProperty = "whatever you want".

Prototypes and Inheritance

Literals aren’t the only way to create objects. They can also be created using the new keyword on previously-defined “class” (JavaScript doesn’t have classes. Instead they use constructor functions and prototypal inheritance, which I’ll get to soon. I just refer to them as classes because it’s easier to say), like this: object = new Object();. Object is what you implicitly extend from any time you create a new object. It provides a few properties automatically, which can be helpful, but most of the time is more annoying than anything.

The way you create a “class” is simply by creating a function called a constructor. You name the function starting with a capital letter to signify that it’s a constructor and not a normal function (this is a convention, not a requirement). Inside of this constructor function, the keyword this refers to the instance of the object. Take a look.

1
2
3
var SomeObject = function() {
this.someProperty = 1;
};

Now, when you say new SomeObject() you’ll get a new object that has a property of someProperty with a value of one. You can, of course, do more than just set properties in a constructor function. You can do whatever you would normally do in a function.

Properties don’t need to be set within the constructor though. In fact, it is best practice to use the prototype to set properties, especially if the properties are functions and the class will be extended. Here’s how we add properties to the prototype.

1
2
3
4
5
6
7
8
9
var SomeObject = function() {
// don't bother doing anything
};

SomeObject.prototype.someProperty = "some value"
// or
SomeObject.prototype = {
someProperty: "some value"
}

The prototype is just an object that holds all of the properties that every instance of the object will automatically have when it is created with the new keyword. It is also where inherited methods are put. Let’s create a new class that extends SomeObject.

1
2
3
4
5
6
7
NewObject = function() {};

// Extend NewObject prototype by assigning SomeObject's prototype to it
NewObject.prototype = SomeObject.prototype;

// Now NewObject has all the same prototype methods that SomeObject does, but you could also do this:
NewObject.prototype = new SomeObject();

That makes sure that if any properties are set in the constructor, they are inherited too. This is probably your best bet if you’re extending someone else’s code. Either way, if SomeObject’s prototype is changed, so will NewObject’s prototype because of JavaScript dynamic nature and pointers.

Now we can add our new methods on, or override inherited methods. Note that we can’t assign an object literal to the prototype anymore because it would wipe out the methods we’ve already set or inherited because the entire prototype object would then be set to the object literal, rather than being extended by it.

1
2
3
4
5
NewObject.prototype.newProperty = function(){…};
// Don't do this now
NewObject.prototype = {
aProperty = "some property value"
}

You can use something like Underscore or LoDash to extend classes in a little nicer way (especially if you prefer to use object literals).

1
2
3
4
5
6
7
8
NewObject = function() {};
// Extend NewObject prototype by assigning SomeObject's prototype to it
_.extend(NewObject.prototype, new SomeObject(),{
newProperty: "new property",

// this will override the property inherited from SomeObject
someProperty: "some property"
});

If you’re interested more in how that works, you should check out the API documentation on either of their websites.

Native Prototype “Enhancement”

Being able to dynamically add to a prototype at any time opens up some interesting possibilities: specifically for extending native classes, like String or Boolean. Maybe you want to change how Boolean‘s toString function works. If you make a change to the prototype, every single instance of a Boolean object (or Boolean primitive) will have the changes baked in. All you have to do is this little bit of code right here:

1
2
3
4
5
6
7
8
Boolean.prototype.toString = function() {
// you're supposedly improved function
};

// How about a new function!
Boolean.prototype.couldntDoThisBefore() {
// This is awesome, right?
}

DO NOT DO THIS. I know I just showed you how, so it should be OK to do it, right? Well, I only showed you it because if you didn’t learn it here, you’d learn it somewhere else where they tell you (naively) that it’s ok. Well if you use any third party code or if there’s any possibility that someone might take over maintaining the project in the future (or immediately) then you’ll probably break something because no one expects the behavior to be different.

Well, that’s all I’ve got for now. There’s plenty to digest there and I’ll provide plenty more to think about in future “JavaScript Fundamentals” articles. The next will be on functions, which may or may not be the next post I write. I hope there are at least a few people out there learning something from these basics. God bless and happy coding.

Author: Joe Zimmerman

Author: Joe Zimmerman Joe Zimmerman has been doing web development ever since he found an HTML book on his dad's shelf when he was 12. Since then, JavaScript has grown in popularity and he has become passionate about it. He also loves to teach others though his blog and other popular blogs. When he's not writing code, he's spending time with his wife and children and leading them in God's Word.