Arithmetic

var a = 10, b = 3;

a + b;   // 13
a - b;   // 7
a * b;   // 30
a / b;   // 3.333...
a % b;   // 1 (modulo)

// Increment / decrement
var n = 0;
n++;   // post-increment
++n;   // pre-increment
n--;   // post-decrement
--n;   // pre-decrement
Show test script
<script runat="server">
/*
 * Chapter: Arithmetic
 * Proves:
 *   1. + - * / % and ++/--.
 * EXPECTED OUTPUT: every line starts with PASS.
 */
function assert(id, actual, expected) {
    Platform.Response.Write((actual === expected ? "PASS " : "FAIL ") + id + " -> [" + actual + "]\n");
}
function assertThrows(id, fn) {
    var threw = false, msg = "";
    try { fn(); } catch (ex) { threw = true; msg = "" + ex.message; }
    Platform.Response.Write((threw ? "PASS " : "FAIL ") + id + " -> " + (threw ? "threw: " + msg : "did NOT throw") + "\n");
}
var a = 10, b = 3;
assert("add", a + b, 13);
assert("sub", a - b, 7);
assert("mul", a * b, 30);
assert("div floor*1000", Math.floor((a / b) * 1000), 3333);
assert("mod", a % b, 1);
var n = 0; n++; assert("inc", n, 1); ++n; assert("preinc", n, 2); n--; assert("dec", n, 1); --n; assert("predec", n, 0);
</script>

String Concatenation

+ concatenates strings. When mixing types, JavaScript coerces non-strings:

"Hello, " + "World"   // "Hello, World"
"Count: " + 42        // "Count: 42"
"Sum: " + (1 + 2)     // "Sum: 3" (parentheses force arithmetic first)
"Sum: " + 1 + 2       // "Sum: 12" (left-to-right string concat!)

Concatenating across multiple lines:

var html = '<div class="profile">' +
           '<h2>' + name + '</h2>' +
           '<p>' + email + '</p>' +
           '</div>';
Show test script
<script runat="server">
/*
 * Chapter: String Concatenation
 * Proves:
 *   1. Documented concat coercion.
 * EXPECTED OUTPUT: every line starts with PASS.
 */
function assert(id, actual, expected) {
    Platform.Response.Write((actual === expected ? "PASS " : "FAIL ") + id + " -> [" + actual + "]\n");
}
function assertThrows(id, fn) {
    var threw = false, msg = "";
    try { fn(); } catch (ex) { threw = true; msg = "" + ex.message; }
    Platform.Response.Write((threw ? "PASS " : "FAIL ") + id + " -> " + (threw ? "threw: " + msg : "did NOT throw") + "\n");
}
assert("hw", "Hello, " + "World", "Hello, World");
assert("count", "Count: " + 42, "Count: 42");
assert("paren", "Sum: " + (1 + 2), "Sum: 3");
assert("ltr", "Sum: " + 1 + 2, "Sum: 12");
</script>

Comparison

// Loose equality (type coercion)
5 == "5"     // true — avoid this
null == undefined // true

// Strict equality (no coercion) — PREFERRED
5 === 5      // true
5 === "5"    // false
null === undefined // false

// Inequality
5 != "5"     // false (loose)
5 !== "5"    // true  (strict — preferred)

// Relational
5 > 3        // true
5 >= 5       // true
3 < 5        // true
3 <= 3       // true

// String comparison (lexicographic)
"b" > "a"    // true
"banana" > "apple" // true

Use strict equality (=== and !==) to avoid subtle type coercion bugs.

Show test script
<script runat="server">
/*
 * Chapter: Comparison
 * Proves:
 *   1. Loose vs strict equality.
 * EXPECTED OUTPUT: every line starts with PASS.
 */
function assert(id, actual, expected) {
    Platform.Response.Write((actual === expected ? "PASS " : "FAIL ") + id + " -> [" + actual + "]\n");
}
function assertThrows(id, fn) {
    var threw = false, msg = "";
    try { fn(); } catch (ex) { threw = true; msg = "" + ex.message; }
    Platform.Response.Write((threw ? "PASS " : "FAIL ") + id + " -> " + (threw ? "threw: " + msg : "did NOT throw") + "\n");
}
assert("loose", 5 == "5" ? "true" : "false", "true");
assert("null==undef", null == undefined ? "true" : "false", "true");
assert("strict num", 5 === 5 ? "true" : "false", "true");
assert("strict mismatch", 5 === "5" ? "true" : "false", "false");
assert("null===undef", null === undefined ? "true" : "false", "false");
assert("!==", 5 !== "5" ? "true" : "false", "true");
assert(">", 5 > 3 ? "true" : "false", "true");
assert("str>", "b" > "a" ? "true" : "false", "true");
</script>

Logical Operators

// AND — returns first falsy or last truthy
true && true   // true
true && false  // false
"a" && "b"    // "b" (last truthy)
"" && "b"     // "" (first falsy)

// OR — returns first truthy or last falsy
false || true  // true
"a" || "b"    // "a" (first truthy)
"" || "b"     // "b" (first truthy)
null || "default" // "default"

// NOT
!true    // false
!false   // true
!""      // true (empty string is falsy)
!"text"  // false
!!value  // double-negation → boolean coercion

Short-circuit defaults pattern:

// Provide fallback values using || (no ?? operator in SSJS)
var name    = Platform.Request.GetQueryStringParameter("name") || "Subscriber";
var timeout = config.timeout || 30;
var debug   = options.debug || false;

Note: || returns the first truthy value — 0 and "" are falsy, so this won’t work if 0 or "" are valid values. In those cases, use explicit checks:

var count = (options.count !== undefined && options.count !== null)
            ? options.count
            : 0;
Show test script
<script runat="server">
/*
 * Chapter: Logical Operators
 * Proves:
 *   1. && || ! returns.
 * EXPECTED OUTPUT: every line starts with PASS.
 */
function assert(id, actual, expected) {
    Platform.Response.Write((actual === expected ? "PASS " : "FAIL ") + id + " -> [" + actual + "]\n");
}
function assertThrows(id, fn) {
    var threw = false, msg = "";
    try { fn(); } catch (ex) { threw = true; msg = "" + ex.message; }
    Platform.Response.Write((threw ? "PASS " : "FAIL ") + id + " -> " + (threw ? "threw: " + msg : "did NOT throw") + "\n");
}
assert("and", true && true ? "true" : "false", "true");
assert("and last", "a" && "b", "b");
assert("and first falsy", "" && "b", "");
assert("or first", "a" || "b", "a");
assert("or fallback", "" || "b", "b");
assert("null or", null || "default", "default");
assert("not true", !true ? "true" : "false", "false");
assert("not empty", !"" ? "true" : "false", "true");
var options = {};
var count = (options.count !== undefined && options.count !== null) ? options.count : 0;
assert("explicit 0 default", count, 0);
</script>

Ternary Operator

var message = isLoggedIn ? "Welcome back!" : "Please log in.";

// Nested (use sparingly — hard to read)
var label = count === 0 ? "none" : (count === 1 ? "one" : "many");
Show test script
<script runat="server">
/*
 * Chapter: Ternary Operator
 * Proves:
 *   1. Ternary branches.
 * EXPECTED OUTPUT: every line starts with PASS.
 */
function assert(id, actual, expected) {
    Platform.Response.Write((actual === expected ? "PASS " : "FAIL ") + id + " -> [" + actual + "]\n");
}
function assertThrows(id, fn) {
    var threw = false, msg = "";
    try { fn(); } catch (ex) { threw = true; msg = "" + ex.message; }
    Platform.Response.Write((threw ? "PASS " : "FAIL ") + id + " -> " + (threw ? "threw: " + msg : "did NOT throw") + "\n");
}
assert("t", true ? "Welcome back!" : "Please log in.", "Welcome back!");
assert("f", false ? "Welcome back!" : "Please log in.", "Please log in.");
assert("nested", 0 === 0 ? "none" : (1 === 1 ? "one" : "many"), "none");
</script>

Assignment Operators

var x = 5;
x += 3;  // x = x + 3  → 8
x -= 2;  // x = x - 2  → 6
x *= 4;  // x = x * 4  → 24
x /= 6;  // x = x / 6  → 4
x %= 3;  // x = x % 3  → 1
Show test script
<script runat="server">
/*
 * Chapter: Assignment Operators
 * Proves:
 *   1. += -= *= /= %=.
 * EXPECTED OUTPUT: every line starts with PASS.
 */
function assert(id, actual, expected) {
    Platform.Response.Write((actual === expected ? "PASS " : "FAIL ") + id + " -> [" + actual + "]\n");
}
function assertThrows(id, fn) {
    var threw = false, msg = "";
    try { fn(); } catch (ex) { threw = true; msg = "" + ex.message; }
    Platform.Response.Write((threw ? "PASS " : "FAIL ") + id + " -> " + (threw ? "threw: " + msg : "did NOT throw") + "\n");
}
var x = 5; x += 3; assert("+=", x, 8); x -= 2; assert("-=", x, 6); x *= 4; assert("*=", x, 24); x /= 6; assert("/=", x, 4); x %= 3; assert("%=", x, 1);
</script>

typeof

typeof "string"   // "string"
typeof 42         // "number"
typeof true       // "boolean"
typeof undefined  // "undefined"
typeof null       // "object" (JS quirk)
typeof {}         // "object"
typeof []         // "object"
typeof function(){} // "function"

Use typeof for safe existence checks:

if (typeof myVar !== "undefined") {
    // myVar has been declared and assigned
}
Show test script
<script runat="server">
/*
 * Chapter: typeof
 * Proves:
 *   1. typeof results including null quirk.
 * EXPECTED OUTPUT: every line starts with PASS.
 */
function assert(id, actual, expected) {
    Platform.Response.Write((actual === expected ? "PASS " : "FAIL ") + id + " -> [" + actual + "]\n");
}
function assertThrows(id, fn) {
    var threw = false, msg = "";
    try { fn(); } catch (ex) { threw = true; msg = "" + ex.message; }
    Platform.Response.Write((threw ? "PASS " : "FAIL ") + id + " -> " + (threw ? "threw: " + msg : "did NOT throw") + "\n");
}
assert("str", typeof "string", "string");
assert("num", typeof 42, "number");
assert("bool", typeof true, "boolean");
assert("undef", typeof undefined, "undefined");
assert("null", typeof null, "object");
assert("obj", typeof {}, "object");
assert("arr", typeof [], "object");
assert("fn", typeof function () {}, "function");
var myVar = 1;
assert("existence check", typeof myVar !== "undefined" ? "true" : "false", "true");
</script>

Bitwise (rarely needed)

5 & 3    // 1   (AND)
5 | 3    // 7   (OR)
5 ^ 3    // 6   (XOR)
5 << 1   // 10  (left shift)
5 >> 1   // 2   (right shift)
5 >>> 0  // 5   (unsigned right shift)
(-1) | 0     // throws: Arithmetic operation resulted in an overflow.
(-1) >>> 0   // throws: Arithmetic operation resulted in an overflow.
5 & (-1)     // throws: Arithmetic operation resulted in an overflow.
5 << (-1)    // throws: Value was either too large or too small for a UInt16.
~ is broken for every operand

Bitwise NOT never computes -(x + 1). ~0, ~1, ~2, ~5 and ~255 all return the same constant 1.84467440737096e+19 (264), so ~5 === -6 is false and even ~5 < 0 is false. Use -(x + 1) instead of ~x, and never use ~indexOf(…) as a truthiness idiom — see Known Bugs.

~5          // 1.84467440737096e+19  — expected -6
~5 === -6   // false
-(5 + 1)    // -6  — the working alternative

<< also does not truncate its result to 32 bits (0x80000000 << 1 returns 4294967296, not 0), so bitwise code cannot rely on 32-bit wrap-around.

Show test script
<script runat="server">
/*
 * Chapter: Bitwise
 * Proves:
 *   1. Positive bitwise ops match documented results.
 *   2. DEV: negative operands throw.
 *   3. DEV: ~ is broken; -(x+1) works.
 * EXPECTED OUTPUT: every line starts with PASS.
 */
function assert(id, actual, expected) {
    Platform.Response.Write((actual === expected ? "PASS " : "FAIL ") + id + " -> [" + actual + "]\n");
}
function assertThrows(id, fn) {
    var threw = false, msg = "";
    try { fn(); } catch (ex) { threw = true; msg = "" + ex.message; }
    Platform.Response.Write((threw ? "PASS " : "FAIL ") + id + " -> " + (threw ? "threw: " + msg : "did NOT throw") + "\n");
}
assert("AND", 5 & 3, 1);
assert("OR", 5 | 3, 7);
assert("XOR", 5 ^ 3, 6);
assert("<<", 5 << 1, 10);
assert(">>", 5 >> 1, 2);
assert(">>>", 5 >>> 0, 5);
assertThrows("DEV (-1)|0 throws", function () { return (-1) | 0; });
assertThrows("DEV 5&(-1) throws", function () { return 5 & (-1); });
assertThrows("DEV 5<<(-1) throws", function () { return 5 << (-1); });
var tilde = ~5;
assert("DEV ~5 is not -6", tilde === -6 ? "true" : "false", "false");
assert("workaround -(5+1)", -(5 + 1), -6);
assert("DEV << no 32-bit wrap", (0x80000000 << 1) === 0 ? "true" : "false", "false");
</script>