Objects, properties and methods in JavaScript

Ben Aston
7 min readApr 14, 2015

--

This is part four of a series starting with A brief history of JavaScript.

In my previous post we learned about user-defined types and hoisting in JavaScript; how functions are heavily overloaded to provide scope, types, functions and methods.

We also saw that EcmaScript 6 introduced syntactic sugar for the definition of types — although under the hood nothing really changes.

Finally, we learned that hoisting can be confusing if you are coming from a block-scoped language like C or Java. ES6 brings with it the additional non-hoisted types of variable declaration let and const.

Here, we will look at objects, properties and methods in JavaScript, touching on the prototype chain and “this”.

One of the best parts of JavaScript is the way it makes working with objects and functions easy. There are two “original” ways to make an object, a variation on a theme, and a brand new way added in EcmaScript 5.

First there is the ubiquitous object literal syntax:

var car = { color: 'blue' };

This syntax is widely appreciated for its ease of use. But lacks any encapsulation.

The second approach to object creation is a variation on the theme of the object literal syntax — creating an object factory using a function:

function carFactory(color) {
var car= {};
car.color = color; // For example.
return car;
}
var car = carFactory('blue');

This approach has the benefit of encapsulating the logic for the initialization of the car (because functions define scope).

This approach is so common however, that there is also a similar but terser way to create an object — the new operator:

function Car(color) {
this.color = color;
}
var car = new Car();

By convention we name the constructor function with a capital letter to indicate it should be called with new. There is no need to suffix the name with -Factory. That is implicit.

What new is doing for us here is three-fold:

— first, it is instantiating an object behind the scenes on our behalf (with the appropriate prototype chain, which we will revisit later),

— second, this inside the constructor function is set to the object instance created behind the scenes.

— third, the object instance is returned from the function automatically. We do not need to return anything explicitly from constructor functions called with new.

The final way to create an object instance in JavaScript was added in EcmaScript 5. Object.create returns an object with the prototype chain configured according to the prototype object supplied to it.

You are also able to define properties on the object returned by supplying additional metadata to the function, in the form of an object literal. Like so:

function Car() {}var o = Object.create(Car.prototype, { /* optional own-property definitions */ });
o instanceof Car; //true

A full discussion of Object.create is scheduled for a later posting.

this

Let’s move on to the topic of this. With JavaScript’s weird mix of classic object-orientation, object-based- and functional-programming paradigms, we cannot rely on a straightforward meaning for this.

In short, in JavaScript the value taken by this depends on how a function is called.

This sounds ridiculous, but it is completely true. Consider:

var o = {}, f;o.foo = function() { console.log(this); }
f = o.foo;
o.foo(); // Prints out o.
f(); // Prints out the global object(!)

The JavaScript interpreter actually looks to see how you are invoking a function to determine the value of this at runtime. If you don’t believe me copy the above into your browser console for your self.

But this default behavior can be dangerous.

Setting the value of this to the global object when functions are not invoked as methods is just begging for accidental change to the global object.

Especially in a language with dynamic properties.

For this reason, in 2011 ES5 introduced a “strict mode” that changes the behavior so that in the scenario above, this is set to be the safer undefined instead.

You turn on strict mode by declaring a pragma at the very start of either your code or a function:

(function () {
'use strict';
var o = {}, f; o.foo = function() { console.log(this); }
f = o.foo;
f(); // Prints out undefined.
}());

You can also override the default this value by using Function.prototype.call or Function.prototype.apply to specify the value to use yourself.

Furthermore, Function.prototype.bind will return a wrapper for a function with the value of this “set in stone” and unchangeable from then on.

var o = {}, p = {}, f;o.foo = function() { console.log(this); }
o.foo.call(o); // Prints out o.
o.foo.call(p); // Prints out p.
f = o.foo.bind(o);
f(); // Prints out o.

Object Properties and Methods

Properties can be added and removed dynamically to and from objects like so:

var car = { color: 'blue' };
car.marque = 'Aston Martin'; // Adds a string value property.
delete car.color; // Removes the property named 'color'.

Note that delete is not like delete in C, where memory is freed when it is called.

In JavaScript delete only removes the property from the object. If said property held a reference to an object, then that object will continue to remain in existence if another object refers to it; or it will be garbage collected in the normal manner at some later time.

Properties can be either straightforward values or functions. If a function is a property of an object, it is said to be a method on that object.

Functions in JavaScript can be invoked with as many or as few arguments as you like. Every time a function is invoked a variable named arguments is created behind the scenes that contains all the values sent to a function.

function foo() { // No parameters.
console.log(arguments);
}
foo('a'); // [ 'a' ]
foo('a', 'b'); // [ 'a', 'b' ]

This seems like an oversight until you realize that this gives you the power to write incredibly flexible APIs. For example, the following function, defined with two parameters in its signature, works just fine when invoked with only one argument:

function foo(important, optional) {
console.log(important, optional);
}
foo('a'); // 'a' undefined
foo('a', 'b'); // 'a' 'b'

Inheritance

JavaScript has an unusual implementation of inheritance. It uses prototypical inheritance. This differs from class-based languages where inheritance relationships are defined at compilation-time.

Instead, in JavaScript inheritance hierarchies are defined at runtime — and not on classes but on object instances.

Every function has a property named prototype. This is set to be a plain object instance (with the constructor property set to point to the original function itself).

function Foo() {} // "Akin" to running "var Foo = new Function();"

Merely declaring a function results in a function object being created behind the scenes with a property prototype set to a new object instance.

Foo.prototype instanceof Object; // true
Foo.prototype.constructor === Foo; //true

The prototype object is used when creating instances of the constructor function.

var f = new Foo();

In the above, the new operator has configured the prototype chain. By this I mean it has added a property to the instance f named __proto__ and pointed it to foo.prototype.

f.__proto__ === Foo.prototype

The corollary is that all instances of Foo will now share the same object on their prototype chain: Foo.prototype.

This can be both powerful and dangerous.

Powerful, in that it means that we can achieve a significant saving on memory when instantiating large numbers of objects (for example, object instances might represent a large number of enemies in a game). Dangerous, in that a change to the prototype object will affect all instances of that constructor function.

Object instances can also have their own properties. These are called (unsurprisingly) “own-properties”.

f.bar = function() {};

A change to the own-property bar will only affect instance f.

Summary

Objects and functions are among the best parts of JavaScript. They can be created and modified at runtime, quickly and easily.

There are a number of different ways to create new objects, each of which is useful in different scenarios. Object literals offer a quick and dirty way to create instances; factory functions can be used in conjunction to improve encapsulation.

The new operator makes factory functions terser.

Object.create provides fine-grained control, enabling the setting of property attributes and the prototype chain directly.

JavaScript does not have keywords for specifying the visibility of variables and properties. Instead we need to rely on the scoping system to control visibility. Oftentimes, functions will be used to provide the visibility control we need.

The flexibility and power of the language mean that the straightforward approach taken for this by languages like Java does not suffice for JavaScript. Functions on Function.prototype like call, apply and bind help us control the value of this during function invocations.

Inheritance in JavaScript is unusual. Functions have a prototype property automatically set to an object instance. This object instance is added to the prototype chain of all object instances created by that function.

In this way object instances can share functionality, emulating classical inheritance.

My name is Ben Aston and thank you for reading my post today. I am a London-based JavaScript consultant, available for short-term consultancy globally. I can be contacted at ben@bj.ma.

If you would like to further develop your knowledge of JavaScript you might be interested in my hands-on training course. Full details can be found online at www.learnjavascript.london.

If you enjoyed this piece, please let me know by clicking the “recommend” button below.

You may also be interested in my post on closures in JavaScript.

Made in the United Kingdom

--

--