# group source lines into complete expressions (using a brutal-force method)
group_src = function(code, context) {
  if ((n <- length(code)) < 1) return(list(code))
  i = i1 = i2 = 1
  x = list()
  while (i2 <= n) {
    piece = code[i1:i2]
    if (eval(parse(text=sprintf("%s$validate(piece)", context))) &&  eval(parse(text=sprintf('%s$eval(piece)!="undefined"', context)))) {
      x[[i]] = piece; i = i + 1
      i1 = i2 + 1 # start from the next line
    }
    i2 = i2 + 1
  }
  if (i1 <= n) parse(text = piece)  # must be an error there
  x
}
#
library(knitr)
knit_engines$set(V8 = function(options) {
  require(V8)
  context <- ifelse(!is.null(options$V8.context), options$V8.context, "ct")  
  if(!exists(context)){
    assign(context, new_context(), envir = .GlobalEnv)
    if(!is.null(options$V8.libraries)){
      for(library in options$V8.libraries){
        eval(parse(text=sprintf('%s$source("%s")', context, library))) 
        }
      }
    }
  code <- as.character(c(options$code))
  if(!eval(parse(text=sprintf("%s$validate(code)", context)))) stop("unvalid javascript code")
  if(!is.element(options$results, c("hide", "last"))){
    code <- group_src(code, context)
    output <- sapply(code, function(code) eval(parse(text=sprintf("%s$eval(code)", context))) )
    code <-  sapply(code, function(code) knitr:::wrap.source(list(src= paste(code, collapse = "\n")), options))
    }else{
      if(options$results=="last") output <- eval(parse(text=sprintf("%s$eval(code)", context))) 
      code <-  knitr:::wrap.source(list(src= paste(code, collapse = "\n")), options)
      if(options$results=="hide") return(code)
      return(c(code, knitr:::wrap.character(output, options)))
      }
  return(c(sapply(seq_along(code), function(i) c(code[i], knitr:::wrap.character(output[i], options)))))
  })

Define x in Javascript context using the chunk option engine='V8':

var x=[]
for(i = 0; i<3; i++){
  x[i]=i;
}
## 2
x.push([3,4])
## 4
JSON.stringify(x)
## [0,1,2,[3,4]]

In the previous chunk, the results option is set to its default value. You can use results='hide' to hide the output, or results='last' to show only the output generated by the last line:

var x=[]
x.push([1,2])
x.push([3,4])
JSON.stringify(x)
## [[1,2],[3,4]]

By default the Javascript context is a R variable named ct. You can set another name by doing opts_chunk$set(V8.context="mycontext"). Then using the context variable you can import a variable from the Javascript context to R or vice-versa (see ?V8::V8 for details) :

( x.in.R <- ct$get("x") )
##      [,1] [,2]
## [1,]    1    2
## [2,]    3    4
ct$assign("double_x", 2*x.in.R)

The Javascript JSON.stringify function is nice for displaying an object in a V8 chunk:

JSON.stringify(double_x);
## [[2,4],[6,8]]

You can load a Javascript library like this :

ct$source(system.file("js/underscore.js", package="V8"))

As you can see, it works:

JSON.stringify(_.flatten(x))
## [1,2,3,4]

Another way is to give the libraries as a character vector in the V8.libraries chunk option:

opts_chunk$set(V8.libraries=c(system.file("js/underscore.js", package="V8"), "http://coffeescript.org/extras/coffee-script.js"))

The libraries given by this way are loaded only once, at the moment the Javascript context is created.