Categories
JavaScript Basics

JavaScript Refactoring Tips — Arrays and Conditionals

JavaScript is an easy to learn programming language. It’s easy to write programs that run and does something. However, it’s hard to write a piece of clean JavaScript code.

In this article, we’ll look at how to clean up conditionals with arrays, and use classList to manipulate class names.

Replacing Long Or Expressions with Array Checks

We can replace long or expressions with array checks easily. For instance, instead of writing:

if (fruit === 'apple' || fruit === 'orange' || fruit === 'grape') {
  //...
}

We can use some array methods to reduce the length of the conditional expression.

One way is to use the array instance’s includes method to do so:

if (['apple', 'orange' ,'grape'].includes(fruit)) {
  //...
}

As we can see, we checked if any one of them is the value of fruit by comparing the value of fruit in an array with includes .

The includes method returns true if the value we passed into the argument is included in the array instance and false otherwise.

Also, we can use the array instance’s some method to check the value:

if (['apple', 'orange', 'grape'].some(a => a === fruit)) {
  //...
}

The some method lets us check if there’s any array entry with the given condition in the callback exists.

It returns true if one or more exists and false otherwise.

We reduced the long conditional expression with arrays in the first example.

Using the classList Property in DOM Elements

The easiest way to check if a class exists in a DOM element and manipulate multiple classes is to use the classList property.

For instance, if we want to add multiple classes, we can write the following code:

const p = document.querySelector('p');
p.classList.add('foo');
p.classList.add('bar');
p.classList.add('baz');

This way, we can add multiple classes without manipulating strings. We just get the classList property of a DOM element object and then call add to add the classes by passing in a string with the class name into the the add method.

The rendered DOM element now has the foo , bar and baz classes.

Likewise, we can call the classList property’s remove method with a string with the class name to remove to remove the class.

For instance, we can write:

const p = document.querySelector('p');
p.classList.add('foo');
p.classList.add('bar');
p.classList.add('baz');
p.classList.remove('baz');

Then the rendered HTML only has the foo and bar classes since we called remove to remove the baz class.

To check if a class name exists in a DOM element object, we can use the contains method.

To use it, we can write:

const p = document.querySelector('p');
p.classList.add('foo');
p.classList.add('bar');
const hasBaz = p.classList.contains('baz');

In the code above, we called the contains method on the classList property to check if the baz class is rendered in the p element.

Since we didn’t add it in the HTML or with the add method, it should return false .

The classList property has the toggle method to toggle class names on and off. For instance, given the following HTML:

<button>
  toggle
</button>
<p>
  foo
</p>

We can use the button to toggle the bar class on and off as follows:

const p = document.querySelector('p');
const button = document.querySelector('button');
p.classList.add('foo');
p.classList.add('bar');

button.onclick = () => {
  p.classList.toggle('bar');
}

In the code above, we called the toggle method in the click handler to toggle the bar class on and off as we click the button. So we should see that in the HTML.

The clasList property has an array-like iterable object called the DOMTokenList object as a value. Therefore, we can use the spread operator to convert it to an array. This should convert it to an array of strings with the class names.

For instance, we can write the following code:

const p = document.querySelector('p');
p.classList.add('foo');
p.classList.add('bar');
const classArr = [...p.classList];

In the code above, we just used the spread operator to spread the classList property into an array.

Then we get that classArr is [“foo”, “bar”] .

Once we converted the DOMTokenList into an array, then we can use any array methods to manipulate the code.

The spread operator makes a copy of the original object and then spread it into an array, so we can still call the methods in the DOMTokenList to manipulate the class names as we want it.

Conclusion

Long boolean expressions with the || operator can be replaced with an array that checks if any of the items in the array matches the value that we’re checking for.

To manipulate multiple class names, we should use the classList property that’s part of a DOM element object. This way, we can add, remove, and toggle classes without having to manipulate strings and set it to the className property ourselves.

Categories
JavaScript Basics

Plain JavaScript of Lodash Array Methods

Lodash is a very useful utility library that lets us work with objects and arrays easily.

However, now that the JavaScript standard library is catching up to libraries such as Lodash, we can implement many of the functions in simple ways.

In this article, we’ll look at how to implement a few Lodash methods with plain JavaScript.

dropRightWhile

The dropRightWhile function lets us create a slice of an array starting from the right until a condition is met. The condition is determined by a callback.

We can implement it as follows with plain JavaScript as follows:

const dropRightWhile = (arr, condition) => {
  const newArr = [];
  for (let i = arr.length - 1; i >= 0; i--) {
    if (condition(arr[i])) {
      return newArr;
    }
    newArr.push(arr[i]);
  }
  return newArr;
}

In the code above, we have a for loop that’s looped through in reverse. If the condition function, which takes an array entry as the value returns true , then we return newArr , which has the items that are pushed into the array that we want to keep.

If the loop finishes without returning newArr , then it’ll also return newArr .

Therefore, when we have:

const arr = [1, 2, 3]
const dropped = dropRightWhile(arr, (a) => a === 2)

We get that dropped is [3] since we stopped the function when the callback condition is met, which is when an array entry is 2.

dropRightWhile can also take a string with the key name to check if it’s true before returning the sliced array.

We can add that check easily with the following code:

const dropWhile = (arr, key) => {
  const newArr = [];
  for (let i = arr.length - 1; i >= 0; i--) {
    if (arr[i][key]) {
      return newArr;
    }
    newArr.push(arr[i]);
  }
  return newArr;
}

Then when we have the following array and call it as follows:

const arr = [{
    name: 'foo',
    active: false
  },
  {
    name: 'bar',
    active: true
  },
  {
    name: 'baz',
    active: false
  }
]
const dropped = dropRightWhile(arr, 'active');

We get:

[
  {
    "name": "foo",
    "active": false
  }
]

since we return the array where we push the entries from the right until active is true .

dropWhile

dropWhile is the opposite of dropRightWhile . It gets a slice of an array by starting from the beginning and pushing those items into a new array, and returning it either when the loop finishes or when the condition in the callback returns true .

Like dropRightWhile , the callback takes an array entry. For instance, we can implement it ourselves as follows:

const dropWhile = (arr, condition) => {
  const newArr = [];
  for (const a of arr) {
    if (condition(a)) {
      return newArr;
    }
    newArr.push(a);
  }
  return newArr;
}

In the code above, we used the for...of loop instead of a regular for loop since we’re just looping through arr forward, which can be done easily with for loop.

dropWhile can also take a string with the key name to check if it’s true before returning the sliced array.

We can add that check easily with the following code:

const dropWhile = (arr, key) => {
  const newArr = [];
  for (const a of arr) {
    if (a[key]) {
      return newArr;
    }
    newArr.push(a);
  }
  return newArr;
}

Then when we have the following array and call it as follows:

const arr = [{
    name: 'foo',
    active: false
  },
  {
    name: 'bar',
    active: true
  },
  {
    name: 'baz',
    active: false
  }
]
const dropped = dropWhile(arr, 'active');

We get:

[
  {
    "name": "foo",
    "active": false
  }
]

since we return the array where we push the entries until active is true .

fill

The fill method fills the element of an array with values from the start but not up to the end index by replacing the values from the original array with the one that we provide starting from a starting index and ending with the end index.

We can implement fill as follows:

const fill = (arr, value, start, end) => arr.fill(valu, start, end)

In the code above, we have 4 arguments like the Lodash’s fill method, which are arr for the original array, value which is the value we want to fill the array with. start , which is the starting index of array entry we’re replacing, and end , which is the end index of the array we’re replacing the values with.

Then when we call the fill as follows:

const filled = fill([1, 2, 3, 4, 5], 8, 0, 3);

We get that filled is:

[8, 8, 8, 4, 5]

As we can see, the array instance’s fill method does the same job as Lodash’s fill .

Conclusion

We can implement dropWhile , dropRightWhile , and fill easily with plain JavaScript’s array methods. With a few lines of code, we eliminated the need to use Lodash array methods.

Categories
JavaScript Basics

ES6 String and Array Methods that Replace Older Methods

JavaScript is one of the most popular programming languages in the world.

This is because, since 2015, JavaScript has added lots of great features that are meant to replace old features from earlier versions.

In this article, we’ll look at ES6 string and array methods that replace earlier methods.


From indexOf to startsWith

ES6 introduced the string’s startsWith instance method that can be used as a replacement for the indexOf method.

For instance, given the following string:

const str = 'foobar';

Then we can replace:

str.indexOf('foo') === 0

With:

str.startsWith('foo')

If we want to check that the string str starts with 'foo'.

startsWith is much shorter than indexOf and we don’t have to check by index.


From indexOf to endsWith

The endsWith method is even more useful than the startsWith method since there was no easy way to check if a string ended with the given suffix.

Without endsWith, we had to write a function like the following:

const endsWith = (str, suffix) => {
  const index = str.indexOf(suffix);
  return index >= 0 &&
    index === str.length - suffix.length;
}

We had to check that the suffix was located in the string with str.indexOf(suffix) by checking that the index was 0 or larger. Then we had to check that the index was located at the end of the string by checking that it was in str.length — suffix.length.

Then given the following string:

const str = 'foobar';

We would write:

endsWith(str, 'bar')

With endsWith, we just write:

str.endsWith('bar')

It’s convenient that we don’t have to define our own function to check if a string ends with a given suffix string.


From indexOf to includes

The includes method introduced with ES6 checks that a string is located in a given string.

Therefore, given the following string:

const str = 'foobarbaz';

We can check if the substring exists in a string by writing:

str.indexOf('bar') >= 0

With ES6, we can instead write:

str.includes('bar')

This is shorter than indexOf.


From Array.prototype.indexOf to Array.prototype.findIndex

ES6 introduced the findIndex array instance method. It’s useful for finding the index of anything. It takes a callback that returns the condition of what we want to search for.

indexOf doesn’t work well with objects because it only finds the object if it’s the same reference as the given one.

For instance, indexOf works great with primitive values like numbers:

arr.indexOf(1)

It’s shorter than using findIndex as follows:

arr.findIndex(a => a === 1)

They both return the index of 1, which is 0.

However, when we’re searching for the index of an object, indexOf isn’t going to work. Given the following array:

If we write:

arr.indexOf({
  name: 'Alex'
})

Then we’ll get -1 because { name: ‘Alex’ } isn’t the same reference as the one in the array.

Therefore, findIndex will be useful here:

arr.findIndex(a => a.name === 'Alex')

This will return 1, which is the correct index because we return a condition that compares the value of the name property.


From Array.prototype.slice() to Array.from() or the Spread Operator

The slice and from instances can both be replaced with the spread operator in most cases.

For instance, we no longer need slice to convert array-like objects to arrays.

If we want to convert the arguments object into an array, instead of writing:

const arr = Array.prototype.slice.call(arguments);

We write:

const arr = [...arguments];

It’s much shorter and we don’t have to call call and pass in arguments as the this value.

In both examples, we get [1, 2, 3] assigned to arr when we have the given function:

function foo() {
  const arr = [...arguments];
}

And call it by writing:

foo(1, 2, 3);

We can also replace most use cases of the Array.from method with the spread operator.

As long as the object we pass into Array.from is an array or another kind of iterable object, we can use the spread operator with it.

Therefore, instead of writing:

function foo() {
  const arr = Array.from(arguments);
}

We can write:

function foo() {
  const arr = [...arguments];
}

The only case where Array.from is useful is when converting objects that have integers as their property identifiers and the length property to an array.

For instance, we can write:

To convert:

To [“foo”, “bar”, “baz”].

We can’t use the spread operator to convert that to an array since it’s not an iterable object.


Conclusion

Aside from a few edge cases, the new ES6 string and array functions are great additions that can be used to shorten code in many places.

The endsWith string instance method saves the most code. Shorter, self-explanatory code is easier on everyone’s brain.

Categories
JavaScript Basics

Plain JavaScript versions of Lodash Array Filtering and Manipulation Methods

Lodash is a very useful utility library that lets us work with objects and arrays easily.

However, now that the JavaScript standard library is catching up to libraries such as Lodash, we can implement many of the functions in simple ways.

We can implement the pullAllBy , pullAllWith , pullAt , and remove methods easily with plain JavaScript.

pullAllBy

The pullAllBy returns an array that removes the given values that matches the items we want to remove after converting them with the iteratee function.

We can implement it as follows:

const pullAllBy = (arr, values, iteratee) => arr.filter(a => !values.map(iteratee).includes(iteratee(a)))

In the code above, we call the given iteratee function to map the values before doing the comparison with includes . Also in includes , we also call iteratee to do the same conversion so that they can be compared properly.

Then we can use our pullAllBy function as follows:

const result = pullAllBy([1, 2.1, 3], [2.2, 3], Math.floor)

And we get [1] for result .

pullAllWith

The Lodash pullAllWith method takes a comparator instead of the iteratee to compare the values to exclude with the comparator instead of an iteratee to convert the values before comparing them.

For instance, we can implement it as follows:

const pullAllWith = (arr, values, comparator) => arr.filter(a => values.findIndex((v) => comparator(a, v)) === -1)

In the code above, we use the plain JavaScript’s findIndex method with a callback that calls the comparator to compare the values.

We call filter to filter out them items that are included with the values array.

Then when we call it as follows:

const result = pullAllWith([1, 2, 3], [2, 3], (a, b) => a === b)

We get [1] for result .

pullAt

The Lodash pullAt method returns an array with the elements with the items with the given indexes.

It also removes the elements in-place with those indexes.

Again, we can use the filter method to filter out the items that we want to remove as follows:

const pullAt = (arr, indexes) => {
  let removedArr = [];
  const originalLength = arr.length
  for (let i = 0; i < originalLength; i++) {
    if (indexes.includes(i)) {
      removedArr.push(arr[i]);
    }
  }

  for (let i = originalLength - 1; i >= 0; i--) {
    if (indexes.includes(i)) {
      arr.splice(i, 1);
    }
  }
  return removedArr.flat()
}

In the code above, we used a for loop to loop through the array and call splice on arr on the items with the given index in the indexes array.

Then we push the removed items into the removedArr array.

We then have and 2nd loop, which loops arr in reverse so that it doesn’t change arr ‘s indexes before we call splice on it.

In the loop, we just call splice to remove the items with the given index.

Finally, we call flat to flatten the array since splice returns an array.

Therefore, when we call it as follows:

const arr = [1, 2, 3]
const result = pullAt(arr, [1, 2])

We see that result is [2, 3] since we specified [1, 2] in the array with the index to remove and arr is now [1] since that’s the only one that’s not removed.

remove

The remove method removes the items from an array in place with the given condition and returns the removed items.

We can implement it ourselves with the for loop as follows:

const remove = (arr, predicate) => {
  let removedArr = [];
  const originalLength = arr.length
  for (let i = 0; i < originalLength; i++) {
    if (predicate(arr[i])) {
      removedArr.push(arr[i]);
    }
  }
  for (let i = originalLength - 1; i >= 0; i--) {
    if (predicate(arr[i])) {
      arr.splice(i, 1);
    }
  }
  return removedArr.flat();
}

In the code above, we have 2 loops as we have with the pullAt method. However, instead of checking for indexes, we’re checking for a predicate .

Like pullAt , we have to loop through the array indexes in reverse to avoid splice changing the indexes as we’re looping through the items of arr .

Then when we call remove as follows:

const arr = [1, 2, 3]
const result = remove(arr, a => a > 1)

We get that result is [2, 3] and arr is [1] since we specified that the predicate is a => a > 1 , so anything bigger than 1 is removed from the original array and the rest are returned.

Conclusion

The pullAt and remove methods are very similar, except that pullAt takes an array of index and remove takes a callback with the given condition.

pullAllBy and pullAllWith are implemented with the filter method. pullAllBy also needs to map the values with the iteratee function before doing comparisons.

Categories
Vue

How to render an array of data in Vue

Vue.js is an easy to use web app framework that we can use to develop interactive front end apps.

In this article, we’ll look at how to render lists with thev-for directive.

Using v-for to Map Array to Elements

We can use the v-for directive to render a list of items from an array.

For example, we can use it as follows:

src/index.js :

new Vue({
  el: "#app",
  data: {
    persons: [{ name: "Joe" }, { name: "Jane" }, { name: "Mary" }]
  }
});

index.html :

<!DOCTYPE html>
<html>
  <head>
    <title>App</title>
    <meta charset="UTF-8" />
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  </head>

  <body>
    <div id="app">
      <div v-for="person in persons">
        {{person.name}}
      </div>
    </div>
    <script src="src/index.js"></script>
  </body>
</html>

In the code above, we have the v-for directive, and then we write person in persons to loop through the data.persons array.

Then we get the name property from each entry and display it.

person is an alias for the array element being iterated on.

Then we get:

Joe

Jane

Mary

All the properties of the array entry is available during iteration.

We can also add an optional second argument to access the index of the array. For example, we can write the following:

src/index.js :

new Vue({
  el: "#app",
  data: {
    persons: [{ name: "Joe" }, { name: "Jane" }, { name: "Mary" }]
  }
});

index.html ;

<!DOCTYPE html>
<html>
  <head>
    <title>App</title>
    <meta charset="UTF-8" />
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  </head>

  <body>
    <div id="app">
      <div v-for="(person, index) in persons">
        {{index}} - {{person.name}}
      </div>
    </div>
    <script src="src/index.js"></script>
  </body>
</html>

Then we get:

0 - Joe

1 - Jane

2 - Mary

We can also use of instead of in to match the for...of loop syntax in JavaScript:

<!DOCTYPE html>
<html>
  <head>
    <title>App</title>
    <meta charset="UTF-8" />
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  </head>

  <body>
    <div id="app">
      <div v-for="person of persons">
        {{person.name}}
      </div>
    </div>
    <script src="src/index.js"></script>
  </body>
</html>

Photo by Jens Kreuter on Unsplash

v-for with an Object

We can also use v-for to loop through the values of an object.

So if we write the following:

src/index.js :

new Vue({
  el: "#app",
  data: {
    book: {
      title: "JavaScript Book",
      author: "John Smith",
      publishedYear: 2019
    }
  }
});

index.html :

<!DOCTYPE html>
<html>
  <head>
    <title>App</title>
    <meta charset="UTF-8" />
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  </head>

  <body>
    <div id="app">
      <div v-for="value in book">
        {{value}}
      </div>
    </div>
    <script src="src/index.js"></script>
  </body>
</html>

And we get:

JavaScript Book

John Smith

2019

We can loop through the keys of the object by providing a second argument to the expression as follows:

src/index.js :

new Vue({
  el: "#app",
  data: {
    book: {
      title: "JavaScript Book",
      author: "John Smith",
      publishedYear: 2019
    }
  }
});

index.html :

<!DOCTYPE html>
<html>
  <head>
    <title>App</title>
    <meta charset="UTF-8" />
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  </head>

  <body>
    <div id="app">
      <div v-for="(value, key) in book">
        {{key}} - {{value}}
      </div>
    </div>
    <script src="src/index.js"></script>
  </body>
</html>

Then we get:

title - JavaScript Book

author - John Smith

publishedYear - 2019

Also, we can provide a third argument for the index of the object entry.

To do this, we can write:

src/index.js:

new Vue({
  el: "#app",
  data: {
    book: {
      title: "JavaScript Book",
      author: "John Smith",
      publishedYear: 2019
    }
  }
});

index.html :

`<!DOCTYPE html>
<html>
  <head>
    <title>App</title>
    <meta charset="UTF-8" />
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  </head>

  <body>
    <div id="app">
      <div v-for="(value, key, index) in book">
        {{index}}: {{key}} - {{value}}
      </div>
    </div>
    <script src="src/index.js"></script>
  </body>
</html>

Then we get:

0: title - JavaScript Book

1: author - John Smith

2: publishedYear - 2019

The order of iteration over an object is based on the enumeration order of Object.keys() , which isn’t guaranteed to be consistent across JavaScript engine implementations.

Maintaining State

v-for by default updates the items in place instead of moving the DOM elements to match the order of the items to make sure it reflects what should be rendered at a particular index.

Therefore, it’s only suitable when the list doesn’t rely on child component state or temporary DOM state like input values.

To make sure Vue knows which elements are unique, we should provide a key attribute via the v-bind:key directive.

For example, we can write:

src/index.js :

new Vue({
  el: "#app",
  data: {
    persons: [{ name: "Joe" }, { name: "Jane" }, { name: "Mary" }]
  }
});

index.html :

<!DOCTYPE html>
<html>
  <head>
    <title>App</title>
    <meta charset="UTF-8" />
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  </head>

  <body>
    <div id="app">
      <div v-for="person in persons" v-bind:key="person.name">
        {{person.name}}
      </div>
    </div>
    <script src="src/index.js"></script>
  </body>
</html>

We have to use primitive values as keys.

The key attribute is a generic mechanism for Vue to identify nodes.

Conclusion

We can use v-for to iterate through entries of an array or entries of an object and render the entries.

To use it to render arrays, we can either use in or of . Also, we can access the index of an array entry with v-for .

To iterate through objects, we can do the same thing, except that the first argument is the value of a property, the second argument is the key and the third is the index.

Only the first argument is required in each case.

The key attribute can be set so the Vue can identify unique nodes. We can set it to a primitive value with v-bind:key .