The part of Marketing Cloud that handles SSJS is a derelict .NET app and thus the version of Jint, a C# JavaScript interpreter, used to run your script is an incomplete implementation of the ECMAScript 3.0 spec. Array
's iterative methods like indexOf
, map
, and reduce
didn't appear until ES5. If you want to use them, you'll need to polyfill. For example, here's the Array.prototype.indexOf
polyfill from MDN, modified so Marketing Cloud's JavaScript interpreter won't panic:
if (!Array.prototype.indexOf) {
Array.prototype.indexOf = (function (Obj, max, min) {
'use strict'
return function indexOf (member, fromIndex) {
if (this === null || this === undefined) {
throw TypeError('Array.prototype.indexOf called on null or undefined')
}
var that = new Obj(this)
var len = that.length
var i = min(fromIndex || 0, len)
if (i < 0) {
i = max(0, len + i)
} else if (i >= len) {
return -1
}
if (member === undefined) {
for (; i !== len; ++i) {
if (that[i] === undefined && i in that) {
return i // undefined
}
}
} else if (member !== member) {
for (; i !== len; ++i) {
if (that[i] !== that[i]) {
return i // NaN
}
}
} else {
for (; i !== len; ++i) {
if (that[i] === member) {
return i // all else
}
}
}
return -1 // if the value was not found, then return -1
}
}(Object, Math.max, Math.min))
}
Here are some general tips on tweaking polyfills for use in SSJS:
- Always use
new
keyword with constructors, even those for which it's commonly omitted, like Object()
, Array()
, and Error()
. It is safe to use your discretion for the Boolean()
and String()
constructors.
instanceof
is seriously broken. Find an alternative check.
- There is no
__proto__
, only Zuul prototype
: Get it with <BuiltIn>.prototype
for built-ins and objects with type "clr"
or "clrmethodinfo
", and Object.getPrototypeOf(obj)
for everything else; set it like obj.prototype = proto
.
- Bitwise operators are buggy because:
- Operands are cast from JavaScript's double precision numbers to UInt64 in C# prior to applying the operation. This can cause the engine to throw integer overflow errors when Jint tries to pack the numbers back into an UInt32. I'm not certain under which conditions Jint will cast to Float64 or UInt32.
- In most JavaScript engines,
~8
(1000
) yields -9
(-1001
); as executed by Jint, operations affect all 64 bits of a UInt64, not just the shortest array of bits necessary to represent the number; thus, ~8
(1000
) becomes 18446744073709551607
(1111111111111111111111111111111111111111111111111111111111110111
). As Float64s are very holey as N gets very large or very small, the JavaScript value becomes 18446744073709600000
after coercion and rounding.
Object
is the constructor of all constructors, not Function
, and functions do not inherit from Function.prototype
. You'll find yourself in a bind trying to implement Function.prototype.bind
.