Common pitfalls developing JavaScript applications in R

The examples below use the following options

debug = TRUE, rules = basic_rules(), deparsers = basic_deparsers(), asset_tags = basic_tags()

in the source_r function call. Under this setting, R functions are not loaded into the environment.


1. JavaScript uses 0-based indexing

x <- Array(1, 2, 3)   # Array is a function provided in JavaScript
console::log(x[0])

2. Undeclared variables are created in the global environment

f <- function() {
    x <- 3      # Variable used without declaration
    return(x)
}
console::log(f())
console::log(x)        # 'x' shows up in the global!

While directly accessing and modifying global variables are not uncommon in JavaScript visualisations - as we will see when we use p5.js in the other articles - it is best to use it only when it is necessary. Here is how one declares a variable before using it:

f <- function() {
    declare(x)  # Declare variable. Alternatively, you can combine
    x <- 3      # the two lines using `let(x = 3)`.
    return(x)
}
# console::log(x)      # This will throw an error.

3. return in JavaScript function must be explicit

add <- function(x, y) { 
    x + y           # returns nothing, i.e. undefined
}  
console::log(add(3, 4))    # expects nothing

add2 <- function(x, y) { 
    return(x + y)   # returns x + y
}
console::log(add2(3, 4))   # expects 7

4. JavaScript function reads argument by position / order

first <- function(x, y) { 
    return(x)
}
console::log(first(y = 3, x = 1))   # the result is 3, not 1!

Note that since JavaScript does not use named argument, y = 3 and x = 1 are actually interpreted as assignments! Both assignments will happen before the function first is called.

But don’t worry, this won’t be a problem in sketch as it will strip off all the names during the transpilation, i.e. first(y = 3, x = 1) gets transpiled into first(3, 1). The design decision rules out the use of in-place assignments, but it guards against unintended ones.


5. JavaScript passes objects by reference (think of R6 in R)

x = Array(1, 2, 3)
y = x
z = Array(...x)  # make a copy explicitly

y[0] = 999
console::log(x)         # x is modified!
console::log(y)
console::log(z)

6. A browser session has a pre-populated namespace

For example, the variables document, window, location, var, stop, open, focus are taken already. Avoid assigning values to these variables!

The full list can be found with the following code:

# The object (strictly) named "window" refers to your browser window
for (b in Object::keys(window)) {
    if (window$hasOwnProperty(b)) console::log(b)
}