Where strings left off
A string is a sequence of characters, and JavaScript stores one much like an array: characters sit in consecutive slots with an index starting at 0.
- Three ways to create one. Double quotes, single quotes, or a template literal.
- Length and last index are different numbers.
"hello world"has a length of 13, so its indexes run 0 to 12. That gap is the source of most off-by-one bugs. - Where strings show up in testing work. URLs, selectors, assertions, response messages, and log parsing.
Every character also carries a numeric ASCII code, reachable with charCodeAt().
Three ways to read a single character, and they fail differently:
| Access | Out of range returns | Negative index | Notes |
|---|---|---|---|
str[i] |
undefined |
not supported | Direct index access |
str.charAt(i) |
empty string | not supported | Works on older browsers |
str.at(i) |
undefined |
supported, -1 is the last character |
Newer method |
Extracting part of a string
slice(start, end) cuts a section out. The end index is not included, so the characters you get run from start up to end - 1.
const str = "login_test_pass";
str.slice(0, 5); // "login"
str.slice(11); // "pass" (index 11 to the end)
str.slice(-3); // "ass" (last three characters)
The class read the first example aloud as "0 to 4", which is the index positions being counted out (0, 1, 2, 3, 4). Written as code that is slice(0, 5), because the second argument stops one short.
substring(start, end) does the same job with one restriction:
str.substring(6, 10); // "test"
str.substring(-3); // negative values are not supported, treated as 0
Slice is the array method splice you already know, minus the mutation. slice returns a copy and leaves the original alone.
The method cheat sheet
A cheat sheet covering the full set was shared in the class notes. These are the ones that carry most of the work:
| Group | Methods |
|---|---|
| Length and characters | length, charAt(), at(), charCodeAt(), codePointAt() |
| Searching | indexOf(), lastIndexOf(), includes(), startsWith(), endsWith() |
| Extracting | slice(), substring() |
| Splitting and joining | split(), join(), concat() |
| Case and whitespace | toUpperCase(), toLowerCase(), trim(), trimStart(), trimEnd() |
| Replacing | replace(), replaceAll() |
| Converting | toString(), parseInt(), Number() |
codePointAt() exists for Unicode characters such as emoji, and rarely comes up in day-to-day test code.
Splitting turns a string into an array, and joining turns it back:
"a,b,c".split(","); // ["a", "b", "c"]
"abc".split(""); // ["a", "b", "c"] (split on nothing, character by character)
["qa", "sdet", "ai"].join(" > "); // "qa > sdet > ai"
Replacing accepts a plain string or a pattern. The g flag means global, so every match is replaced rather than just the first:
"app.qa.app.com".replace(/app/g, "qa"); // "qa.qa.qa.com"
Converting matters most in API testing, where a response field arrives as one type and the assertion needs the other:
(200).toString(); // "200"
parseInt("200px"); // 200
toString() throws on null and undefined. String(null) returns "null" instead, so the wrapper function is the safe choice when the value might be missing.
Regular expressions were named several times and deliberately held back: a dedicated Regex 101 session runs on a Friday evening in the last week of August, 8:00 PM IST. The matching methods and the flag meanings (g, \d, \w) belong to that session. The companion tutorial is already live if you want a head start.
Strings are immutable
Assigning to a position does not change the string. It fails quietly and the original survives:
let str = "hello";
str[0] = "X";
console.log(str); // "hello"
The methods that look like they edit a string do not: toUpperCase() and friends return a new string and leave the original untouched. Reassign the variable if you want the change to stick.
The silent failure above is non-strict mode behaviour. Under "use strict" the same assignment throws a TypeError instead. Either way the string never changes, which is the point worth remembering.
Java's StringBuffer and StringBuilder have no JavaScript equivalent. They solve a problem JavaScript handles differently, so do not go looking for them here.
Interview drill: reverse a string with a loop
The coding-practice platform now carries 150 questions, with more than 26 on strings alone. Reverse is the one that opens the set.
const str = "hello";
let reverse = "";
for (let i = str.length - 1; i >= 0; i--) {
reverse = reverse + str[i];
}
console.log(reverse); // "olleh"
Two details decide whether this works. The loop starts at str.length - 1 because length is 5 while the last index is 4. It ends at i >= 0 rather than i > 0, because index 0 holds a character that has to be counted.
The trace, one pass per row:
| i | str[i] |
reverse after the pass |
|---|---|---|
| 4 | o | "o" |
| 3 | l | "ol" |
| 2 | l | "oll" |
| 1 | e | "olle" |
| 0 | h | "olleh" |
Reverse a string without using split(), reverse() or join(). On the practice platform, built-in-only answers are rejected, so the loop is the answer that scores.
In a live interview the order flips: give the short built-in answer first, and when the interviewer asks for it without built-ins, produce the loop. Knowing both is the point.
Today's task: write a program to check whether a string is a palindrome. A string is a palindrome when it equals its own reverse, so the loop above already does most of the work.
Objects are key-value pairs, not OOP objects
An object in JavaScript is a set of key and value pairs inside curly braces. This is not the object of classes and constructors. The closest thing in another language is a Java HashMap or a Python dictionary.
const result = { status: "pass", browser: "chrome", retries: 2 };
result.status; // "pass" dot notation
result["status"]; // "pass" bracket notation
result['status']; // "pass" single quotes work too
Keys are case-sensitive: status and Status are two different keys that can both exist in the same object.
JSON looks almost identical and is not the same thing. JSON requires double quotes around every key; a JavaScript object literal does not.
const obj = { status: "pass" }; // JavaScript object
const json = { "status": "pass" }; // JSON shape, double-quoted key
Keys can be added, updated and deleted after creation, values can be nested objects or arrays, and a value can even be a function, which makes the object behave like a small class with both data and behaviour:
const user = {
name: "Pramod",
getName: function () {
return this.name;
}
};
user.getName(); // "Pramod"
this refers to the object the method is attached to. A plain object literal has no constructor.
This is not academic. Playwright test data, generated fake users, and config blocks are all objects:
const data = { username: "admin", password: "secret", expectedResult: "dashboard" };
// used later as data.username, data.password, data.expectedResult
Getters and setters, object methods in depth, and callbacks and promises were named as upcoming topics and were not covered in this session.
Call by value vs call by reference
The interview question hiding behind objects. Primitives copy their value; objects copy their reference.
Primitives, where the copy is independent:
let a = 10;
let b = a;
b = 99;
console.log(a); // 10
console.log(b); // 99
Objects, where both names point at the same thing:
let a = { status: "pass" };
let b = a;
b.status = "fail";
console.log(a.status); // "fail"
console.log(b.status); // "fail"
| Primitives | Objects | |
|---|---|---|
| What gets copied | the value | the reference |
| Types | number, string, boolean | object, array, function |
| Change the copy | original is untouched | original changes too |
| Name | call by value | call by reference |
Two more consequences worth carrying into an interview:
conston an object locks the reference, not the contents. You cannot point the name at a different object, but you can still change the values inside it.- Two objects with identical contents are not the same object. They sit at different references, so comparing them directly returns false.
The analogy from class: two friends in an exam. The one who knows the answers writes his own, so when you change yours nothing happens to his, that is call by value. The one copying off your paper changes the moment you change, that is call by reference, and both of you make the same mistake.
Copying by reference is the sharper edge of the two: a function handed an object can quietly modify the caller's data.
Homework and announcements
- Today's task: the palindrome program, linked as a task on the practice platform.
- Practice: the string set on the coding-practice platform, 26 or more interview questions.
- Regex 101: Friday evening in the last week of August, 8:00 PM IST. An extra session on regular expressions. The in-depth tutorial is already published.
- Claude 101 part two: Tuesday evening, completing the certification.
- Questions: taken in the Tuesday morning class. Use the doubt thread until then.
- Today's code is pushed to the class repository.