Categories
Lodash

Learning JavaScript by Implementing Lodash Methods — Object Traversal

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 some methods for traversing through object keys.

forOwn

The Lodash forOwn method iterates through an object’s own enumerable string keyed properties and run the iteratee function on each property.

The iteratee takes 3 arguments, which are value , key and object . where value is the value of the property that’s being looped through. key is the property key string, object is the object that’s being traversed.

We can get all the object’s keys with the Object.keys method as an array, so we can loop through the keys as follows:

const forOwn = (obj, iteratee) => {
  for (const key of Object.keys(obj)) {
    const result = iteratee(obj[key], key, obj);
    if (result === false) {
      break;
    }
  }
}

In the code above, we called Object.keys with obj to get the own keys of obj . Then we call iteratee with the value by referencing obj[key] as the 1st argument, key as the 2nd argument, and obj as the 3rd argument.

iteratee is called on each iteration and its return value is set as the value of result .

Then when we call it as follows:

function Foo() {
  this.a = 1;
  this.b = 2;
}

Foo.prototype.c = 3;

forOwn(new Foo(), (value, key) => console.log(key));

We get a and b from the console log output since a and b are the Foo ‘s instance’s own property, but c is an inherited property from Foo ‘s prototype.

forOwnRight

Lodash’s forOwnRight method is like forOwn except that it loops through the object’s keys in reverse order.

We can just change forOwn ‘s implementation slightly by calling reverse on the array returned by Object.keys to loop through the keys in reverse.

For instance, we can implement that as follows:

const forOwnRight = (obj, iteratee) => {
  for (const key of Object.keys(obj).reverse()) {
    const result = iteratee(obj[key], key, obj);
    if (result === false) {
      break;
    }
  }
}

In the code above, we have the same implementation as forOwn except that we called reverse after Object.keys .

Then when we call it as follows:

function Foo() {
  this.a = 1;
  this.b = 2;
}

Foo.prototype.c = 3;

forOwnRight(new Foo(), (value, key) => console.log(key));

We see b then a logged in the console log output.

functions

The functions method returns the array with the property names of own properties that are function valued.

We can implement that ourselves by checking whether the given property has type function and put it in the returned array.

For instance, we can do that as follows:

const functions = (obj) => Object.entries(obj).filter(([key, value]) => typeof value === 'function').map(([key]) => key);

In the code above, we used Object.entries to get the key and value of each property of obj as a nested array with each entry as an array of the key and value.

Then we called filter on what’s returned by Object.entries by destructuring the given key and value on each entry, and then return whatever value has the 'function' type by checking value with the typeof operator.

Next, we called map on with the key destructured from the array to return the keys only and put them in the returned array.

Then when we have a Foo constructor and call it with the Foo instance as follows:

function Foo() {
  this.a = () => 'a';
  this.b = () => 'b';
}

Foo.prototype.c = () => 'c';

const result = functions(new Foo());

We get that result is [“a”, “b”] since in the Foo instance, only 'a' and 'b' are function valued own properties.

Conclusion

To implement the forOwn and forOwnRight Lodash methods, we can use the Object.keys method to get all the keys and then use the for...of loop to loop through the own keys of the given object.

The functions method can be implemented by calling Object.entries to get the keys and values of an object as an array.

Then we can call the filter method with the typeof operator to check the ones that value type 'function' . Then we can get the keys of the function valued properties and return an array with them with map.

Categories
Lodash

Learning JavaScript by Implementing Lodash Methods — Converting Objects

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 Lodash methods to convert objects.

toArray

The Lodash toArray method transforms a given value to an array.

For instance, we can implement as follows:

const toArray = val => {
  if (val instanceof String || typeof val === 'string') {
    return val.split('');
  } else if (val instanceof Object) {
    return Object.values(val)
  }
  return [];
}

In the code above, we checked if val is a string by using the instanceof operator for strings created with the String constructor and use the typeof operator to check for primitive strings.

Then we split the strings into with the split method in this case.

If val is an object, then we return the values with Object.values .

Otherwise, we return an empty array.

Then we can call it as follows:

console.log(toArray({
  'a': 1,
  'b': 2
}));

console.log(toArray('abc'));

console.log(toArray(1));

console.log(toArray(null));

The first call should return [1, 2] , the 2nd returns ['a', 'b', 'c'] , and the last 2 return an empty array.

toFinite

Lodash’s toFinite method converts values to finite values.

We can do that by checking for Infinity and -Infinity and then returning the finite values accordingly.

For instance, we can write the following function to do that:

const toFinite = (val) => {
  if (val === Infinity) {
    return Number.MAX_VALUE
  } else if (val === -Infinity) {
    return -Number.MAX_VALUE
  }
  return isNaN(val) ? 0 : +val;
}

In the code above, we checked if val is Infinity or -Infinity and return Number.MAX_VALUE and — Number.MAX_VALUE respectively.

Otherwise, we use the isNaN function to check is val can be converted to a number. The isNaN function tries to convert the argument into a number before checking if the converted value is NaN or not.

If it’s not NaN , then we return val converted to a number. Otherwise, we return 0.

Then we can call it as follows:

console.log(toFinite(3.2));
console.log(toFinite(Number.MIN_VALUE));
console.log(toFinite(Infinity));
console.log(toFinite('3.2'));

Then we get:

3.2
5e-324
1.7976931348623157e+308
3.2

from the console log output.

toInteger

Lodash’s toInteger method converted the given value to an integer.

We can implement our own toInteger function as follows:

const toInteger = (val) => {
  if (val === Infinity) {
    return Number.MAX_VALUE
  } else if (val === -Infinity) {
    return -Number.MAX_VALUE
  }
  return isNaN(val) ? 0 : Math.round(+val);
}

In the code above, we check if val is Infinity our -Infinity , then we return Number.MAX_VALUE and -Number.MAX_VALUE respectively.

Otherwise, we check if val can be converted to a number, and then call Math.round if the number can be converted to a number.

Then we can call it as follows:

console.log(toInteger(3.2));
console.log(toInteger(Number.MIN_VALUE));
console.log(toInteger(Infinity));
console.log(toInteger('3.2'));

We then get the following values logged for each function call:

3
0
1.7976931348623157e+308
3

toLength

The toLength method converts a number to an integer that’s suitable to be used as the length of an array-like object.

We can implement our own toLength method as follows:

const toLength = (val) => {
  if (val === Infinity || Math.round(+val) > 4294967295) {
    return 4294967295
  } else if (+val < 0) {
    return 0
  }
  return isNaN(val) ? 0 : Math.round(+val);
}

In the code above, we check that if val is Infinity or if the converted integer is bigger than 4294967295, which is the maximum length of an array.

If it is, then we return 4294967295. If val converted to a number if negative, then we return 0.

Otherwise, we call Math.round to round the converted number if the converted value is a number.

Then when we call it as follows:

console.log(toLength(3.2));
console.log(toLength(Number.MIN_VALUE));
console.log(toLength(Infinity));
console.log(toLength('3.2'));

We get the following values from the console log outputs:

3
0
4294967295
3

Conclusion

We can implement Lodash’s object conversion methods easily ourselves.

The toArray method can be implemented by splitting strings or getting the values of an object.

The toFinite method can be implemented by returning the biggest integer in JavaSscript if it’s Infinity and the negative of that if it’s -Infinity . Otherwise, if it’s a number, then we return the 0 if the value isn’t a number or the number itself if it can be converted into a number.

Likewise, the toLength method can implemented in a similar way except that instead of returning the largest integer for Infinity and negative of that for -Infinity , we return the maximum length of a JavaScript array for Infinity and 0 for -Infinity or any other negative number.

Categories
Lodash

Learning JavaScript by Implementing Lodash Methods — Comparison and Constructors

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 look at how to clone objects in a variety of ways and do comparisons on object values.

conformsTo

The Lodash conformsTo checks if all object entries conform to a given predicate.

We can check the value of each property to see if the condition is met as follows:

const conformsTo = (obj, predicate) => {
  for (const [key, val] of Object.entries(obj)) {
    if (typeof predicate[key] === 'function' && predicate[key](val)) {
      return true
    }
  }
  return false;
}

In the code above, we used the Object.entries method to get all the entries of an object. Then we used destructuring to destructure the array entries returned by Object.entries to the keys and values.

Then we check val against the predicate[key] function, which returns the true if the condition in it is met and false otherwise.

Then we can use it as follows:

const result = conformsTo({
  a: 1
}, {
  a: x => x >= 0
});

Then since a has value 1, it conformsTo should return true because each value if bigger than or equal to 0 as the predicate has condition x >= 0 as the value of the a property.

eq

The Lodash eq object compares 2 objects to see if they’re equivalent using the SameValueZero algorithm.

We can implement our own eq function by doing the comparing for +0 and -0 ourselves and using Object.is for everything else:

const eq = (a, b) => {
  if (a === +0 && b === -0 ||
    a === -0 && b === +0 ||
    a === 0 && b === -0 ||
    a === 0 && b === +0 ||
    a === +0 && b === 0 ||
    a === -0 && b === 0) {
    return true;
  }
  return Object.is(a, b);
}

In the code above, we compared the 0 values with different signs and return true for all of them.

Then we use object Object.is for all other comparisons. When we call it as follows:

const result = eq(1, -0);

We get that result is false and if we call it as follows:

const result = eq(+0, -0);

we get that result is true .

gt

The Lodash gt method returns a boolean indicating if one number is bigger than the other.

We can just use the > operator to do the comparison ourselves. We can implement it as follows:

const gt = (a, b) => a > b;

Then we can call it as follows:

const result = gt(2, 1);

result is true .

gte

Like gt , we can implement the Lodash gte method with the >= operator.

We can write the following function as follows:

const gt = (a, b) => a >= b;

Then when we write the following code:

const result = gt(2, 2);

We get that result is true .

isArray

The Lodash isArray method checks is a value is an array. We can just use the Array.isArray method to check if an object is an array.

Therefore, we can write the following code to implement our own isArray method:

const isArray = arr => Array.isArray(arr);

In the code above, we just called Array.isArray to check if arr is an array.

Then we can call it as follows:

const result = isArray([1, 2, 3]);

We get that result is true .

isDate

The Lodash isDate method checks if an object is an instance of the Date constructor.

We can use the constructor.name property of an object to check what constructor the object is created from.

Therefore, we can write the following to implement our own isDate function:

const isDate = date => date.constructor.name == 'Date'

Then we can call the function as follows:

const result = isDate(1);

and get that result is false . If we call it as follows:

const result = isDate(new Date());

We get that result is true .

Conclusion

We can use the constuctor.name property to get the name of the constructor that an object is created from.

To check if an object is an array, we can use the Array.isArray method to implement it.

To compare values for equality, we can use === and Object.is . Finally, we can use the > and >= to check if something is bigger than another.

Categories
Lodash

Learning JavaScript by Implementing Lodash Methods — Picking Items and Getting Sizes

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 Lodash methods that let us pick items and getting sizes of collections.

reject

The reject method takes a collection of items and a predicate with the items that we don’t want to include in the returned array and return an array with the items that are opposite of the predicate.

We can implement this as follows:

const reject = (collection, predicate) => collection.filter(c => !predicate(c));

In the code above, we just called filter with a callback that returns the predicate call negated.

Then we can call it as follows:

const users = [{
    'user': 'foo',
    'active': false
  },
  {
    'user': 'bar',
    'active': true
  }
];

const result = reject(users, o => !o.active);

The code above rejects the users entries that have active set to false as the value.

This means that we return the entries with active set to true . Therefore, we get:

[
  {
    "user": "bar",
    "active": true
  }
]

as the value of result .

sample

The Lodash sample method returns a random element from a collection. Since plain JavaScript has a Math.random method, we can use that to get a random element from an array as follows:

const sample = (collection) => {
  const index = Math.random() * (collection.length);
  return collection[Math.floor(index)];
};

In the code above, we just used the Math.random method which is multiplied by the collection.length to get the index . Then we take the floor of it to get the actual index.

Then when we call it as follows:

const result = sample([1, 2, 3]);

We get a random item from the array.

sampleSize

The sampleSize method takes an array to get the items from and the size of the sample, we want to get.

It returns the array that takes random elements from the collection up to the given size .

We can implement the sampleSize method as follows:

const sampleSize = (collection, size) => {
  let sampled = [];
  for (let i = 1; i <= size; i++) {
    const index = Math.random() * (collection.length);
    sampled.push(collection.splice(index, 1)[0]);
  }
  return sampled;
};

In the code above, we created a loop that gets the index of the collection to pick by calling the Math.random multiplied by collection.length .

Then we called splice on collection to remove that element from collection and push it into the sampled array.

Once we have enough sampled items, we return sampled .

Then when we call it as follows:

const result = sampleSize([1, 2, 3], 2);

We get 2 different items from the array we passed in as the value of result .

shuffle

The Lodash shuffle method returns an array that’s a shuffled version of the original array.

We can implement it as follows:

const shuffled = (collection) => {
  let shuffled = [];
  const originalLength = collection.length;
  for (let i = originalLength - 1; i >= 0; i--) {
    const index = Math.random() * (collection.length);
    shuffled.push(collection.splice(index, 1)[0]);
  }
  return shuffled;
};

In the code above, we created a loop that loop through the collection ‘s original length. Then we get a random item from the collection and put it into the shuffled array as we did with the sampleSize function above.

Once the loop is done, we returned the shuffled array.

Then when we call shuffle as follows:

const result = shuffled([1, 2, 3]);

We get a shuffled version of the array we passed in.

size

The size method gets the size of a collection, which can be an array or an object. Since we have the length property of arrays and we have the Object.keys method for objects, we can implement it with the following code:

const size = (collection) => {
  if (Array.isArray(collection)) {
    return collection.length;
  } else {
    return Object.keys(collection).length;
  }
};

In the code above, we check if collection is an array. If it is, then we return the length property of it.

Otherwise, we return the array returned by Object.keys ‘s length property.

When we call it as follows:

const result = size([1, 2, 3]);

We get that result is 3.

When we call it with an object:

const result = size({
  'a': 1,
  'b': 2
});

We get that result is 2.

Conclusion

The reject method can be implemented with the filter method by negating the predicate in the callback.

The sample family of methods and shuffle can be implemented with Math.random and splice .

Finally, the size method can be implemented with the length of the array or length of the array returned by Object.keys .

Categories
Lodash

Learning JavaScript by Implementing Lodash Methods — Transforming Objects

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 some object methods with plain JavaScript.

toPlainObject

The Lodash’s toPlainObject method converts an object to a plain object by merging in the inherited enumerable properties into the object itself.

We can implement it by using the Object.create method

Then we use the Object.getPrototypeOf method and then merge them into the object’s own properties.

For instance, we can implement it as follows:

const toPlainPObject = (obj) => {
  let plainObj = Object.create(null);
  plainObj = {
    ...obj
  };
  let prototype = Object.getPrototypeOf(obj)
  while (prototype) {
    plainObj = {
      ...plainObj,
      ...prototype
    }
    prototype = Object.getPrototypeOf(prototype)
  }
  return plainObj;
}

In the code above, we have our toPlainObject function, which takes the obj parameter containing the object that we want to convert to a plain object.

We then create a new object with Object.create with the argument null , which creates a plain object by creating an object without a prototype.

Then we use the spread operator to merge obj ‘s own properties into plainObj .

Next, we call Object.getPrototypeOf with obj passed in to get obj ‘s prototype. Then we use a while loop to merge the prototype’s properties into plainObj and go up the prototype chain with:

prototype = Object.getPrototypeOf(prototype)

In the end, we return plainObj .

Now when we call it as follows:

function Foo() {
  this.a = 1;
}

Foo.prototype.b = 2;
console.log(toPlainPObject(new Foo()));

We get the console log output is {a: 1, b: 2} .

toSafeInteger

Lodash’s toSafeInteger method converts a value to a safe integer. It does this by checking for Infinity and -Infinity and then return the maximum safe integer and the maximum safe integer multiplied by 1 respectively.

We can implement it as follows:

const toSafeInteger = val => {
  if (val === Infinity) {
    return Number.MAX_SAFE_INTEGER
  } else if (val === -Infinity) {
    return -1 * Number.MAX_SAFE_INTEGER
  }
  return isNaN(+val) ? 0 : Math.round(+val);
}

In the code above, we check if val is Infinity or -Infinity . If it’s Infinity , then we return Number.MAX_SAFE_INTEGER . If val is -Infinity , then we return -Number.MAX_SAFE_INTEGER .

Otherwise, we check if val can be converted to a number by calling isNaN . If it returns true then we return 0, otherwise, we call Math.round with +val after it’s converted to a number.

Then we can call it as follows:

console.log(toSafeInteger(3.2));
console.log(toSafeInteger(Number.MIN_VALUE));
console.log(toSafeInteger(Infinity));
console.log(toSafeInteger('3.2'));

Then we get the following output from each of the respectively:

3
0
9007199254740991
3

toString

Lodash’s toString method coverts a given value to a string. An empty string is returned for null and undefined values.

For instance, we can implement it as follows:

const toString = val => {
  if (Object.is(val, -0)) {
    return '-0'
  } else if (Object.is(val, +0)) {
    return '+0'
  } else if (Object.is(val, null) || Object.is(val, undefined)) {
    return ''
  } else if (Array.isArray(val)) {
    return val.join(',');
  }
  return JSON.stringify(val);
}

In the code above, we used Object.is to check whether val is one of the listed values. We use Object.is instead of === because -0 and +0 are considered different with Object.is .

If val isn’t -0 , +0 , null or undefined then we use JSON.stringify to convert the object to a string.

Then we can call it as follows:

console.log(toString(null));
console.log(toString(-0));
console.log(toString([1, 2, 3]));

Then we get an empty string from the first console log, '-0' from the 2nd console log and 1,2,3 from the last console log.

invert

The Lodash invert method flips the keys and values of an object. If 2 properties have the same value, then the later one overwrites the earlier one.

We can do that ourselves with the Object.keys method to get the keys to populate a new object with the keys and values inverted as follows:

const invert = (obj) => {
  let invertedObj = {};
  for (const key of Object.keys(obj)) {
    invertedObj[obj[key]] = key;
  }
  return invertedObj;
}

In the code above, we created the invertedObj object. Then we loop through the keys by getting them with the Object.keys method and then looping through them with the for...of loop.

Then we populate the values of obj as the keys of invertedobj and the keys of obj as the values of invertedObj .

In the end, when we call it as follows:

const object = {
  'a': 1,
  'b': 2,
  'c': 1
};

console.log(invert(object));

We get {1: “c”, 2: “b”} logged from the console log output.

Conclusion

To implement the toPlainObject method, we can use the Object.getPrototype method to traverse the prototype chain of an object.

The toString and toSafeInteger methods are similar in that they both do a series of checks on the argument passed in and then return some values accordingly.

Finally, we can use Object.keys to get the keys of an object to implement invert .