Data Types
Strings, numbers, booleans, null, undefined, objects, and arrays in SFMC SSJS.
Primitive Types
String
Strings use single or double quotes. No template literals (backticks).
var single = 'Hello';
var double = "World";
var combined = "Hello, " + "World!"; // concatenation only
var withNewline = "Line 1\nLine 2";
var withQuote = "He said \"hello\"";
var withTab = "col1\tcol2";
String length:
var str = "Hello";
var len = str.length; // 5
Number
Numbers are IEEE 754 doubles (same as JavaScript).
var integer = 42;
var decimal = 3.14;
var negative = -100;
var big = 1e6; // 1000000
var nan = NaN; // not a number
var inf = Infinity;
// Type checks
typeof 42 === "number"; // true
isNaN(NaN); // true
isFinite(Infinity); // false
Boolean
var yes = true;
var no = false;
// Falsy values in SSJS (same as JS):
// false, 0, "", null, undefined, NaN
// Truthy: everything else, including "0", "false", [], {}
if ("false") { Write("Truthy!"); } // will execute
null
Explicitly no value. Use for intentionally empty variables.
var result = null;
typeof null === "object"; // true (JS quirk)
result === null; // true
undefined
A variable that has been declared but not assigned.
var x;
typeof x === "undefined"; // true
x === undefined; // true
SFMC quirk: Platform.Function.Lookup() returns a genuine null when no matching row is found, but a CLR null when the row exists and the field is empty — and that value throws on any coercion, so !result is unsafe. Wrap the result in String() and test for "null" or "". See Lookup.
Show test script
<script runat="server">
/*
* Chapter: Primitive Types
* Proves:
* 1. string/number/boolean/null/undefined basics.
* 2. 'false' string is truthy.
* 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("concat", "Hello, " + "World!", "Hello, World!");
assert("len", "Hello".length, 5);
assert("typeof42", typeof 42, "number");
assert("isNaN", isNaN(NaN) ? "true" : "false", "true");
assert("isFinite Inf", isFinite(Infinity) ? "true" : "false", "false");
assert("typeof null", typeof null, "object");
var result = null; assert("===null", result === null ? "true" : "false", "true");
var x; assert("undef", typeof x, "undefined");
var branch = ""; if ("false") { branch = "Truthy!"; }
assert("false-string truthy", branch, "Truthy!");
</script>
Objects
Plain objects are key-value maps. Use them for structured data.
var subscriber = {
key: "abc123",
email: "jane@example.com",
active: true
};
// Access
var email = subscriber.email; // dot notation
var key = subscriber["key"]; // bracket notation
// Assign
subscriber.name = "Jane Smith";
subscriber["status"] = "confirmed";
// Check property exists
if (subscriber.hasOwnProperty("email")) {
// safe to access
}
// Iterate — always use hasOwnProperty
for (var prop in subscriber) {
if (subscriber.hasOwnProperty(prop)) {
Write(prop + ": " + subscriber[prop] + "<br>");
}
}
Always use
hasOwnPropertyinfor...inloops. SFMC objects may have inherited enumerable properties (like_type) that you don’t want to process.
Show test script
<script runat="server">
/*
* Chapter: Objects
* Proves:
* 1. dot/bracket/hasOwnProperty.
* 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 subscriber = { key: "abc123", email: "jane@example.com", active: true };
assert("dot", subscriber.email, "jane@example.com");
assert("bracket", subscriber["key"], "abc123");
subscriber.name = "Jane Smith";
assert("assign", subscriber.name, "Jane Smith");
assert("hasOwn", subscriber.hasOwnProperty("email") ? "true" : "false", "true");
</script>
Arrays
Arrays are ordered lists. SSJS has ES3/5-safe array operations.
var fruits = ["apple", "banana", "cherry"];
var nums = [1, 2, 3, 4, 5];
var mixed = ["text", 42, true, null];
// Access and length
var first = fruits[0]; // "apple"
var len = fruits.length; // 3
// Safe array methods (available in SSJS)
fruits.push("date"); // add to end (returns new length)
fruits.pop(); // remove from end
fruits.shift(); // remove from front
fruits.unshift("avocado"); // add to front
fruits.reverse(); // in-place reverse
fruits.sort(); // in-place sort (lexicographic)
// Slice (safe)
var sub = fruits.slice(1, 3); // ["banana", "cherry"] — no mutation
// String join
var str = fruits.join(", "); // "apple, banana, cherry"
Missing array methods — use polyfills or manual loops:
// ❌ These are NOT available in SSJS:
// arr.forEach(), arr.map(), arr.filter(), arr.find(), arr.indexOf()
// arr.every(), arr.some(), arr.reduce(), arr.includes()
// ✅ Manual equivalents:
for (var i = 0; i < arr.length; i++) {
var item = arr[i];
// process item
}
See Polyfills for ready-to-use Array method implementations.
Show test script
<script runat="server">
/*
* Chapter: Arrays
* Proves:
* 1. push/pop/slice/join basics.
* 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 fruits = ["apple", "banana", "cherry"];
assert("first", fruits[0], "apple");
assert("len", fruits.length, 3);
fruits.push("date");
assert("push len", fruits.length, 4);
fruits.pop();
var sub = ["apple", "banana", "cherry"].slice(1, 3);
assert("slice0", sub[0], "banana");
assert("join", ["a", "b"].join(", "), "a, b");
</script>
Type Conversions
// String to number
var n1 = Number("42"); // 42
var n2 = parseInt("42", 10); // 42 — argument must already be a clean integer string
var n3 = parseFloat("3.14"); // ~3.14 (IEEE float; do not compare with === to a decimal literal)
var n4 = "5" * 1; // 5 (implicit)
// Number to string
var s1 = String(42); // "42"
var s2 = 42 + ""; // "42" (concatenation coercion)
var s3 = (42).toString(); // "42"
// Boolean coercion
var b1 = Boolean(0); // false
var b2 = Boolean(""); // false
var b3 = Boolean("0"); // true (non-empty string!)
var b4 = !!value; // double-negation shorthand
Unlike browser JavaScript, parseInt("42px") returns NaN in SFMC SSJS — the engine does not stop at the first non-digit. Strip units before calling parseInt, or use Number(...) on a clean numeric string.
Show test script
<script runat="server">
/*
* Chapter: Type Conversions
* Proves:
* 1. Number/parseInt/String/Boolean on clean values.
* 2. DEV: parseInt("42px") is NaN (browser JS: 42).
* 3. parseFloat is IEEE — compare via Math.floor(x*100).
* 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("Number", Number("42"), 42);
assert("parseInt clean", parseInt("42", 10), 42);
assert("DEV parseInt('42px') is NaN (browser: 42)", isNaN(parseInt("42px", 10)) ? "true" : "false", "true");
assert("parseFloat ~3.14", Math.floor(parseFloat("3.14") * 100), 314);
assert("implicit", "5" * 1, 5);
assert("String", String(42), "42");
assert("concat coerce", 42 + "", "42");
assert("toString", (42).toString(), "42");
assert("Boolean0", Boolean(0) ? "true" : "false", "false");
assert("Boolean empty", Boolean("") ? "true" : "false", "false");
assert("Boolean '0'", Boolean("0") ? "true" : "false", "true");
</script>
JSON
SSJS does not have JSON.parse or JSON.stringify. Use the SFMC alternatives:
// Parse JSON string → object
var obj = Platform.Function.ParseJSON(jsonString + "");
// The + "" keeps a non-string value a valid argument — objects/arrays throw
// Serialize object → JSON string
var jsonStr = Platform.Function.Stringify(obj);
Show test script
<script runat="server">
/*
* Chapter: JSON
* Proves:
* 1. ParseJSON/Stringify round-trip.
* 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 obj = { name: "Jane", n: 1 };
var jsonStr = Platform.Function.Stringify(obj);
var parsed = Platform.Function.ParseJSON(jsonStr + "");
assert("name", parsed.name, "Jane");
assert("n", parsed.n, 1);
</script>