JavaScript Map

This article illustrates the operations of JavaScript Map. Most of the content come from MDN.

About Map

The Map object holds key-value pairs and remembers the original insertion order of the keys. It iterates its elements in insertion order — a for...of loop returns an array of [key, value] for each iteration.

  • Key equality

    NaN is considered the same as NaN (even though NaN !== NaN) and all other values are considered equal according to the semantics of the === operator.

    let myMap = new Map()
    myMap.set(NaN, 'not a number')
    
    myMap.get(NaN)
    // "not a number"
    
    let otherNaN = Number('foo')
    myMap.get(otherNaN)
    // "not a number"
    

Basic operations

Create

Use the Map() constructor creates Map objects.

Syntax:

new Map([iterable]);
// iterable can be an Array or other iterable objects whose elements are key-value pairs.

Examples:

let map1 = new Map([
  [1, 'one'],
  [2, 'two'],
  [3, 'three'],
]);

let map2 = new Map();
map2.set(1, 'one');
map2.set(2, 'two');
map2.set(3, 'three');

Size

console.log(map1.size);

Loop

There are several ways to loop a Map object.

iterator or entries

The initial value of the @@iterator property is the same function object as the initial value of the entries method. The map iterator function, which is the entries() function by default.

iterator:

const map1 = new Map();

map1.set('0', 'foo');
map1.set(1, 'bar');

const iterator1 = map1[Symbol.iterator]();

for (const item of iterator1) {
    console.log(item);
}
// expected output: Array ["0", "foo"]
// expected output: Array [1, "bar"]

entries():

The entries() method returns a new Iterator object that contains the [key, value] pairs for each element in the Map object in insertion order. In this particular case, this iterator object is also an iterable, so the for-of loop can be used.

const iterator1 = map1.entries();
for (const item of iterator1) {
    console.log(item);
}
// expected output: Array ["0", "foo"]
// expected output: Array [1, "bar"]

for…of

let myMap = new Map();
myMap.set(0, 'zero');
myMap.set(1, 'one');

// -------- Loop key, value pairs
for (let [key, value] of myMap) {
  console.log(key + ' = ' + value)
}
// 0 = zero
// 1 = one

// -------- Loop keys
for (let key of myMap.keys()) {
  console.log(key)
}
// 0
// 1

// -------- Loop values
for (let value of myMap.values()) {
  console.log(value)
}
// zero
// one

// -------- entries
for (let [key, value] of myMap.entries()) {
  console.log(key + ' = ' + value)
}
// 0 = zero
// 1 = one

forEach

The forEach() method executes a provided function once per each key/value pair in the Map object, in insertion order.

function logMapElements(value, key, map) {
  console.log(`m[${key}] = ${value}`);
}

new Map([['foo', 3], ['bar', {}], ['baz', undefined]])
  .forEach(logMapElements);

// expected output: "m[foo] = 3"
// expected output: "m[bar] = [object Object]"
// expected output: "m[baz] = undefined"

Syntax

myMap.forEach(callback([value][, key][, map])[, thisArg])

Parameters

  • callback

    Function to execute for each entry of myMap. It takes the following arguments:

    • value Optional. Value of each iteration.
    • key Optional. Key of each iteration.
    • map Optional. The map being iterated (myMap in the above Syntax box).
  • thisArg Optional

    Value to use as this when executing callback.

Delete

  • delete(), deletes the specified element.
  • clear(), deletes all elements.

delete()

The delete(key) method removes the specified element from a Map object by key.

It returns true if an element in the Map object existed and has been removed, or false if the element does not exist.

const map1 = new Map();
map1.set('bar', 'foo');

console.log(map1.delete('bar'));
// expected result: true
// (true indicates successful removal)

console.log(map1.has('bar')); // false

clear()

The clear() method removes all elements from a Map object.

const map1 = new Map();

map1.set('bar', 'baz');
map1.set(1, 'foo');
console.log(map1.size); // 2

map1.clear();
console.log(map1.size); // 0

get()

The get(key) method returns a specified element from a Map object. If the value that is associated to the provided key is an object, then you will get a reference to that object and any change made to that object will effectively modify it inside the Map object.

const map1 = new Map();
map1.set('bar', 'foo');

console.log(map1.get('bar')); // "foo"
console.log(map1.get('baz')); // undefined

has()

The has(key) method returns a boolean indicating whether an element with the specified key exists or not.

const map1 = new Map();
map1.set('bar', 'foo');

console.log(map1.has('bar')); // true
console.log(map1.has('baz')); // false

set()

The set(key, value) method adds or updates an element with a specified key and a value to a Map object.

const map1 = new Map();

map1.set('bar', 'foo');
console.log(map1.get('bar')); // "foo"

map1.set('bar', 'foo2');
console.log(map1.get('bar')); // "foo2"

This is the only right way to update or add an element through set().

Note

It is possible to set properties of a Map like other generic objects, but this will cause considerable confusion. For these properties set in this way are not stored in the Map for queries. Other operations on the data fail:

let wrongMap = new Map()
wrongMap['bla'] = 'blaa'
wrongMap['bla2'] = 'blaaa2'

console.log(wrongMap)  // Map { bla: 'blaa', bla2: 'blaaa2' }

// Other operations on the data fail.

wrongMap.has('bla')    // false
wrongMap.delete('bla') // false
console.log(wrongMap)  // Map { bla: 'blaa', bla2: 'blaaa2' }

Members

entities()

The entries() method returns a new Iterator object that contains the [key, value] pairs for each element in the Map object in insertion order. In this particular case, this iterator object is also an iterable, so the for-of loop can be used. When the protocol [Symbol.iterator] is used, it returns a function that, when invoked, returns this iterator itself.

const map1 = new Map();

map1.set('0', 'foo');
map1.set(1, 'bar');

const iterator1 = map1.entries();

console.log(iterator1.next().value);
// expected output: ["0", "foo"]

console.log(iterator1.next().value);
// expected output: [1, "bar"]

keys()

The keys() method returns a new Iterator object that contains the keys for each element in the Map object in insertion order.

const map1 = new Map();

map1.set('0', 'foo');
map1.set(1, 'bar');

const iterator1 = map1.keys();

console.log(iterator1.next().value);
// expected output: "0"

console.log(iterator1.next().value);
// expected output: 1

values()

The values() method returns a new Iterator object that contains the values for each element in the Map object in insertion order.

const map1 = new Map();

map1.set('0', 'foo');
map1.set(1, 'bar');

const iterator1 = map1.values();

console.log(iterator1.next().value);
// expected output: "foo"

console.log(iterator1.next().value);
// expected output: "bar"

Other operations

Map and Array

Array to Map

It is easy to convert an Array to a Map, for Map() constructor accepts an array as its parameter:

let kvArray = [['key1', 'value1'], ['key2', 'value2']];

// Use the regular Map constructor to transform a 2D key-value Array into a map
let myMap = new Map(kvArray);

Map to Array

To convert a Map to an Array:

let kvArray = [['key1', 'value1'], ['key2', 'value2']];
let myMap = new Map(kvArray);

// Use Array.from() to transform a map into a 2D key-value Array
let arr1 = Array.from(myMap);
console.log(arr1); // Will show you exactly the same Array as kvArray

// A succinct way to do the same, using the spread syntax
let arr2 = [...myMap];
console.log(arr2);

let arr3 = Array.from(myMap.keys());
console.log(arr3); // ["key1", "key2"]

Map and JSON

There is not direct support to convert a map to JSON, we can do that by using array.

Map to Json

let jsonStr = JSON.stringify([...myMap]);
// Or
let jsonStr2 = JSON.stringify(Array.from(myMap));

JSON to Map

let myMap = Map(JSON.parse(jsonStr));

Object vs Map

An object is similar to a map, both of them have a key-value structure. Objects vs Maps lists the differences between objects and a maps. Below are some main of them :

  • Key type:
    • The keys of an Object must be either a String or a Symbol.
    • A Map‘s keys can be any value (including functions, objects, or any primitive).
  • Size:
    • You need to get the item count of an object manually.
    • Use size property to directly get size of a map.
  • Iteration
    • By default, Object does not implement an iteration protocol, it is not directly iterable using for...of statement (by default). The for…in statement allows you to iterate over the enumerable properties of an object.
    • A Map is iterable, it can be directly iterated.
  • Performance

    When it comes to scenarios involving frequent additions and removal:

    • A map performs better.

Suggestions about object vs map

geeksforgeeks: Map vs Object:

Object is much more than a Map, it shouldn’t be used just for the purpose of hashing if there exists another choice.

Reference

JavaScript String

This article lists the operations of JavaScript String and the things you want to know about it. Treat it as a reference list.

About String in JavaScript

As in other programming languages, a string in JavaScript is also a sequence of characters.

A Sting is one of the seven primitive data types in JavaScript and String object is a wrapper for a String primitive.

A set of 16-bit unsigned integer values

It is a set of “elements” of 16-bit unsigned integer values.

Immutable

Unlike some programming languages (such as C), JavaScript strings are immutable. This means that once a string is created, it is not possible to modify it.

String primitives and String objects

JavaScript automatically converts primitives to String objects, so that it’s possible to use String object methods for primitive strings. In contexts where a method is to be invoked on a primitive string or a property lookup occurs, JavaScript will automatically wrap the string primitive and call the method or perform the property lookup.

let s_prim = 'foo'
let s_obj = new String(s_prim)

console.log(typeof s_prim) // Logs "string"
console.log(typeof s_obj)  // Logs "object"

String primitives and String objects also give different results when using eval(). Primitives passed to eval are treated as source code; String objects are treated as all other objects are, by returning the object. For example:

let s1 = '2 + 2'              // creates a string primitive
let s2 = new String('2 + 2')  // creates a String object
console.log(eval(s1))         // returns the number 4
console.log(eval(s2))         // returns the string "2 + 2"

A String object can always be converted to its primitive counterpart with the valueOf() method.

console.log(eval(s2.valueOf()))  // returns the number 4

Escape notation

Code Output
U+0000 NULL character
' single quote
" double quote
\ backslash
n new line
r carriage return
v vertical tab
t tab
b backspace
f form feed
uXXXX (where XXXX is 4 hex digits; range of 0x00000xFFFF) UTF-16 code unit / Unicode code point between U+0000 and U+FFFF
u{X}u{XXXXXX} (where X…XXXXXX is 1–6 hex digits; range of 0x00x10FFFF) UTF-32 code unit / Unicode code point between U+0000 and U+10FFFF
xXX (where XX is 2 hex digits; range of 0x000xFF) ISO-8859-1 character / Unicode code point between U+0000 and U+00FF

Basic operations

Create strings

Strings can be created as primitives from string literals, or as object using String() constructor. In most situations, they can be used interchangeably.

const str1 = 'Hello';
const str2 = "World";
const str3 = `A template string`;
const str4 = new String('A string object');

A string literal can be enclosed by single quotes '' or double quotes"", both of them are treated identically. Or you can use a pair of backticks ““ to create a template string (or a template literal).

Template literals (Template strings)

Template literals can be useful, below are 2 of the examples:

They can contain placeholders:

let a = 5;
let b = 10;
console.log(`a is ${a}, b is ${b}`); // a is 5, b is 10

console.log(`a * 10 times: ${a.repeat(10)}`); // a * 10 times: aaaaaaaaaa

They can be used to represent multiple lines in a direct way:

console.log(`string text line 1
string text line 2`);

Multiple line of strings

There are several ways to represent multiple line of string or long strings in JavaScript.

1.Use + to append multiple strings together:

let longString = "This is a very long string which needs " +
                 "to wrap across multiple lines because " +
                 "otherwise my code is unreadable.";

2.Use the backslash character (“) at the end of each line to indicate that the string will continue on the next line:

let longString = "This is a very long string which needs 
to wrap across multiple lines because 
otherwise my code is unreadable.";

3.Use a template string:

let longString = `This is a very long string which needs
 to wrap across multiple lines because
 otherwise my code is unreadable.`;

Length

const str1 = 'Hello';
console.log(str1.length); // 5

Access characters or elements

To access an individual character:

return 'cat'.charAt(1); // returns "a"
// Or
return 'cat'[1] // returns "a"

Not it will not succeed to delete or assign a new value via [].

Check

startsWith()

The startsWith(searchString[, position] method determines whether a string begins with the characters of a specified string, returning true or false as appropriate.

  • position, the position in this string at which to begin searching for searchString. Defaults to 0.
const str1 = 'Hello!';

console.log(str1.startsWith('He'));    // true
console.log(str1.startsWith('lo', 3)); // true

console.log(str1.startsWith('A'));     // false

endsWith()

The endsWith(searchString[, length]) method determines whether a string ends with the characters of a specified string, returning true or false as appropriate.

  • length, it is used as the length of str. Defaults to str.length.
const str1 = 'Hello!';

console.log(str1.endsWith('llo'));    // true
console.log(str1.endsWith('llo', 3)); // false

console.log(str1.endsWith('?'));      // false

Compare

Use operators to compare two strings.

const a = 'a'
const b = 'b'

console.log( a < b);  // true
console.log( a <= b); // true
console.log( a > b);  // false

Equal check:

  • == return true if the operands are equal.
  • === returns true if the operands are equal and of the same type.
const a = 'Hello';
const b = new String('Hello');
const c = 'hello';

const d = 1;
const f = '1';

//------------- equal: ==

// Compare the strings in a and b for being equal in the usual case-sensitive way.
console.log(a == b); // true
console.log(a == c); // false
console.log(d == f); // true

// Case-insentitive
console.log(c.toUpperCase() == c.toUpperCase()); // true

// ------------ strict equal: ===

console.log(a === b); // false

Concat

contact()

The concat() method concatenates the string arguments to the calling string and returns a new string.

Examples

// To concatenate two or more strings.

const str1 = 'Hello';
const str2 = 'World';

console.log(str1.concat(' ', str2));
// expected output: "Hello World"

console.log(str1.concat(' ', str2, ', ', str1, ' ', str2));
// expected output: "Hello World, Hello World"

Index of

indexOf()

indexOf(searchValue[, fromIndex]) returns the index within the calling String object of the first occurrence of the specified value, starting the search at fromIndex. Returns -1 if the value is not found.

lastIndexOf()

The lastIndexOf(searchValue[, fromIndex]) method returns the index within the calling String object of the last occurrence of the specified value, searching backwards from fromIndex. Returns -1 if the value is not found.

Lower, upper

toLowerCase()

The toLowerCase() method returns the calling string value converted to lower case.

const sentence = 'The quick brown fox jumps over the lazy dog.';

console.log(sentence.toLowerCase());
// expected output: "the quick brown fox jumps over the lazy dog."

toUpperCase()

The toUpperCase() method returns the calling string value converted to uppercase (the value will be converted to a string if it isn’t one).

const sentence = 'The quick brown fox jumps over the lazy dog.';

console.log(sentence.toUpperCase());
// expected output: "THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG."

Pad

padEnd()

The padEnd(targetLength [, padString) method pads the current string with a given string (repeated, if needed) so that the resulting string reaches a given length. The padding is applied from the end of the current string.

  • padString, if it is too long to stay within targetLength, it will be truncated. Default value is " ".
const str1 = 'Breaded Mushrooms';

console.log(str1.padEnd(25, '.'));
// expected output: "Breaded Mushrooms........"

const str2 = '200';

console.log(str2.padEnd(5));
// expected output: "200  "

padStart()

The padStart(targetLength [, padString]) method pads the current string with another string (multiple times, if needed) until the resulting string reaches the given length. The padding is applied from the start of the current string.

const str1 = '5';

console.log(str1.padStart(2, '0'));
// expected output: "05"

const fullNumber = '2034399002125581';
const last4Digits = fullNumber.slice(-4);
const maskedNumber = last4Digits.padStart(fullNumber.length, '*');

console.log(maskedNumber);
// expected output: "************5581"

Repeat

repeat()

To make a string repeat multiple times:

const a = 'a';

console.log(chorus.repeat(10));
// expected output: "aaaaaaaaaa"

Replace

The replace() and replaceAll return a new string with some or all matches of a pattern replaced by a replacement. The pattern can be a string or a RegExp, and the replacement can be a string or a function to be called for each match.

For replace(), if pattern is a string, only the first occurrence will be replaced.

replace()

The replace() method returns a new string with some or all matches of a pattern replaced by a replacement.

Syntax

replace(regexp|substr, newSubstr|function)

Examples

const p = 'The quick brown fox jumps over the lazy dog. If the dog reacted, was it really lazy?';

console.log(p.replace('dog', 'monkey'));
// expected output: "The quick brown fox jumps over the lazy monkey. If the dog reacted, was it really lazy?"


const regex = /Dog/i;
console.log(p.replace(regex, 'ferret'));
// expected output: "The quick brown fox jumps over the lazy ferret. If the dog reacted, was it really lazy?"

replaceAll()

The replaceAll() method returns a new string with all matches of a pattern replaced by a replacement.

Syntax

replaceAll(regexp|substr, newSubstr|function)

Examples

const p = 'The quick brown fox jumps over the lazy dog. If the dog reacted, was it really lazy?';

console.log(p.replaceAll('dog', 'monkey'));
// expected output: "The quick brown fox jumps over the lazy monkey. If the monkey reacted, was it really lazy?"


// global flag required when calling replaceAll with regex
const regex = /Dog/ig;
console.log(p.replaceAll(regex, 'ferret'));
// expected output: "The quick brown fox jumps over the lazy ferret. If the ferret reacted, was it really lazy?"

Sub string

There are several methods to extract a port of a string, substring and slice are almost identical except some subtle differences if start is greater than end, or there are negative arguments:

  • substring(start[, end]), if start is greater than end, substring swaps the two argument.
  • slice(begin[, end]), if begin is greater than (or equal) end, it returns an empty string. If end is negative, it is treated as str.length + endIndex.
  • substr(start[, length]), a legacy feature in ECMAScript. It’s best to avoid using it if possible.

Differences between substring() and slice():

const str = 'Hello';

// If start is greater than end.
console.log(str.substring(5, 2));  // "llo"
console.log(str.slice(5, 2));      // ""

// Negative values.

// Negative start is treated as 0 for substring().
console.log(str.substring(-3, 3));  // "Hel"
// Negative start is treated as str.length -start for slice().
console.log(str.slice(-3, 3));      // "l"

// Negative end is treated as 0;
console.log(str.substring(0, -2)); // ""
// Negative end is treated as str.length + endIndex for slice().
console.log(str.slice(0, -2));     // "Hel"

substring()

The substring(start[, end]) returns the part of the string between the start and end indexes, or to the end of the string.

const str = 'Hello';

console.log(str.substring(1, 3)); // "el"
console.log(str.substring(2));    // "llo"
console.log(str.substring(0, 100)); // "Hello"

// Negative argument is treated as 0.
console.log(str.substring(-3));     // "Hello"
console.log(str.substring(-3, 3));  // "Hel"

// If start is greater than end, the effect of substring() is
// as if the two arguments were swapped.
console.log(100, 1);   // "ello"
console.log(100, 10);  // ""
console.log(100, 200); // ""

// NaN is treated as 0.
console.log(str.substring('a', 0));  // "H"
console.log(str.substring(0, 'a')); // ""

slice()

const str = 'Hello';

console.log(str.slice(1, 3));   // "el"
console.log(str.slice(2));      // "llo"
console.log(str.slice(0, 100)); // "Hello"

console.log(str.slice(-3));     // "llo"
console.log(str.slice(-3, 3));  // "l"

// NaN is treated as 0.
console.log(str.slice('a', 0));  // "H"
console.log(str.slice(0, 'a')); // ""

substr() (a legacy feature)

substr(start[, length]) returns a portion of the string, starting from the start index and extending for characters of length or ones to the end if length is not specified.

const str = 'Hello';

console.log(str.substr(1, 2)); // "el"
console.log(str.substr(2));    // "llo"

console.log(str.substr(-3));     // "llo"
console.log(str.substr(-3, 2));  // "ll"

// The value of start is capped at str.length if its value is out of range.
console.log(str.substr(-100, 2));// "He"

// If length is negative, it is reated as 0
console.log(str.substr(-3, -2)); // ""
console.log(str.substr(1, -2));  // ""

Search

includes()

The includes(searchString[, position]) method performs a case-sensitive search to determine whether one string may be found within another string, returning true or false as appropriate.

  • position, the position within the string at which to begin searching for searchString. (Defaults to 0.)
const sentence = 'The quick brown fox jumps over the lazy dog.';
const word = 'fox';

console.log(sentence.includes(word)); // true
console.log(sentence.includes(word, 20)); // false

search()

The search(regexp) method executes a search for a match between a regular expression and this String object.

If a non-RegExp object regexp is passed, it is implicitly converted to a RegExp with new RegExp(regexp).

const paragraph = 'The quick brown fox jumps over the lazy dog. If the dog barked, was it really lazy?';

// any character that is not a word character or whitespace
const regex = /[^ws]/g;

console.log(paragraph.search(regex));
// expected output: 43

console.log(paragraph[paragraph.search(regex)]);
// expected output: "."

Split

split()

The split([separator[, limit]) method divides a String into an ordered list of substrings, puts these substrings into an array, and returns the array.

  • separator, the separator can be a simple string or it can be a regular expression.
  • limit, the number of substrings to be included in the array. If it is 0, [] is returned.
const str = 'Welcome to JavaScript world.';

const words = str.split(' '); // words: ["Welcome","to","JavaScript","world."]

const chars = str.split('');
// chars: ["W","e","l","c","o","m","e"," ","t","o"," ","J","a","v","a","S","c","r","i","p","t"," ","w","o","r","l","d","."]

const strCopy = str.split(); // strCopy: ["Welcome to JavaScript world."]

To string

toString()

The toString() method returns a string representing the specified object.

const stringObj = new String('foo');

console.log(stringObj);
// expected output: String { "foo" }

console.log(stringObj.toString());
// expected output: "foo"

Trim

To remove whitespace from both or either of the ends of a string. Whitespace in this context is all the whitespace characters (space, tab, no-break space, etc.) and all the line terminator characters (LF, CR, etc.).

const greeting = '   Hello world!   ';

console.log(greeting);             // expected output: "   Hello world!   ";

// To remove whitespace from both ends.
console.log(greeting.trim());      // expected output: "Hello world!";

// To remove whitespace from the beginning
console.log(greeting.trimStart()); // expected output: "Hello world!

// To remove whitespace from the end
console.log(greeting.trimEnd());   // expected output: "   Hello world!";

valueOf

valueOf()

The valueOf() method returns the primitive value of a String object.

const stringObj = new String('foo');

console.log(stringObj);
// expected output: String { "foo" }

console.log(stringObj.valueOf());
// expected output: "foo"

Char Unicode

Unicode to char

The static String.fromCharCode() method returns a string created from the specified sequence of UTF-16 code units.

console.log(String.fromCharCode(189, 43, 190, 61));
// expected output: "½+¾="

It accept a sequence of numbers that are UTF-16 code units. The range is between 0 and 65535 (0xFFFF). Numbers greater than 0xFFFF are truncated. No validity checks are performed.

Char to Unicode

The charCodeAt() method returns an integer between 0 and 65535 representing the UTF-16 code unit at the given index.

const sentence = 'The quick brown fox jumps over the lazy dog.';

const index = 4;

console.log(`The character code ${sentence.charCodeAt(index)} is equal to ${sentence.charAt(index)}`);
// expected output: "The character code 113 is equal to q"

Reference