The Testing Academy · Class Notes Saturday, 8 August (IST)
Live class · study guide

JavaScript strings, objects, and call by reference

Extracting parts of a string with slice and substring, reversing a string with a loop instead of a built-in, and the difference between call by value and call by reference once objects enter the picture.

By Pramod Dutta, The Testing Academy. Study notes from the live JavaScript class, rebuilt from the session recording. Code is reproduced as it was written on screen, with the output the class saw.

01

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
02

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.

JavaScript
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:

JavaScript
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.

03

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:

JavaScript
"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:

JavaScript
"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:

JavaScript
(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.

04

Strings are immutable

Assigning to a position does not change the string. It fails quietly and the original survives:

JavaScript
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.

05

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.

JavaScript
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.

06

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.

JavaScript
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.

JavaScript
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:

JavaScript
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:

JavaScript
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.

07

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:

JavaScript
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:

JavaScript
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:

  • const on 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.

08

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.