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
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.
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), ... ]
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 theRFunctionobject.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']