Strings in JavaScript have many built-in methods that make text manipulation powerful and convenient:
// String creation
let single = 'Single quotes';
let double = "Double quotes";
let template = `Template literals allow ${single} and ${double}`;
// Basic string properties
let greeting = "Hello, World!";
console.log(greeting.length); // 13 (includes spaces and punctuation)
console.log(greeting[0]); // "H" (zero-indexed access)
console.log(greeting[7]); // "W"
// Common string methods
console.log(greeting.toLowerCase()); // "hello, world!"
console.log(greeting.toUpperCase()); // "HELLO, WORLD!"
console.log(greeting.indexOf("World")); // 7 (position where "World" starts)
console.log(greeting.includes("Hello")); // true
console.log(greeting.startsWith("Hello")); // true
console.log(greeting.endsWith("!")); // true
// String manipulation
console.log(greeting.replace("World", "JavaScript")); // "Hello, JavaScript!"
console.log(greeting.substring(0, 5)); // "Hello" (start at 0, end before 5)
console.log(greeting.slice(7)); // "World!" (from position 7 to end)
console.log(greeting.split(", ")); // ["Hello", "World!"]
// Trimming whitespace
let spacedText = " trim me ";
console.log(spacedText.trim()); // "trim me"
console.log(spacedText.trimStart()); // "trim me "
console.log(spacedText.trimEnd()); // " trim me"
// Template literals for multiline strings
let multiline = `This is line 1
This is line 2
This is line 3`;
console.log(multiline);
Many coding problems involve these string manipulation patterns:
// Reversing a string
function reverseString(str) {
return str.split('').reverse().join('');
}
console.log(reverseString("hello")); // "olleh"
// Checking for palindrome
function isPalindrome(str) {
// Remove non-alphanumeric characters and convert to lowercase
let cleanStr = str.toLowerCase().replace(/[^a-z0-9]/g, '');
return cleanStr === cleanStr.split('').reverse().join('');
}
console.log(isPalindrome("A man, a plan, a canal: Panama")); // true
// Counting character occurrences
function countChar(str, char) {
return str.split(char).length - 1;
}
console.log(countChar("banana", "a")); // 3
// Converting case
function camelToSnakeCase(camelCase) {
return camelCase.replace(/[A-Z]/g, letter => `_${letter.toLowerCase()}`);
}
console.log(camelToSnakeCase("thisIsACamelCaseString")); // "this_is_a_camel_case_string"
Arrays store ordered collections of data and provide methods to manipulate that data:
// Creating arrays
let fruits = ["apple", "banana", "orange"];
let numbers = [1, 2, 3, 4, 5];
let mixed = [1, "two", true, null, {name: "object"}];
let empty = [];
let newArray = new Array(3); // Creates array with 3 empty slots
// Accessing elements
console.log(fruits[0]); // "apple"
console.log(fruits[fruits.length - 1]); // "orange" (last element)
// Basic array properties
console.log(fruits.length); // 3
// Modifying arrays
fruits[1] = "pear"; // Replace item at index 1
console.log(fruits); // ["apple", "pear", "orange"]
// Adding elements
fruits.push("grape"); // Add to end
console.log(fruits); // ["apple", "pear", "orange", "grape"]
fruits.unshift("strawberry"); // Add to beginning
console.log(fruits); // ["strawberry", "apple", "pear", "orange", "grape"]
// Removing elements
let lastFruit = fruits.pop(); // Remove from end
console.log(lastFruit); // "grape"
console.log(fruits); // ["strawberry", "apple", "pear", "orange"]
let firstFruit = fruits.shift(); // Remove from beginning
console.log(firstFruit); // "strawberry"
console.log(fruits); // ["apple", "pear", "orange"]
// Finding elements
console.log(fruits.indexOf("pear")); // 1
console.log(fruits.includes("apple")); // true
// Joining and splitting
console.log(fruits.join(", ")); // "apple, pear, orange"
let sentence = "This is a sentence";
let words = sentence.split(" ");
console.log(words); // ["This", "is", "a", "sentence"]
Modern JavaScript provides powerful methods for working with array data:
let numbers = [1, 2, 3, 4, 5];
// forEach - performs an action for each element
numbers.forEach(num => {
console.log(num * 2);
}); // Outputs: 2, 4, 6, 8, 10
// map - creates a new array with transformed elements
let doubled = numbers.map(num => num * 2);
console.log(doubled); // [2, 4, 6, 8, 10]
// filter - creates a new array with elements that pass a test
let evens = numbers.filter(num => num % 2 === 0);
console.log(evens); // [2, 4]
// find - returns first element that passes a test
let firstEven = numbers.find(num => num % 2 === 0);
console.log(firstEven); // 2
// some - tests if any element passes a test
let hasEven = numbers.some(num => num % 2 === 0);
console.log(hasEven); // true
// every - tests if all elements pass a test
let allEven = numbers.every(num => num % 2 === 0);
console.log(allEven); // false
// reduce - reduces array to a single value
let sum = numbers.reduce((total, num) => total + num, 0);
console.log(sum); // 15
Common array operations for sorting, slicing, and combining:
// Sorting arrays
let letters = ['d', 'a', 'c', 'b'];
letters.sort();
console.log(letters); // ['a', 'b', 'c', 'd']
let nums = [10, 5, 8, 1, 7];
nums.sort((a, b) => a - b); // Numeric sort
console.log(nums); // [1, 5, 7, 8, 10]
// Reversing arrays
nums.reverse();
console.log(nums); // [10, 8, 7, 5, 1]
// Slicing arrays (doesn't modify original)
let fruits = ["apple", "banana", "orange", "grape", "mango"];
let citrus = fruits.slice(2, 4); // Start at index 2, end before index 4
console.log(citrus); // ["orange", "grape"]
// Splicing arrays (modifies original)
let veggies = ["carrot", "broccoli", "cucumber", "pepper"];
veggies.splice(1, 2, "spinach", "kale"); // Remove 2 items starting at index 1, insert new items
console.log(veggies); // ["carrot", "spinach", "kale", "pepper"]
// Combining arrays
let array1 = [1, 2, 3];
let array2 = [4, 5, 6];
let combined = array1.concat(array2);
console.log(combined); // [1, 2, 3, 4, 5, 6]
// Spread operator (modern way to combine)
let spreadCombined = [...array1, ...array2];
console.log(spreadCombined); // [1, 2, 3, 4, 5, 6]
Patterns that frequently appear in algorithm problems:
// Finding maximum value
function findMax(arr) {
return Math.max(...arr);
// Alternative: return arr.reduce((max, current) => Math.max(max, current), arr[0]);
}
console.log(findMax([3, 7, 2, 9, 5])); // 9
// Checking for duplicates
function hasDuplicates(arr) {
return new Set(arr).size !== arr.length;
}
console.log(hasDuplicates([1, 2, 3, 1])); // true
console.log(hasDuplicates([1, 2, 3])); // false
// Two Sum problem (find two numbers that add up to target)
function twoSum(nums, target) {
const map = new Map();
for (let i = 0; i < nums.length; i++) {
const complement = target - nums[i];
if (map.has(complement)) {
return [map.get(complement), i];
}
map.set(nums[i], i);
}
return null; // No solution found
}
console.log(twoSum([2, 7, 11, 15], 9)); // [0, 1]
// Flattening a nested array
function flatten(arr) {
return arr.reduce((flat, current) => {
return flat.concat(Array.isArray(current) ? flatten(current) : current);
}, []);
}
console.log(flatten([1, [2, 3], [4, [5, 6]]])); // [1, 2, 3, 4, 5, 6]
Understanding time complexity for common array operations:
When working with large arrays, prefer: