Objects And The Dreaded new Keyword

(Pssst! All the code referenced in this post can be found at https://github.com/NerdcoreSteve/objectsandnew, pass it on!)

Ok, I think it's way past time I talk about objects again. (btw here's my old post about them).

This is an object:

const  
    spiderman = {
        firstName: 'Peter',
        lastName: 'Parker',
        homeTown: 'New York'
    }

All an object is is a collection of keys and values. spiderman's keys are firstName, lastName, and homeTown. spiderman's values are 'Peter', 'Parker', and 'New York' respectively.

I can use Object.keys to get spiderman's keys:

console.log(Object.keys(spiderman))  
[ 'firstName', 'lastName', 'homeTown' ]

I can access any object's properties using either the . character or with brackets like these []:

console.log(spiderman.firstName)  
console.log(spiderman['lastName'])  
Peter  
Parker  

Just as with any other value, I can return an object from a function:

    superHero = (firstName, lastName, homeTown) => ({
        firstName, lastName, homeTown
    })

The above uses a little destructuring and other new JavaScript tricks which I've blogged about here. Also, to let JavaScript know this is still a one-liner we need to wrap our return value (the object) in parentheses, otherwise JavaScript thinks this is a multi-line function.

Here's what happens when I call that function:

console.log(superHero('Clark', 'Kent', 'Smallville'))  
{ firstName: 'Clark', lastName: 'Kent', homeTown: 'Smallville' }

What if I wanted to add another key-value pair to that object?

    superHeroWithPowers = (firstName, lastName, homeTown, powers) =>
        Object.assign(
            {},
            superHero(firstName, lastName, homeTown),
            {powers})

console.log(  
    superHeroWithPowers(
        'Linda',
        'Lee', 'Midvale',
        ['flight', 'super strength', 'heat vision', 'ice breath', 'x-ray vision']))
{ firstName: 'Linda',
  lastName: 'Lee',
  homeTown: 'Midvale',
  powers:
   [ 'flight',
     'super strength',
     'heat vision',
     'ice breath',
     'x-ray vision' ] }

Object.assign takes its first argument (in this case an empty object) and as many other objects as you care to give it. It returns the first object but modified, adding all the keys and values from all the other objects to the first object.

Here we're giving Object.assign a new and empty object, a superHero, and an object that has powers as a key and the powers array as a value.

By giving Object.assign a new, empty, object as it's first object, we don't have to worry about mutation and can consider superHeroWithPowers a pure function.

Since JavaScript considers functions to be just another value, you can add a function to an object:

    person = (firstName, lastName) => ({
        firstName,
        lastName,
        fullName: function () {
            return `${this.firstName} ${this.lastName}`
        }
    })

console.log(person('Kermit', 'The Frog').fullName())  
Kermit The Frog  

Why aren't I using a one-line arrow function? because of the this keyword.

this refers to the object a function is attached to. Attached to this are all the other key-value pairs of the object. That's how the function fullName is able to access the object's firstName and lastName properties. But this isn't available in arrow functions.

You should also know that a function attached to an object in this way is also called a method.

I don't recommend it, but you can modify an object in-place:

const  
    somePerson = person('Miss', 'Piggy')

console.log(somePerson.fullName())  
somePerson.firstName = 'Ms'  
somePerson.lastName = 'Pacman'  
console.log(somePerson.fullName())  
Miss Piggy  
Ms Pacman  

Heck, you can give a object properties it didn't have before:

somePerson.shoes = 'Chuck Taylor\'s'  
console.log(somePerson)  
{"firstName":"Ms","lastName":"Pacman","shoes":"Chuck Taylor's"}

Now about that new keyword...

Some folks like to make functions that make objects this way:

    spaceShip = function (type, engine, name) {
        this.type = type
        this.engine = engine
        this.name = name
        this.description = function () {
            return `The ${name} is a ${type} class star ship with a ${engine} engine`
        }
    },

No return statement right? Gross, I know. :P

To make an object with this kind of function we need to use new:

console.log((new spaceShip('galaxy', 'warp', 'Enterprise')).description())  
The Enterprise is a galaxy class star ship with a warp engine  

A lot of people, myself included, don't like to use new. One big reason is that the global variable (global in node, window in the browser) will get clobbered by this kind of function if you forget to use it:

spaceShip('excelsior', 'warp', 'Excelsior')  
console.log(global.description())  
The Excelsior is a excelsior class star ship with a warp engine  

I only mention the new keyword at all because it comes up so often if you use external libraries.

One thing I've not mentioned is object inheritance, and for good reason. Even most object-oriented programmers (people who love the new keyword) don't use it much any more. It's really not necessary and more trouble than it's worth.

See you next time and happy coding! :)

Looking for a software developer?