This page describes how OCaml values are represented at runtime in JavaScript. Understanding this is useful for debugging, writing JavaScript primitives, and understanding compatibility limitations.
Js_of_ocaml maps OCaml values to JavaScript values as directly as possible for performance. This differs from the standard OCaml runtime representation.
OCaml type | JavaScript representation |
| Number (32-bit) |
| Number (unboxed) |
| Number (0 or 1) |
| Number (0-255) |
| Special string object (MlBytes) or JavaScript string |
| Special bytes object (MlBytes) |
| JavaScript Array with tag |
| JavaScript Array with tag 0 |
| JavaScript Array with tag 0 |
| Number (constant) or Array (with arguments) |
| Number (32-bit) |
| Number (32-bit) |
| MlInt64 object |
| Ml_Bigarray object |
| Array with exception identity |
| Array with method table and instance variables |
OCaml integers are represented as JavaScript numbers. Unlike native OCaml where integers are 31 or 63 bits (with one bit used for tagging), js_of_ocaml uses the full 32-bit range.
Implications:
max_int and min_int have different values than native OCamlOCaml floats are JavaScript numbers directly.
Implications:
Rounding difference: JavaScript rounds ties away from zero, while native OCaml (libc) rounds ties to even.
OCaml booleans are represented as the numbers 0 (false) and 1 (true), not JavaScript's true and false. See type conversions for converting between them.
OCaml bytes are always represented as MlBytes objects with:
t — tag indicating the encodingl — length in bytesc — contents (a JavaScript string or array of bytes)The contents can be a JavaScript string (more memory efficient) or an array of bytes (for mutation). The runtime converts between these as needed.
OCaml strings can be represented as:
--enable use-js-string is set, which is the default)Important: Even when represented as a JavaScript string, it encodes a sequence of bytes, not UTF-16 text. Each character's code point represents one byte (0-255). Assuming the bytes are UTF-8 encoded text, use Js.string to convert to a native UTF-16 JavaScript string. To convert back, use Js.to_string. See conversions.
OCaml heap-allocated values (arrays, tuples, records, variant constructors with arguments) are represented as JavaScript arrays where:
For example, Some 42 becomes [0, 42] (tag 0, one field).
type t =
| A (* 0 *)
| B (* 1 *)
| C of int (* [0, n] — tag 0, since it's the first non-constant *)
| D of int (* [1, n] — tag 1 *)Int32.t and Nativeint.t are represented directly as JavaScript numbers, like regular int values.
Note that nativeint is 32 bits in js_of_ocaml (matching JavaScript's bitwise operations), not the platform's native word size.
Int64.t values are represented as MlInt64 objects, which store the value as three numbers: two 24-bit integers (lo, mi) and one 16-bit integer (hi), since JavaScript numbers cannot represent the full 64-bit range precisely.
Bigarrays are represented as Ml_Bigarray objects, which use JavaScript Typed Arrays for storing the underlying data:
OCaml kind | JavaScript Typed Array |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
OCaml exceptions are represented as:
For example, Not_found is just its identity object, while Failure "oops" becomes [0, <Failure identity>, "oops"] (index 0 is the block tag).
Note: OCaml exceptions are not JavaScript Error objects. When an OCaml exception propagates to JavaScript code, it appears as an array, not an Error. See error handling for how to work with exceptions across the OCaml/JavaScript boundary.
OCaml objects (from the object-oriented layer) are implemented using JavaScript arrays. They have nothing to do with JavaScript objects. Use the PPX syntax (object%js) to create JavaScript objects.
Due to representation differences, some operations behave differently:
Marshalling (Marshal module):
Polymorphic comparison and hashing: