Keyed Collections
The ES6 keyed collections — Map, Set, WeakMap, and WeakSet — are not available in SSJS. The SFMC Jint engine predates ES2015, so all four are undefined and cannot be constructed.
The ES6 keyed collections are not available in SSJS. The SFMC server-side JavaScript engine (Jint) implements an ES3/ES5-era dialect and predates ES2015, so Map, Set, WeakMap, and WeakSet are entirely absent. Each is undefined, and new Map() (etc.) throws Unknown type: Map.
Status legend
| Icon | Meaning |
|---|---|
| ❌ Missing | Not available (typeof is "undefined"; new throws Unknown type) |
Members
| Member | ES | Status | Notes |
|---|---|---|---|
Map |
ES6 | ❌ Missing | Use a plain object as a string-keyed dictionary |
Set |
ES6 | ❌ Missing | Use a plain object whose keys are the members |
WeakMap |
ES6 | ❌ Missing | No weak-reference collections exist |
WeakSet |
ES6 | ❌ Missing | No weak-reference collections exist |
Map
(ES6) — ❌ Missing. Map is not defined — typeof Map === "undefined" and new Map() throws Unknown type: Map.
For string-keyed lookups, use a plain object as a dictionary:
// Instead of: var m = new Map(); m.set("a", 1);
var m = {};
m["a"] = 1;
Write(m["a"]); // 1
Write("a" in m ? "has" : "no"); // note: the `in` operator is unsafe in CloudPages —
// prefer: (typeof m["a"] != "undefined")
Object keys are always coerced to strings, so a plain object cannot key by object identity or preserve insertion order the way a real Map does. In this engine, using an object as a key does not even reach the string-coercion step — obj[objectKey] = value throws Object reference not set to an instance of an object.
Show test script
<script runat="server">
Platform.Load("core", "1.1.5");
/*
* Chapter: Map
*
* Proves:
* 1. DEVIATION from ECMAScript 2015 marked "DEV": Map does not exist in the
* SFMC Jint engine — typeof Map is "undefined" (spec: "function").
* 2. Constructing it throws "Unknown type: Map" (spec: returns a Map).
* 3. The recommended workaround — a plain object used as a string-keyed
* dictionary — really does store and retrieve values.
* 4. The documented pitfalls of that workaround: object keys are always
* coerced to strings, so a number key and its string form are one and
* the same key; and a plain object cannot key by object identity the way
* a real Map can — using an object as a key throws outright.
* 5. A plain object carries none of the Map API (get/set/has/size).
*
* NOTE: insertion-order preservation is not asserted — property enumeration
* order is implementation-defined, so there is no deterministic check for it.
*
* EXPECTED OUTPUT: every line starts with PASS. A FAIL means the runtime no
* longer matches the documented claim and the page must be revised.
*/
function assert(id, fn, expected) {
var got;
try { got = fn(); } catch (ex) { got = "THREW: " + ex.message; }
Platform.Response.Write((got === expected ? "PASS " : "FAIL ") + id + " -> [" + got + "]\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");
}
/* 1. DEVIATION — Map is absent. Reading the name does not throw; it is undefined. */
assert("DEV typeof Map is 'undefined' (spec: 'function')", function () { return String(typeof Map); }, "undefined");
/* 2. Constructing it throws the documented message. */
assertThrows("DEV new Map() throws (spec: returns a Map)", function () { return new Map(); });
assert("new Map() message is 'Unknown type: Map'", function () { try { return new Map(); } catch (ex) { return ex.message; } }, "Unknown type: Map");
/* 3. Workaround — a plain object as a string-keyed dictionary. */
assert("workaround m['a'] returns 1", function () { var m = {}; m["a"] = 1; return m["a"]; }, 1);
assert("workaround presence test via typeof", function () { var m = {}; m["a"] = 1; return typeof m["a"] != "undefined" ? "has" : "no"; }, "has");
assert("workaround absence test via typeof", function () { var m = {}; m["a"] = 1; return typeof m["zzz"] != "undefined" ? "has" : "no"; }, "no");
assert("workaround overwrite replaces the value", function () { var m = {}; m["a"] = 1; m["a"] = 2; return m["a"]; }, 2);
/* 4a. Pitfall — keys are coerced to strings, so 1 and "1" are the same key. */
assert("pitfall number key is readable as a string key", function () { var n = {}; n[1] = "numeric"; return n["1"]; }, "numeric");
assert("pitfall string key overwrites the number key", function () { var n = {}; n[1] = "numeric"; n["1"] = "stringy"; return n[1]; }, "stringy");
/* 4b. Pitfall — a plain object cannot key by object identity: using an object
* as a key does not even reach the string-coercion step, it throws. */
assertThrows("cannot key by object identity: obj[objKey] = v throws", function () { var k1 = {}; var byObj = {}; byObj[k1] = "first"; return byObj; });
assert("object-key write message", function () { try { var k1 = {}; var byObj = {}; byObj[k1] = "first"; return "did not throw"; } catch (ex) { return ex.message; } }, "Object reference not set to an instance of an object.");
/* 5. A plain object is not a Map — it has none of the Map API. */
assert("plain object has no .get", function () { var m = {}; return String(typeof m.get); }, "undefined");
assert("plain object has no .set", function () { var m = {}; return String(typeof m.set); }, "undefined");
assert("plain object has no .has", function () { var m = {}; return String(typeof m.has); }, "undefined");
assert("plain object has no .size", function () { var m = {}; return String(typeof m.size); }, "undefined");
</script>
Set
(ES6) — ❌ Missing. Set is not defined — typeof Set === "undefined" and new Set() throws Unknown type: Set.
Emulate a set of strings with a plain object whose keys are the members:
// Instead of: var s = new Set(); s.add("x");
var s = {};
s["x"] = true;
Write(typeof s["x"] != "undefined" ? "member" : "absent"); // "member"
Show test script
<script runat="server">
Platform.Load("core", "1.1.5");
/*
* Chapter: Set
*
* Proves:
* 1. DEVIATION from ECMAScript 2015 marked "DEV": Set does not exist in the
* SFMC Jint engine — typeof Set is "undefined" (spec: "function").
* 2. Constructing it throws "Unknown type: Set" (spec: returns a Set).
* 3. The recommended workaround — a plain object whose keys are the members —
* reports membership and non-membership correctly.
* 4. The workaround delivers the defining Set semantics: adding the same
* member twice does not duplicate it, so the key count equals the number
* of distinct members.
* 5. A plain object carries none of the Set API (add/has/size).
*
* EXPECTED OUTPUT: every line starts with PASS.
*/
function assert(id, fn, expected) {
var got;
try { got = fn(); } catch (ex) { got = "THREW: " + ex.message; }
Platform.Response.Write((got === expected ? "PASS " : "FAIL ") + id + " -> [" + got + "]\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");
}
function countKeys(o) {
var c = 0;
for (var k in o) { c = c + 1; }
return c;
}
/* 1. DEVIATION — Set is absent. */
assert("DEV typeof Set is 'undefined' (spec: 'function')", function () { return String(typeof Set); }, "undefined");
/* 2. Constructing it throws the documented message. */
assertThrows("DEV new Set() throws (spec: returns a Set)", function () { return new Set(); });
assert("new Set() message is 'Unknown type: Set'", function () { try { return new Set(); } catch (ex) { return ex.message; } }, "Unknown type: Set");
/* 3. Workaround — a plain object whose keys are the members. */
assert("workaround membership test", function () { var s = {}; s["x"] = true; return typeof s["x"] != "undefined" ? "member" : "absent"; }, "member");
assert("workaround non-membership test", function () { var s = {}; s["x"] = true; return typeof s["y"] != "undefined" ? "member" : "absent"; }, "absent");
/* 4. Duplicate adds do not duplicate the member. */
assert("workaround eliminates duplicates: 2 distinct members", function () { var s = {}; s["x"] = true; s["x"] = true; s["y"] = true; return countKeys(s); }, 2);
assert("workaround still reports x as a member after re-add", function () { var s = {}; s["x"] = true; s["x"] = true; return typeof s["x"] != "undefined" ? "member" : "absent"; }, "member");
/* 5. A plain object is not a Set. */
assert("plain object has no .add", function () { var s = {}; return String(typeof s.add); }, "undefined");
assert("plain object has no .has", function () { var s = {}; return String(typeof s.has); }, "undefined");
assert("plain object has no .size", function () { var s = {}; return String(typeof s.size); }, "undefined");
</script>
WeakMap
(ES6) — ❌ Missing. WeakMap is not defined — typeof WeakMap === "undefined" and new WeakMap() throws Unknown type: WeakMap. There is no weak-reference mechanism in this engine; use a plain object dictionary (which holds strong references) and delete keys manually when done.
Show test script
<script runat="server">
Platform.Load("core", "1.1.5");
/*
* Chapter: WeakMap
*
* Proves:
* 1. DEVIATION from ECMAScript 2015 marked "DEV": WeakMap does not exist in
* the SFMC Jint engine — typeof WeakMap is "undefined" (spec: "function").
* 2. Constructing it throws "Unknown type: WeakMap" (spec: returns a WeakMap).
* 3. The recommended fallback — a plain object dictionary with manual key
* deletion — stores a value and releases it again on delete. It holds a
* STRONG reference; there is no weak-reference mechanism to assert.
*
* EXPECTED OUTPUT: every line starts with PASS.
*/
function assert(id, fn, expected) {
var got;
try { got = fn(); } catch (ex) { got = "THREW: " + ex.message; }
Platform.Response.Write((got === expected ? "PASS " : "FAIL ") + id + " -> [" + got + "]\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");
}
/* 1. DEVIATION — WeakMap is absent. */
assert("DEV typeof WeakMap is 'undefined' (spec: 'function')", function () { return String(typeof WeakMap); }, "undefined");
/* 2. Constructing it throws the documented message. */
assertThrows("DEV new WeakMap() throws (spec: returns a WeakMap)", function () { return new WeakMap(); });
assert("new WeakMap() message is 'Unknown type: WeakMap'", function () { try { return new WeakMap(); } catch (ex) { return ex.message; } }, "Unknown type: WeakMap");
/* 3. Fallback — plain object dictionary with manual cleanup. */
assert("fallback stores a value", function () { var cache = {}; cache["k"] = "value"; return cache["k"]; }, "value");
assert("fallback releases the key on manual delete", function () { var cache = {}; cache["k"] = "value"; delete cache["k"]; return String(typeof cache["k"]); }, "undefined");
</script>
WeakSet
(ES6) — ❌ Missing. WeakSet is not defined — typeof WeakSet === "undefined" and new WeakSet() throws Unknown type: WeakSet. As with WeakMap, no weak-reference collection is available.
Show test script
<script runat="server">
Platform.Load("core", "1.1.5");
/*
* Chapter: WeakSet
*
* Proves:
* 1. DEVIATION from ECMAScript 2015 marked "DEV": WeakSet does not exist in
* the SFMC Jint engine — typeof WeakSet is "undefined" (spec: "function").
* 2. Constructing it throws "Unknown type: WeakSet" (spec: returns a WeakSet).
* 3. As stated for WeakMap, no weak-reference collection is available at all:
* none of the four ES6 keyed collection constructors exists.
*
* EXPECTED OUTPUT: every line starts with PASS.
*/
function assert(id, fn, expected) {
var got;
try { got = fn(); } catch (ex) { got = "THREW: " + ex.message; }
Platform.Response.Write((got === expected ? "PASS " : "FAIL ") + id + " -> [" + got + "]\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");
}
/* 1. DEVIATION — WeakSet is absent. */
assert("DEV typeof WeakSet is 'undefined' (spec: 'function')", function () { return String(typeof WeakSet); }, "undefined");
/* 2. Constructing it throws the documented message. */
assertThrows("DEV new WeakSet() throws (spec: returns a WeakSet)", function () { return new WeakSet(); });
assert("new WeakSet() message is 'Unknown type: WeakSet'", function () { try { return new WeakSet(); } catch (ex) { return ex.message; } }, "Unknown type: WeakSet");
/* 3. No keyed collection of any kind exists. */
assert("typeof Map is 'undefined' too", function () { return String(typeof Map); }, "undefined");
assert("typeof Set is 'undefined' too", function () { return String(typeof Set); }, "undefined");
assert("typeof WeakMap is 'undefined' too", function () { return String(typeof WeakMap); }, "undefined");
</script>