2 The RacketScript-JavaScript FFI
(require racketscript/interop) | |
package: racketscript-compiler |
RacketScript supports direct interoperability with most JavaScript features. This section explains how to invoke plain JavaScript in a RacketScript program.
2.1 RacketScript’s JavaScript FFI Primitive
RacketScript’s #%js-ffi form compiles directly to various JavaScript features. The first argument is a symbol that indicates the kind of JavaScript code to be generated and the rest are the arguments for that kind of operation.
NOTE: Users most likely should not be using this form. Instead, use the API described in the RacketScript’s JavaScript FFI API section, which will expand to the appropriate call to #%js-ffi.
syntax
(#%js-ffi 'var)
(#%js-ffi 'ref obj prop-id)
(#%js-ffi 'index obj prop-expr)
(#%js-ffi 'assign x e)
(#%js-ffi 'new expr)
(#%js-ffi 'throw exn)
(#%js-ffi 'undefined)
(#%js-ffi 'null)
(#%js-ffi 'this)
(#%js-ffi 'arguments)
(#%js-ffi 'object [fld v] ...)
(#%js-ffi 'array args ...)
(#%js-ffi 'typeof obj)
(#%js-ffi 'instanceof obj type)
(#%js-ffi 'string str)
(#%js-ffi 'require mod)
(#%js-ffi 'operator 'op operand ...)
Summary of JavaScript operations supported by #%js-ffi:
'var: Use to access variable in the JavaScript namespace
'ref: JavaScript object property reference, i.e., dot notation
'index: JavaScript index operation, i.e., bracket notation
'assign: JavaScript assignment
'new: JavaScript object constructor
'throw: Throw JavaScript exception
'undefined: JS undefined value
'null: JS null object value
'this: JS this object self reference
'arguments: implicit JS arguments variable containing function args
'object: JS object literals, i.e, curly brace notation
'array: JS array literals, i.e, bracket notation
'typeof: JS typeof operation
'instanceof: JS instanceof operation
'string: JS strings (incompatible with Racket/RacketScript strings, see $/str)
'require: JS import, use to import JS libraries
'operator: Use to call JS functions requiring infix notation
2.2 RacketScript’s JavaScript FFI API
syntax
($ jsid)
($ expr sym) ($ expr expr) ($ expr expr ...)
jsid = valid JS identifier (alphanumeric underscore and dollar chars)
sym : symbol?
Using the $ operator with a single identifier references a JavaScript variable.
Example: ($ JSON)
Note: the identifier be a valid JavaScript identifier (underscore, dollar, and alphanumeric characters only), and not Racket or RacketScript one.
Equivalent to (#%js-ffi 'var jsid).
Supplying a second argument that is a symbol corresponds to accessing a JavaScript object property using dot notation, where the symbol name is the property name.
Example: If handling a web request named req, getting the body of the request could be written ($ req 'body) which compiles to req.body in JavaScript.
Equivalent to (#%js-ffi 'ref req 'body).
Note: The above assumes that req is a RacketScript variable. If the variable is in the JavaScript namespace only, then an additional $ is needed to first access the variable (see first $ case above).
Example: ($ ($ JSON) 'parse) compiles to the JavaScript JSON.parse function.
A second argument that is an arbitrary expression is treated as JavaScript bracket notation.
Example: ($ req "body") compiles to req["body"] in JavaScript.
Equivalent to (#%js-ffi 'index req "body").
Supplying more than two arguments corresponds to a series of bracket lookups.
syntax
($$ dot-chain e ...)
dot-chain = symbol or identifier consisting of multiple dot-separated names
syntax
($/new constructor-expr)
syntax
($/throw exn)
syntax
syntax
syntax
syntax
syntax
($/obj [fld v] ...)
fld = identifier
syntax
($/:= e v)
syntax
($/array e ...)
Often used with define, e.g., (define express ($/require "express")) compiles to:
import * as express from "express";
Equivalent to (#%js-ffi 'require mod) or (#%js-ffi 'require '* mod)
syntax
($/require/* mod)
mod : string?
Shorthand for ($/require mod *)
syntax
($> e call ...)
call = id | (meth arg ...)
For example:
($> (#js.res.status 400) (send #js"Bad Request"))
is compiles to res.status(400).send("Bad Request")
Equivalent to nested #%js-ffi calls (with 'var, 'ref, or 'index).
syntax
($/typeof e)
($/typeof e type)
type :
(and/c string? (or/c "undefined" "object" "boolean" "number" "string" "function"))
The first form returns a string representing the typeof the given JavaScript value. Equivalent to (#%js-ffi 'typeof e).
The second form is shorthand for checking the type of a value. For example, ($/typeof 11 "number") is compiles to
typeof 11 === "number";
Equivalent to ($/binop === (#%js-ffi 'typeof e) ($/str v))
syntax
($/instanceof e type)
e = JavaScript Object
Equivalent to (#%js-ffi 'instanceof e type)
syntax
($/binop op operand1 operand2)
Equivalent to (#%js-ffi 'operator 'op operand1 operand2)
syntax
($/+ operand ...)
procedure
(js-string->string jsstr) → string?
jsstr : JSstring
syntax
($/str s)
2.3 Reader Extensions
#lang racketscript/base includes reader extensions that make it easier to interoperate with JavaScript. Specifically, RacketScript’s reader recognizes three delimiters:
#js
Used to access JavaScript object properties via dot notation.
Example:#js.req.body
where req is a RacketScript variable.Equivalent to a series of #%js-ffi 'ref calls.
#js*
Used to access JavaScript object properties via dot notation. The difference with "#js" is that "#js*" wraps the first identifier in a #%js-ffi 'var form, i.e., it is used to access properties of JavaScript variables rather than RacketScript variables.
Example:#js*.JSON.parse
where JSON is a JavaScript variable.Equivalent to a series of #%js-ffi 'ref calls where the first id is wrapped in a #%js-ffi 'var.
#js"some js string"
Used to create JS strings.
Note: JS strings are not compatible with Racket/RacketScript strings. Use $/str and other related API functions to convert between the two when needed.
Example:(#js*.console.warn #js"Error!")
Equivalent to a #%js-ffi call with 'string.