4. Objects

Objects in JavaScript are simply collections of properties, where each property has a string name (or key) and a value, which can also be a function or any other value. You can think of these objects as equivalent to Python dictionaries.

Note: You may be used to using classes to define objects in Python or Java. JavaScript has no direct analog for classes, though a "class" declaration was introduced in the latest version of JavaScript (ES2015), it works rather differently than Python or Java classes. We will not be covering ES2015 classes here, but you can read more about them here if you are interested.

4.1 Defining Objects

Objects in JS are defined just like dictionaries in Python, using curly braces and pairs of keys and values:

var mustang = {
    make: "Ford",
    model: "Mustang",
    year: 2009,
    isUsed: true,
    makeNoise: function() {
        return "vroom vroom";
    },
};

We can further abstract this away by defining a function to create objects for us (a "constructor"):

function createCar(make, model, year) {
  return {
    make: make,
    model: model,
    isUsed: year !== 2018,
    makeNoise: function() {
      return "vroom vroom";
    },
  };
}

// call it to make a mustang
var mustang = createCar("Ford", "Mustang", 2009);

This is not the only way to create objects in JavaScript, and indeed there is a whole object-oriented paradigm involving something called Object Prototypes that attempts to mimic things like classes and inheritance - things you might be used to if you are coming to JavaScript from a Java/Python/C++ background. We will not cover prototypes, but you can read the MDN documentation on them if you are interested.

4.2 Object Properties

4.2.1 Accessing and Assigning Properties

We can then access object properties in a couple ways:

> mustang.year; // dot notation
2009
> mustang["year"]; // like a dictionary - bracket notation
2009
> var key = "year";
> mustang[key]; // bracket notation again
2009

We can assign object properties in the same ways:

> mustang["topSpeed"]
undefined // uh oh - the object does not have this property!
> mustang["topSpeed"] = 80;
> mustang.topSpeed;
80 // now it does have the property we want.

We can even delete properties from objects using the delete operator:

> delete mustang.topSpeed;
true // property was successfully deleted.
> mustang.topSpeed;
undefined

4.2.2 Iterating Over Properties

There are several ways of iterating over all properties of an object. Starting with the latest version of JavaScript (which all modern browsers should support), we can use the Object.keys(o) function to iterate over all of the own properties of an object o. This function returns an array of all the keys for the own properties of the argument o:

> Object.keys(mustang);
["make", "model", "year", "isUsed", "makeNoise"]

4.3 The this Pointer

The this pointer in JavaScript is a special pointer that we can use inside functions to refer to the enclosing object. For example, suppose we have a function canDrive for our car object that returns whether or not the car can drive at that speed:

var car = {
    //...
    topSpeed: 130,
    canDrive: function(speed) {
        return speed > this.topSpeed;
    },
};
car.canDrive(150); // --> will return false
car.topSpeed = 200;
car.canDrive(150); // --> will return true

In the example, this allows a function defined inside the object to access properties of its enclosing object. It is intended for the same use as the self pointer in Python.

4.3.1 The Behavior of this

The behavior of the this pointer in JavaScript is different than most other programming languages. There are 3 cases that determine what value this is bound to:

4.3.1.1 The Global Scope
this;

When using this in the global scope, it will refer to what's known as the global object, which is typically the window object in web browsers.

4.3.1.2 Calling a Function
someFunction();

The above code may be executed in any context (within another function, in the global scope, in a loop...) and this will still refer to the global object when evaluated inside the body of someFunction.

4.3.1.3 Calling an Object Property
object.someFunction();

In this example, this will refer to object when evaluated inside the body of object.someFunction.

Note: We do not cover object prototypes in this guide, but the new operator also changes the behavior of this so that it refers to the newly created object.

Common Pitfalls

The apparently strange behavior of this was designed to allow for more flexibility in the language. Unfortunately, it can be confusing to get and even experienced JavaScript programmers will fall into the trap of binding this to the wrong thing.

Consider the following code, in which we define a hero character and a function that makes it take damage:

var hero = {
  name: "Gandalf",
  health: 500,
  takeDamage: function(dmg) {
    this.health = Math.max(this.health - dmg, 0);
  },
};

var attacks = [100, 150, 250];
attacks.forEach(hero.takeDamage); // <-- doesn't do what we want!
console.log(hero.health);

The above code is intended to make hero take a total of 100 + 150 + 250 = 500 damage. Instead, it takes no damage whatsoever after executing the code. This is because when we pass in hero.takeDamage as an argument to forEach, the function is then executed as a regular function (see 4.3.1.2) rather than as an object property (see 4.3.1.3). There are a couple ways to fix this; one way is to change what we pass into forEach so that we explicitly call our function as an object property:

attacks.forEach(function(dmg) {
  hero.takeDamage(dmg);
});

The above works, but is a little verbose. Here's a better way: we can bind hero.takeDamage so that whenever this is used inside the function body, it will always refer to what we want it to refer to (the hero object).

attacks.forEach(hero.takeDamage.bind(hero));

The above creates a new function that is identical to hero.takeDamage, but is bound to the hero object permanently. So when we pass it as an argument to forEach, even though the function gets executed as a regular function, since we've bound its this pointer permanently, it will execute as intended.

4.4 Comparing Objects

JS Objects are a reference type. This means that two distinct objects are never equal, even if they have the exact same properties. Only comparing the same object reference with itself returns true.

// Two variables, two distinct objects with the same properties
var fruit = {name: 'apple'};
var fruitbear = {name: 'apple'};

fruit === fruitbear; // --> false
apple = fruit; // apple refers to the same object as fruit
fruit === apple; // --> true

results matching ""

    No results matching ""