Categories
JavaScript JavaScript Basics

How to Repeat Strings with JavaScript

There are a few ways to repeat a string in JavaScript. JavaScript strings have a built in repeat() function. You can also use a loop to do the same thing.

String.repeat Function

To use the repeat function, you pass in the number of times you want to repeat the string as an argument. It returns a new string

For example:

const hello = "hello";  
const hello5 = A.repeat(5);  
console.log(hello5); // "hellohellohellohellohello"

Use a loop

You can use for loop and while loop to do repeatedly concatenate strings.

Using a for loop, you can do:

const hello = "hello";  
let hello5 = '';  
for (let i = 1; i <= 5; i++){  
  hello5 += hello;  
}  
console.log(hello5); // "hellohellohellohellohello"

With a while loop, you can do:

const hello = "hello";  
let hello5 = '';  
let i = 1;  
while(i <= 5){  
  hello5 += hello;  
  i++  
}  
console.log(hello5); // "hellohellohellohellohello"

They both involve increment indexes up to the maximum.

Categories
JavaScript JavaScript Basics

How to Merge Arrays in JavaScript

Oftentimes, we need to combine multiple arrays into one array. With multiple arrays, combining them is pain without some help from JavaScript’s standard libraries. With ES6, there’s also the spread syntax to help us combine arrays.

There are a few ways to merge arrays in JavaScript.

Array.concat

We can all Array.concat on an array to combine 2 arrays and return the new one. For example:

const a = [1,2,3];
const b = [4,5];
const c = a.concat(b) // [1,2,3,4,5]

It also works with multiple arrays. You can pass in as many arrays as you want in the arguments of the concat function. For example:

const a = [1,2,3];
const b = [4,5];
const c = [6,7,8];
const d = a.concat(b, c) // [1,2,3,4,5,6,7]

Array.push

We can push elements of one array into another.

const a = [1,2,3];
const b = [4,5];
let c = Object.assign([], a);
for (let i = 0; i < b.length; i++){
  c.push(b[i]);
}
console.log(c); // [1,2,3,4,5]

What we did is make a copy of a and assigned it to c , then pushed the elements of b by looping through it and adding them to the end of c .

You can use the apply function available with all objects to combine 2 arrays. For example:

const a = [1,2];
const b = [3,4];
a.push.apply(a, b);
console.log(a); // [1,2,3,4];

Spread Operator

With ES6 or later, we can use the spread operator to spread the items from another array into a new array by doing the following:

const a = [1,2,3];
const b = [4,5];
const c = [...a, ...b];
console.log(c); // [1,2,3,4,5]
Categories
JavaScript JavaScript Basics

Handy JavaScript Array Tips

JavaScript, like any other programming language, has many handy tricks that let us write our programs more easily. In this article, we will look at how to do different things that involve arrays, like checking if an object is an array and combining arrays.

Check if an object is an Array

There are multiple ways to check if a JavaScript object or primitive value is an array. The newest way to check is to use the Array.isArray method. It takes one argument, which is any object or primitive value that we want to check if it’s an array. It returns true if it’s an array and false otherwise. However, for TypedArray objects like Int8Array, Uint8Array, Uint8ClampedArray, Int16Array, Uint16Array, Int32Array, Uint32Array, Float32Array, Float64Array, BigInt64Array, and BigUint64Array . It always returns false . For example, if we write the following code:

console.log(Array.isArray([1, 2, 3]));
console.log(Array.isArray(0));
console.log(Array.isArray(null));
console.log(Array.isArray({
  a: 1
}));
console.log(Array.isArray(undefined));
console.log(Array.isArray(Infinity));
console.log(Array.isArray(new Uint8Array()));

We get the following output from the console.log statements:

true  
false  
false  
false  
false  
false  
false

It’s a very handy method for determining if an object is an array. An alternative way to check if an object is an array is to use the instanceof operator. It works by checking if Array.prototype is on an object’s prototype chain. The only situation that it fails but works when using Array.isArray is that instanceof will fail when checking objects across frames wince the object instance will likely be different from the one that’s used for the array test with the instanceof operator. We can use it as in the following code:

console.log([1, 2, 3] instanceof Array);
console.log(0 instanceof Array);
console.log(null instanceof Array);
console.log({
    a: 1
  }
  instanceof Array);
console.log(undefined instanceof Array);
console.log(Infinity instanceof Array);
console.log(new Uint8Array() instanceof Array);

The console.log output should be exactly the same as the ones before since we didn’t put any objects inside a frame. Array.isArray is the simplest and most robust solution since most modern browsers have this method built-in, and that it works across frames.

Combining Arrays

With modern JavaScript, combining arrays into one is easier than ever. Array objects have the concat method which is called on an array, and takes in one or more arguments, which one or more arrays or objects that we want to combine into the array which it’s being called on. Note that it can also take in other non-array values that we want to pass in to be added into the array that it’s being called on. It returns a new array instance with the new array values so that we chain a series of calls to the concat method to combine more arrays into one. For example, we can write the following code for the most basic use case:

const arr1 = [1, 2, 3];
const arr2 = ['a', 'b', 'c'];
const combinedArr = arr1.concat(arr2);
console.log(combinedArr);

Then we get that the value of combinedArr will be [1, 2, 3, “a”, “b”, “c”] . We can also pass in more than one argument each of which are arrays into the concat method like in the following code:

const arr1 = [1, 2, 3];
const arr2 = ['a', 'b', 'c'];
const arr3 = ['1', '2', '3'];
const arr4 = ['d', 'e', 'f'];
const arr5 = ['g', 'h', 'i'];
const arr6 = [null, Infinity, NaN];
const arr7 = [10, 11, 12];
const arr8 = [{}, {
  a: 1
}, {
  b: 2
}];
const combinedArr = arr1.concat(arr2, arr3, arr4, arr5, arr6, arr7, arr8);
console.log(combinedArr);

Then we get the following output from the console.log output:

[
  1,
  2,
  3,
  "a",
  "b",
  "c",
  "1",
  "2",
  "3",
  "d",
  "e",
  "f",
  "g",
  "h",
  "i",
  null,
  null,
  null,
  10,
  11,
  12,
  {},
  {
    "a": 1
  },
  {
    "b": 2
  }
]

As we can see, the concat method is smart enough to combine multiple arrays into the first array, and that we have all the entries from all the arrays in one new array. The array returned from the concat method does not reference the original arrays. Also, it works with multiple types of data. It doesn’t matter what we pass in it, should still work. For example, if we have the following code:

const arr1 = [1, 2, 3];
const arr2 = ['a', 'b', 'c'];
const arr3 = ['1', '2', '3'];
const arr4 = ['d', 'e', 'f'];
const arr5 = ['g', 'h', 'i'];
const arr6 = [null, Infinity, NaN];
const arr7 = [10, 11, 12];
const arr8 = [{}, {
  a: 1
}, {
  b: 2
}];
const combinedArr = arr1.concat(arr2, arr3, arr4, arr5, arr6, arr7, arr8, 1, 'a', {
  c: 3
});

Then we get the following output if we run console.log on combinedArr :

[  
  1,  
  2,  
  3,  
  "a",  
  "b",  
  "c",  
  "1",  
  "2",  
  "3",  
  "d",  
  "e",  
  "f",  
  "g",  
  "h",  
  "i",  
  null,  
  null,  
  null,  
  10,  
  11,  
  12,  
  {},  
  {  
    "a": 1  
  },  
  {  
    "b": 2  
  },  
  1,  
  "a",  
  {  
    "c": 3  
  }  
]

This is very useful since don’t have to worry about the data types of the objects that we pass in or how many arguments we passed into the concat method. It takes as many arguments as we pass in. Since the concat method returns a new array with the values combined into one array, we can also chain the calls of the concat method to combine multiple things into a single array-like in the following code:

const arr1 = [1, 2, 3];
const arr2 = ['a', 'b', 'c'];
const arr3 = ['1', '2', '3'];
const arr4 = ['d', 'e', 'f'];
const arr5 = ['g', 'h', 'i'];
const arr6 = [null, Infinity, NaN];
const arr7 = [10, 11, 12];
const arr8 = [{}, {
  a: 1
}, {
  b: 2
}];
const combinedArr = arr1
  .concat(arr2)
  .concat(arr3)
  .concat(arr4)
  .concat(arr5)
  .concat(arr6)
  .concat(arr7)
  .concat(arr8)
  .concat(1)
  .concat('a', {
    c: 3
  });

Then we should get the following out when we run console.log on combinedArr:

[  
  1,  
  2,  
  3,  
  "a",  
  "b",  
  "c",  
  "1",  
  "2",  
  "3",  
  "d",  
  "e",  
  "f",  
  "g",  
  "h",  
  "i",  
  null,  
  null,  
  null,  
  10,  
  11,  
  12,  
  {},  
  {  
    "a": 1  
  },  
  {  
    "b": 2  
  },  
  1,  
  "a",  
  {  
    "c": 3  
  }  
]

With ES6, we have the spread operator, which we can use to combine arrays into one by spreading the values of the array into another array, and we can do that for all the arrays in one array separated by a comma after each array is spread. The spread also works with all array-like objects like arguments, Sets, Maps, or any object that has a Symbol.iterator method, which return a generator so that we can iterate through the items in the object with the for...of loop. To combine arrays and objects together into one array with the spread operator, we can write something like the following code:

const arr1 = [1, 2, 3];
const arr2 = ['a', 'b', 'c'];
const arr3 = ['1', '2', '3'];
const combinedArr = [...arr1, ...arr2, ...arr3];

Then we get:

[
  1,
  2,
  3,
  "a",
  "b",
  "c",
  "1",
  "2",
  "3"
]

when we run console.log on combinedArr . It also works with overlapping values across different arrays like the concat method does. For example, we can write the following code:

const arr1 = [1, 2, 3];
const arr2 = ['a', 'b', 'c'];
const arr3 = [1, '2', '3'];
const combinedArr = [...arr1, ...arr2, ...arr3];

and get that the value of combinedArr would be:

[  
  1,  
  2,  
  3,  
  "a",  
  "b",  
  "c",  
  1,  
  "2",  
  "3"  
]

As we can see, we have the value 1 in both arr1 and arr3 , but they both made it into combinedArr , which is good. We can also put objects into our new array that before, after or between the spread operations like in the following code:

const arr1 = [1, 2, 3];
const arr2 = ['a', 'b', 'c'];
const arr3 = [1, '2', '3'];
const combinedArr = ['c', ...arr1, 'c', ...arr2, 'c', ...arr3];

Then we get the following value for combinedArr :

[  
  "c",  
  1,  
  2,  
  3,  
  "c",  
  "a",  
  "b",  
  "c",  
  "c",  
  1,  
  "2",  
  "3"  
]

This means that the feature of the concat method can easily be replicated by the spread operator, and we don’t have to pass in a long list of arguments or chain multiple calls of the concat method together to combine arrays and other types of objects into one array.

There are multiple ways to check if a JavaScript object or primitive value is an array. The newest way to check is to use the Array.isArray method, but we can also use the old instanceof operator to check if an object is an array. Array.isArray works across frames so it’s more robust than the instanceof operator. With modern JavaScript, combining arrays into one is easier than ever. Array objects have the concat method which is called on an array and takes in one or more arguments, which one or more arrays or objects that we want to combine into the array which it’s being called on. Note that it can also take in other non-array values that we want to pass in to be added into the array that it’s being called on. It returns a new array instance with all the combined values included in the new array.

Categories
JavaScript JavaScript Basics

Debugging JavaScript Apps with the Console Object

JavaScript has great debugging tools built into it. One simple but powerful way to debug is by using the console object. This object has numerous methods which allow us to inspect the state of our program at any given time. The specifics of how the console works vary from browser to browser, but in the most popular browsers the console object has become standardized.

Console Methods

The console object is a global object. It’s a property of window in most browsers, and can be referenced via window.console or simply console. The console object has the following methods:

  • console.assert(boolStatement, message) log a message and the stack trace to the console if the first argument is false.
  • console.clear() clears the console.
  • console.count(label) log the number of times this method has been called with the given label.
  • console.countReset() resets the value of the counter for the given label.
  • console.debug(message) log a message to the console with the log level ‘debug’.
  • console.dir(obj) list the properties of the given JavaScript object. The content will have triangles to show the content of child objects.
  • console.dirxml(obj) displays an HTML or XML representation of the object if possible.
  • console.error(message) log an error message to the console. We can use string substitution and additional arguments to format the log message.
  • console.group() creates a group of console messages, indented by levels. We can move out of a level with groupEnd().
  • console.groupCollapsed() creates a group of console messages, indented by levels with the items collapsed. We can move out of a level with groupEnd()
  • console.groupEnd() exits the current inline group.
  • console.info(message) log informational messages. We can use string substitution and additional arguments to format the log message.
  • console.log(message) used for general logging of information. We can use string substitution and additional arguments to format the log message.
  • console.table() log and display data in a tabular format.
  • console.time(name) starts a timer with the name specified in the parameter. 10000 simultaneous timers can be run on a given page.
  • console.timeEnd(name) stop the specified timer and log the elapsed time in second since it started.
  • console.timeLog() logs the value of the specified timer to the console.
  • console.trace() logs a stack trace.
  • console.warn(message) log a warning message to the console. We can use string substitution and additional arguments to format the log message.

Different Levels of Logging

Logging data is the most common use for the console object. To do this we can use console.log(), console.info(), console.warn() or console.error() depending on the kind of information you’re logging. They’re all styled differently.

console.error() is styled with a red background in Chrome, console.warn() is styled with a yellow background in Chrome, and console.log() has no special background in Chrome.

We can pass in any JavaScript data into them. For example, we can write something like:

const obj = {a: 1, b: 2, c:3};
const message = { message: 'Error occurred' };
console.log(obj);
console.info('Info logged', 123); 
console.warn('Warning logged');
console.error('Error', message);

We can output as many things as we want in one line since the console.log(), console.info(), console.warn(), or console.error() methods all can take more than one argument. So we can write something like:

const obj = {  
  a: 1,  
  b: 2,  
  c: 3  
};  
const message = {  
  message: 'Error occurred'  
};  
console.log(obj, obj, message);  
console.info('Info logged', 123, obj, message);  
console.warn('Warning logged', obj, message);  
console.error('Error', obj, message);

And everything will be logged. We get the following logged:

{a: 1, b: 2, c: 3} {a: 1, b: 2, c: 3} {message: "Error occurred"}
Info logged 123 {a: 1, b: 2, c: 3} {message: "Error occurred"}
Warning logged {a: 1, b: 2, c: 3} {message: "Error occurred"}
Error {a: 1, b: 2, c: 3} {message: "Error occurred"}

String Substitutions

With string substitutions, we can format our console in a way that’s easier to read. It works by replacing placeholders in a string with the arguments that you pass into the right of the string you’ve passed in. The following placeholders can be used for string substitutions:

  • %o or %O this placeholder will be replaced with a JavaScript object. You can click on the object name to get more data about the object when you click on the object in the console.
  • %d or %i this placeholder will be replaced with an integer. We can use this placeholder to format numbers. We can write something like %.3d to round numbers to 3 significant digits with leading 0s.
  • %s this placeholder will be replaced with a string
  • %f this placeholder will be replaced with a floating-point value. We can use this placeholder to format numbers. We can write something like %.3d to round numbers to 3 significant digits with leading 0s.
const obj = {
  a: 1,
  b: 2,
  c: 3
};
const message = {
  message: 'Error occurred'
};
console.log('Object %o', obj);
console.info('Number is %.3d', 123.456);
console.warn('Warning: number is: %.3d', 123.456);
console.error('Error - Error is %o. Error message is %s', message, message.message);

If we run the code above, wherever we have the %o placeholder and log an object, we can click the triangle to see more data. Whenever we have %.3d with a number, we see our number in the argument rounded to 3 significant digits. Strings stay as strings.

Styling Messages

Console messages can also be styled with CSS with the %c directive. Any text after the %c directive will be styled with whatever styles are specified. We pass in the string with the %c directive as the first argument and the string with the styles in the second argument. For example, we can write:

console.log("This is a %cMy colorful message", "color: lightgreen; font-style: italic; background-color: black;padding: 2px");

The following syntax is allowed in the style string:

  • background and its longhand equivalents. Note that background-image doesn’t seem to work in Firefox, although it does work in Chrome.
  • border and its longhand equivalents
  • border-radius
  • box-decoration-break
  • box-shadow
  • clear and float
  • color
  • cursor
  • display
  • font and its longhand equivalents
  • line-height
  • margin
  • outline and its longhand equivalents
  • padding
  • text-* properties such as text-transform
  • white-space
  • word-spacing and word-break
  • writing-mode

Console Grouping

We can group console output by using the console.group() to create the group and the console.groupEnd() method to end the group. The console.groupCollapsed() method is similar to the console.group() method but creates a collapsed group. To view the output of a collapsed group, you can click the triangle button to open the output. For example, we can create multiple console log groups with the following code:

console.log("Outer level");
console.group("Group 1");
console.log("Message in group 1");
console.group("Group 2");
console.log("Message in group 2");
console.group("Group 3");
console.log("Message in group 3");
console.group("Group 4");
console.log("Message in group 4");
console.groupEnd();
console.groupEnd();
console.groupEnd();
console.log("Back in group 3");
console.groupEnd();
console.log("Back in group 2");

Find How Long Something Takes to Run

To calculate the time that some code takes to run, we can use console timer objects. We can use the console.time() method to start a timer with a string that you pass in as the label of the timer. Then you can call console.timeLog() to log the time of the timer when it’s running and the console.timeEnd() to end the timer. For example, we can write the following code to see the what time a loop loops through an element:

const arr = Array.from({
  length: 5
}, (v, i) => i);
(async () => {
  console.time("loop time");
  for await (let i of arr) {
    console.log(i)
    console.timeLog("loop time");
    await new Promise((resolve, reject) => setTimeout(() => resolve(i), 1000))
  }
  console.timeEnd("loop time");
})();

We can have multiple timers set simultaneously, like in the following code:

const arr = Array.from({
  length: 5
}, (v, i) => i);
const arr2 = Array.from({
  length: 10
}, (v, i) => i);
const asyncLoop1 = async () => {
  console.time("loop time");
  for await (let i of arr) {
    console.log(i)
    console.timeLog("loop time");
    await new Promise((resolve, reject) => setTimeout(() => resolve(i), 1000))
  }
  console.timeEnd("loop time");
}
const asyncLoop2 = async () => {
  console.time("loop time 2");
  for await (let i of arr2) {
    console.log(i)
    console.timeLog("loop time 2");
    await new Promise((resolve, reject) => setTimeout(() => resolve(i), 1000))
  }
  console.timeEnd("loop time 2");
}
(async () => {
  await asyncLoop1();
  await asyncLoop2();
})()

If the 2 timers have different names, then they’re 2 different timers. The elapsed time of each timer will be logged individually. They can run at the same time like in the following code:

const arr = Array.from({
  length: 5
}, (v, i) => i);
const arr2 = Array.from({
  length: 10
}, (v, i) => i);

const asyncLoop1 = async () => {
  console.time("loop time");
  for await (let i of arr) {
    console.log(i)
    console.timeLog("loop time");
    await new Promise((resolve, reject) => setTimeout(() => resolve(i), 1000))
  }
  console.timeEnd("loop time");
}
const asyncLoop2 = async () => {
  console.time("loop time 2");
  for await (let i of arr2) {
    console.log(i)
    console.timeLog("loop time 2");
    await new Promise((resolve, reject) => setTimeout(() => resolve(i), 1000))
  }
  console.timeEnd("loop time 2");
}
asyncLoop1();
asyncLoop2();

Then we see that the 2 timers are simultaneously from the console’s log.

Log Stack Trace

We can also log the stack trace of function calls with the console.trace() method. We just put it inside the function we want to get the stack trace from and we can get the entire chain of function calls. For example, we can write:

const a = () => console.trace()  
const b = () => a()  
const c = () => b()  
const d = () => c()  
const e = () => d()e();

Log Objects and Arrays Values in Tables

To display log data in a table when we log objects, we can use the console.table command. It works with both objects and arrays. For objects, it will log the properties in the row and column if the object is 2 levels deep. For example, if we have:

const family = {  
  son: {  
    firstName: 'John',  
    lastName: 'Jones'  
  },  
  daughter: {  
    firstName: 'Jane',  
    lastName: 'Jones'  
  }  
}

console.table(family)

If we have a single level object, then we get the keys on the left and values on the right. For example, if we run:

const son = {  
  firstName: 'John',  
  lastName: 'Jones'  
}

console.table(son)

console.table() also works for arrays. We can use it to log 1-D and 2-D arrays. For one dimensional arrays, we get the indexes of the array on the left side and the values on the right side. For example, if we have:

const arr = [1, 2, 3];  
console.table(arr)

If we have use console.table() to log a two-dimensional array, we get the indexes of the top-level array on the left and the indexes of the nested array on the top of the table, with the values of each entry in the table. For example, if we have:

const arr = [
  ['a', 1],
  ['b', 2],
  ['c', 3]
];
console.table(arr);

The console.table() method has a second argument that restricts the columns displayed by setting an array with the keys of an object that we want to display or the indexes of an array that we want to log. This only works with nested objects that are 2 levels deep. For example, we can write:

const family = {
  son: {
    firstName: 'John',
    lastName: 'Jones'
  },
  daughter: {
    firstName: 'Jane',
    lastName: 'Jones'
  }
}
console.table(family, ['firstName'])

Then we only get the firstName column and the corresponding values displayed. This only works with the second level properties for nested objects.

As we can see, the console object is very useful for logging data in our JavaScript programs. We can have different levels of logging with console.log(), console.info(), console.warn(), and console.error() methods. We can display objects and arrays in a table with console.table(). We can see how long code takes to run with console.time() and associated methods, and we can group messages with console.group() and associated methods.

Categories
JavaScript JavaScript Basics

How to Identify Falsy Values in JavaScript

The following values are falsy in JavaScript, which means that if they are casted to a boolean value, it will be false.

  • false
  • 0
  • empty string: "" , '' , or ``
  • null
  • undefined
  • NaN — not a number value

If you evaluate them as boolean like so, you get:

Boolean(false); // false
Boolean(0); // false
Boolean(""); // false
Boolean(''); // false
Boolean(``); // false
Boolean(undefined); // false
Boolean(null); // false
Boolean(NaN); // false

as opposed to truthy values like objects, which are anything else but the values above:

Boolean({}) // true
Boolean(true) // true
Boolean([]) // true

You can also use the !! shortcut to cast to Boolean, the right ! cast the variable into a boolean and negate the value, and the left ! negate it back to the actual boolean value.

!!(false); // false
!!(0); // false
!!(""); // false
!!(''); // false
!!(``); // false
!!(undefined); // false
!!(null); // false
!!(NaN); // false

Similarly for truthy values:

!!({}) // true
!!(true) // true
!!(\[\]) // true

With shortcut evaluation, boolean ANDs and ORs are evaluated up to the first truthy value:

const abc = false && "abc"; // false, since false is false and "abc" is true

const def = false || "def"; // true, since false is false and "def" is true

It is always good to check for falsy values like null and undefined to avoid crashes.