JS::Value
(also accessible using the jsval
typedef
, although this is deprecated) is the type of JavaScript values in the JSAPI.
A C++ variable of type JS::Value
represents a value in JavaScript: a string, number, object (including arrays and functions), boolean, symbol, null
, or undefined
.
JS::Value
is a class whose internal structure is an implementation detail. Embeddings should not rely on observed representation details or upon the size of JS::Value
.
The data in a JS::Value
can be accessed using these member functions:
JS type | JS::Value type tests |
Constructor | Accessors | Mutators |
---|---|---|---|---|
null |
val.isNull() |
JS::NullValue() |
N/A | val.setNull() |
undefined |
val.isUndefined() |
JS::UndefinedValue() |
N/A | val.setUndefined() |
boolean | val.isBoolean() , val.isTrue(), val.isFalse() |
JS::BooleanValue(bool) , JS::TrueValue() , JS::FalseValue() |
val.toBoolean() |
val.setBoolean(bool) |
number | val.isInt32() , val.isDouble(), val.isNumber() |
JS::NumberValue(any number type) , JS::Int32Value(int32_t) , JS::DoubleValue(double) , JS::Float32Value(float) |
val.toInt32() , val.toDouble() , val.toNumber() |
val.setInt32(int32_t) , val.setNumber(uint32_t) , val.setNumber(double) |
string | val.isString() |
JS::StringValue(JSString*) |
val.toString() |
val.setString(JSString *) |
object | val.isObject() |
JS::ObjectValue(JSObject&) , JS::ObjectOrNullValue(JSObject*) |
val.toObject() |
val.setObject(JSObject &) |
symbol | val.isSymbol() |
JS::SymbolValue(JS::Symbol*) |
val.toSymbol() |
val.setSymbol(JS::Symbol &) |
Numbers are stored in a JS::Value
either as a double
or as an int32_t
. The different representations are visible using the separate int32/double methods but do not affect observable semantics (ignoring performance). The number mutators attempt to use int32_t
representation for compatible input values, returning true
when int32
could be used and false
when double
representation was required. Any double
value may be stored in a JS::Value
, in one of these two representations. The only exception is that only a single NaN
value can be represented. (Note that both -0
and +0
are allowed, and the latter may sometimes be stored using the int32_t
representation.)
JS::Value
further provides these methods combining various aspects of the above methods:
JS::ObjectOrNullValue(JSObject*)
returns an object value corresponding to the given non-null pointer, or anull
value if the pointer is null.val.setObjectOrNull(JSObject *)
sets the given value to the specified object, or tonull
if the pointer was null.val.isObjectOrNull()
returnstrue
if the value is either an object orundefined
.- Correspondingly,
val.toObjectOrNull()
returns a non-nullJSObject *
if the value is an object, andNULL
if the value isnull
. val.isPrimitive()
returnstrue
if the value is a primitive value -- that is, not an object. It is equivalent to!val.isObject()
.val.isNullOrUndefined()
returnstrue
if the value is eithernull
orundefined
.val.isGCThing()
returnstrue
if a JS value has a type that is subject to garbage collection.
The are two major issues to be aware of when using JS::Value
.
JS::Value
is not inherently type-safe- It is an error to call any accessor method on a value of a non-matching type:
val.toInt32()
must only be called ifval.isInt32()
,val.toString()
must only be called ifval.isString()
, and so on. - In particular, note that it is an error to call
val.toObject()
whenval.isNull()
. The now-deprecatedjsval
methods allowedJSVAL_TO_OBJECT(val)
whenJSVAL_IS_NULL(val)
, but this was a source of constant bugs.val.toObject()
is only permitted whenval.isObject()
. An assertion is thrown in the case that the type is not correct (val.isX()
is called for eachval.toX()
, whereX
is the type). - It is highly recommended that you develop and test with an
--enable-debug
build to detect mostJS::Value
misuse. Debug builds will assert correct JSAPI use in many other instances as well. JS::Value
is subject to garbage collection- A
JS::Value
can refer to a string or object located in SpiderMonkey's garbage-collected heap. - The garbage collector is designed to automatically free unreachable memory. It is rather eager about its job. It's like a robot that goes around picking up everything that isn't nailed down and putting it in the trash. If an application has a
JS::Value
variable that refers to aJSObject
, the garbage collector might not know you're using theJSObject
. So it might free it, leaving a dangling pointer. The solution is to tell SpiderMonkey that you're using the object, then tell it again when you're done. - In short, every
JS::Value
must be rooted or your program will randomly crash. In some places, SpiderMonkey provides already-rootedJS::Value
s which you can use for variables. See SpiderMonkey GC Rooting Guide.
The jsval
typedef
for JS::Value
JS::Value
was historically known in the JSAPI as jsval
. SpiderMonkey 1.8.5 made jsval
into a C struct
and exposed it in C++ through the full-fledged JS::Value
class. As of SpiderMonkey 17, jsval
is a typedef
of JS::Value
, and SpiderMonkey is gradually transitioning to a new C++ JSAPI, at whose heart lies JS::Value
.
jsval
is deprecated; new code should use JS::Value
. The old JSVAL_IS_*
methods, JSVAL_*
constants and *_TO_JSVAL
methods, and JSVAL_TO_*
methods are also deprecated; uses of each should be replaced with use of the corresponding val.is*()
, *Value()
, and val.to*()
methods.
JS type | jsval type tests |
jsval constants and constructors |
jsval accessors |
---|---|---|---|
null |
JSVAL_IS_NULL(v) |
JSVAL_NULL |
|
undefined |
JSVAL_IS_VOID(v) |
JSVAL_VOID |
|
boolean | JSVAL_IS_BOOLEAN(v) |
JSVAL_TRUE , JSVAL_FALSE , BOOLEAN_TO_JSVAL(b) |
JSVAL_TO_BOOLEAN(v) |
number | JSVAL_IS_NUMBER(v) , JSVAL_IS_INT(v) , JSVAL_IS_DOUBLE(v) |
JSVAL_ZERO , JSVAL_ONE , INT_TO_JSVAL(i) , DOUBLE_TO_JSVAL(d) |
JSVAL_TO_INT(v) , JSVAL_TO_DOUBLE(v) |
string | JSVAL_IS_STRING(v) |
STRING_TO_JSVAL(str) |
JSVAL_TO_STRING(v) , JS_GetStringChars(str) , JS_GetStringLength(str) |
object | !JSVAL_IS_PRIMITIVE(v) |
OBJECT_TO_JSVAL(obj) |
JSVAL_TO_OBJECT(v) |
There was also a further method, JSVAL_IS_OBJECT(v)
, which did not what you would expect -- return true
if the value was an object -- but rather returned true if the value was an object or if it was null
. These confusing semantics led to this method being removed from the JSAPI in more recent releases, but older code might still use it. Uses of this method should be replaced with v.isObjectOrNull()
.