Convert R Objects to JavaScript

Once webR has been loaded into a web page, objects can be converted into JavaScript from the R environment. For example, it is possible perform some computation within R and then convert the resulting R object into a JavaScript object for use.

Converting R objects to JavaScript objects

Warning

At the moment, not all R objects can be converted to JavaScript objects. Attempting to convert an unsupported R object will throw a JavaScript exception.

Explicitly converting an RObject to JavaScript can be done by invoking the RObject.toJs() method, which returns a JavaScript representation of the associated R object. In most cases, JavaScript conversion has been implemented by serialising the R object to an WebRDataJs.

Serialising R objects

Invoking RObject.toJs() on an R object serialises the object to a JavaScript object of type WebRDataJs. This type is designed to form a tree structure, supporting an unambiguous JavaScript representation for potentially nested R objects.

Most R objects are serialised to JavaScript objects that contain the following properties,

Property Value
type A description of the R object’s type as a string.
names An array of strings corresponding to the R object’s names attribute, or null for no names.
values An array containing the value(s) associated with the R object. A JavaScript null indicates a missing value, NA.

Some R objects, such as lists or environments, contain references to other R objects. Such objects are serialised recursively. Any R objects deeper than the maximum depth setting will not be serialised and instead included in the values array as an RObject. By default, R objects are serialised with infinite maximum depth.

An R NULL object is serialised to a JavaScript object of type WebRDataJsNull. This type does not include the names or values properties.

Warning

The structure of serialised R objects may be updated in future versions of webR, expanding to include more R object attributes. As such, compatibility of serialised R objects between versions of webR is not guaranteed.

Serialisation options

An options argument of type ToJsOptions can be provided to the RObject.toJs() method for fine-grained control over how objects are serialised.

The following options are available,

Property Description
depth How deep should nested R objects be serialised? A value of 0 indicates infinite depth.

Example: Serialising an R double atomic vector

const primes = await webR.evalR('c(2,3,5,7,11,13)');
await primes.toJs()
{
  type: 'double'
  names: null
  values: [2, 3, 5, 7, 11, 13]
}

Other R object conversion methods

Subclasses of RObject provide additional methods to convert objects into a JavaScript representation. For example, the toTypedArray() method can be invoked on atomic vectors, such as an RDouble, to access a copy of the raw buffer as it exists in WebAssembly memory.

const primes = await webR.evalR('c(2,3,5,7,11,13)')
await primes.toTypedArray()
Float64Array(6) [2, 3, 5, 7, 11, 13, buffer: ArrayBuffer(48), ... ]
Note

When converting atomic vectors to JavaScript values, missing values of NA are represented as values of null in the resulting JavaScript representation. This conversion process may have a performance cost for very large vectors.

When using toTypedArray(), however, a copy of the raw memory buffer is returned. In this case the raw sentinel values will be preserved in the case of missing values.

Cached R objects

WebR.objs contains named references to long-living R objects in the form of RObject proxies. WebR.objs is automatically populated at initialisation time, and its properties may be safely accessed once the promise returned by WebR.init() resolves.

WebR.objs contains references to the following R objects,

Property JavaScript Type R object
null RNull NULL
true RLogical TRUE
false RLogical FALSE
na RLogical Logical NA
globalEnv REnvironment The R global environment
baseEnv REnvironment The R base environment

Additional R object proxy hooks

The RObject proxies are implemented with so-called hooks, for instance a hook that forwards class method invocation to the webR worker thread. The following hooks provide additional R object functionality.

Executing R functions from JavaScript

At the moment, R functions cannot be directly converted into JavaScript functions. However, references to R functions can be executed from JavaScript in a limited way. It is possible to return an R function or closure with WebR.evalR() and wrap it as an RFunction proxy. The R function represented by the proxy can be called by either:

  • Invoking the RFunction.exec() method on the RFunction object.

  • Using (), i.e. the normal JavaScript function call syntax.

In either case, both JavaScript or RObject proxies can be passed as arguments to the associated R function. In the case of JavaScript values they are converted to R objects before function execution.

const fn = await webR.evalR('function(x) { 2 * x }');
const result = await fn.exec([1,2,3]);
await result.toArray()
[2, 4, 6]

The result of the R computation is automatically converted back into a JavaScript representation using RObject.toJs() if the RFunction proxy was executed using ().

const sin = await webR.evalR('sin');
await sin([1,2,3]);
{
  type: 'double'
  names: null
  values: [0.8414709848078965, 0.9092974268256817, 0.1411200080598672]
}

Looping over R vectors

RObject proxies are async iterable for objects with a length property. As such, R vectors can be looped over using the JavaScript for await...of syntax. For example,

const list = await webR.evalR('list(2,4,6,"abc")')
for await (i of list){
  console.log(await i.toArray())
}
[2]
[4]
[6]
['abc']