Learn JavaScript Next – New Array Methods

5.6 Summary

  • 1
    Array.from

    creates an array containing all the values from an array-like object

  • 1
    Array.of

    creates an array with supplied values is safer than

    1
    new Array
  • 1
    Array.prototype.includes

    checks if array contains a value at any of it’s indices

  • 1
    Array.prototype.find

    searches an array based on a criteria function and returns a first value found

  • 1
    Array.prototype.fill

    fills an array with a specified value.

Chapter 6: Object.assign

In this session we will cover:

  • Setting Default Values with object.assign
  • Extending Objects with Object.assign
  • Preventing Mutations When Using Object.assign
  • How Object.assign Assigns Values
1
Object.assign

is one such method. With it we can easily set default values or extend objects in place or as copies all without having to write a lot of boilerplate code to do so.

Priming Exercise: JavaScript objects can inherit properties from another object via the prototype chain. However any given object can only have one prototype. How would you go about devising a way to allow objects to inherit from multiple source objects?

6.1 Setting Default Values with

1
Object.assign


1
2
3
4
5
6
7
8
9
function createMap(options) {
  options = Object.assign({
    width: 900,
    height: 500,
    coordinates: [33.762909, -84.422675]
  }, options)
 
  // ...
}

Using

1
object.assign

is much more terse than our initial approach. The way

1
object.assign

works is, it takes any number of objects as arguments and it assigns all the values from subsequent objects on the first. If any objects contain the same keys, the object in to the right will override the object to the left in the list. This is demonstrated below:


1
2
3
4
5
6
7
let a = { x: 1, y: 2, z: 3 }
let b = { x: 5, y: 6 }
let c = { x: 12 }

Object.assign(a, b, c)

console.log(a)

fig_6-1

When setting defaults like this with

1
Object.assign

we are basically taking objects that are incomplete and filling in the missing values. Another common task is taking objects that are ready complete, and extending them into more customized variations.

6.2 Extending Objects with

1
Object.assign

Another common use case for

1
Object.assign

is to just add some additional properties to an existing object.


1
2
3
4
5
6
7
8
9
10
11
12
13
function createBaseSpaceShip() {
  return {
    if function() {
      // ... fly function implementation
    },
    shoot: function() {
      // ... shoot function implementation
    },
    destroy: function() {
      // ... function for when the ship is destroyed
    }
  }
}

To create a specialized spaceship you just create a copy of a base spaceship and extend it with the specialized features:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// Listing 6.2
function createBomberSpaceShip() {
 let spaceship = createBaseSapceShip()
 
 Object.assign(spaceship, {
   bomb: function() {
     // ... make the ship drop a bomb
   }
 })
 
 return spaceship
}

let bomber = createBomberSpaceShip()
bomber.shoot()
bomber.bomb()

First we create a base spaceship object. Then we use

1
Object.assign

to ad an additional

1
bomb

property. You could create several enhanced spaceships using this technique. This function does have a lot of boilerplate though, so if you were going to reuse this technique you could create a helper function for enhancing the base spaceship:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
function enhancedSpaceShip(enhancements) {
  let spaceship = createBaseSpaceShip()
 
  Object.assign((spaceship, enhancements)
               
  return spaceship
}
               
function createBomberSpaceShip() {
  return enhancedSpaceShip({
    bomb: function() {
      // ... make the ship drop a bomb
    }
  })
}
 
function createStealthSpaceShip() {
  return enhancedSapceShip({
    stealth: function() {
      // ... make the ship invisible
    }
  })
}
 
let bomber = createBomberSpaceShip()
bomber.shoot()
bomber.bomb()

let stealthShip = createStealthSpaceShip()
stealthship.shoot()
stealthship.stealth()

Now we created an

1
enhancedSpaceship

function that takes an object of enhancements as an argument. These enhancements could be new features or override existing features. Notice how in every example so far we have created an object and then mutated it? Sometimes that is desired but often what we want is just a copy.

6.3 Preventing Mutations When Using object.assign

For example, what if in our spaceship example we didn’t have a function for creating a new copy of the base spaceship object. What if we just had a single base spaceship object. If that were the case, every time we call

1
Object.assign

to enhance it, we would be enhancing the base which we don’t want. Instead we would want to make a copy and leave the base unchanged. You may think that

1
const

can help you here but it can’t. Remember,

1
const

only prevent overriding a variable with a new object, but it does not prevent modifying/mutating the existing object.

Since

1
Object.assign

mutates the first object in the parameter list, and leaves the rest of the objects unchanged, a common practice is to make the first object an empty object literal.


1
2
3
let newObject = {}
Object.assign(newObject, {foo: 1}, {bar: 2})
console.log(newObject)

When doing this, it is inconvenient to first create the empty object, then pass it to

1
Object.assign

. Conveniently,

1
Object.assign

also returns the mutated object, so you can shorten it like so:


1
2
3
let newObject = Object.assign({}, {foo: 1}, {bar: 2})

console.log(newObject)

Let’s rewrite out spaceship example to use a single base object and our enhance function to make an enhanced copy:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
// Listing 6.4
const baseSpaceShip = {
  fly: function() {
    // ... fly function implementation
  },
  shoot: function() {
    // ... shoot function implementation
  },
  destroy: function() {
    // ... function for when the ship is destroyed
  }
}

function enhancedSpaceShip(enhancements) {
  return Object.assign({}, baseSpaceShip, enhancements) // By passing {} as the first argument, Object.assign makes a copy
}

function createBomberSpaceShip() {
  return enhancedSpaceShip({
    bomb: function() {
      // ... make the ship drop a bomb
    }
  })
}

function createStealthSpaceShip() {
  return enhancedSpaceShip({
    stealth: function() {
      // ... make the ship invisible
    }
  })
}

Notice how because we abstracted away our enhancement technique into it’s own function, when we modified how it works, we didn’t have to make any changes to the

1
createBomberSpaceShip

or

1
createStealthSpaceShip

.

At this point you may thinking that

1
Object.assign

basically just merge objects from right to left. Well, not exactly, it only assigns values from the left to the right. This minor distinction is what we will discuss next.

How

1
Object.assign

Assigns Values

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.