A heavy set of restrictions are imposed on user code that can be executed by the interpreter. This allows to make the runtime as simple to implement and reason about as possible. The following restrictions are non-normative and being worked on pending the result of proof of concepts implemented in various host programming languages.
- Verdict: Recommended
- Reason: easy to implement, required for LibreJS-level distribution of code in preferred form of modification by each web site
- Standard: JS1
- Verdict: Recommended
- Implementation complexity: low
- Incidence rate: very common
- Reason: Turing-completeness
- Standard: JS1
- Verdict: Required
- Incidence rate: very common
- Reason: Turing-completeness
- Standard: JS1
- Verdict: Required
- Incidence rate: rare
- Reason: single original way for dynamic iteration on Object keys
- Standard: JS1
- Verdict: Required
- Incidence rate: very common
- Reason: basic modularization. A restriction of return at the very end of the body was considered, but then dismissed as easy to implement without this restriction while greatly improving clarity of user code.
- Standard: JS1
- Verdict: Recommended
- Incidence rate: none in web code, high in command line and server CGI code
- Reason: Turing-completeness
- Solution: process.stdin.on
- Workaround: some other API that can open and read from a file descriptor
- Standard: Node.js
- Verdict: Recommended
- Incidence rate: none in web code, high in command line and server CGI code
- Reason: native platform interface
- Solution: require('fs').readFile()
- Alternative: require('fs').readFileSync()
- Workaround: some other API that can open and read from a file descriptor
- Standard: Node.js
- Verdict: Recommended
- Incidence rate: none in web code, high in command line and server CGI code
- Reason: native platform interface
- Solution: require('fs').writeFile()
- Workaround: some other API that can open and write to a file descriptor
- Standard: Node.js
- Verdict: required, partial
- Restriction: recommend working around property accessors by not reading this field after having written to it and only write to it once between browser preemption points (starting execution of a script, XHR, document.write, timeout, form submit, a href)
- Implementation complexity: low if String backed, intermediate if property accessors need to be introduced to the language just for this
- Incidence rate: low, but non-negligible
- Reason: useful for authentication of extant web hosting services
- Workaround: none on web, adding and parsing headers via HTTP/TCP connections on native platforms
- Standard: NS2
- Verdict: required
- Reason: the visitor must have control over untrusted code
- Implementation complexity: low
- Verdict: required
- Reason: the visitor must have control over untrusted code
- Implementation complexity: higher intermediate due to many corner cases
- Solution: account for each allocation including overheads of alignment and padding, accessing a large index in an array, allocate many small objects, concatenating large strings, setting many fields on a single object, manipulations on mmap'ped files
- Verdict: required
- Reason: the visitor must have control over untrusted code
- Implementation complexity: intermediate
- Solution: if the interactive user agent is single threaded without a means to abort the script from the interface, start a watchdog timer within the event loop and terminate the script if the single atomic dispatch takes more than the quota. If the user interface can remain responsive for aborting a running script, the total CPU time since the last user interaction with the script should be metered and the user warned if it had taken more than a threshold or if the average CPU utilization percentage caused by the script had exceeded a threshold after some time.
- Verdict: recommended, partial
- Restriction: creation with the 0-argument constructor, only the
.length
getter can be used and square bracket indexing, missing: join, reverse, sort - Implementation complexity: low, intermediate with an efficient data structure
- Workaround: substitute an Object, manually update a length property with each addition or iterate over it until reaching
undefined
instead of a given length - Standard: ES1
- Verdict: recommended, partial
- Reason: caching, private keys, state not uploaded on each request as with cookies, safer than cookies
- Restriction: getItem(), setItem() and key(). Without getters, length is not supported, removeItem() and clear() optional
- Implementation complexity: low, individual files with storage quota accounting
- Workaround: store private keys and state in URI hash anchor and ask user to update bookmark after every session
- Standard: 2009-2010 (Firefox 3.5, Safari 4, IE8, Opera 10.5, Chrome 5)
- Verdict: recommended
- Implementation complexity: low if granularity provided by event loop conditioning is sufficient, intermediate if termination at reductions or via a separate process model would be warranted, very high if resumption without POSIX job control signals also required
- Verdict: Recommended
- Reason: Potential for building a higher level library by the user
- Standard: ES1 (
Function
), ES3 (function(){}
)
- Verdict: Recommended
- Reason: modularization, reducing global oversaturation and reduce visibility of unrelated functionality
- Standard: ES3
- Verdict: recommended
- Incidence: high
- Workaround: if, &
- Standard: JS1
- Verdict: recommended
- Incidence: low
- Implementation complexity: low
- Workaround: interpreter
- Standard: JS1
- Verdict: recommended, partial
- Reason: suggested by style guides, avoids wide classes of errors, easy to understand by beginners
- Restriction: can only homogeneously compare non-NaN integers or strings, along with
null
andundefined
to any value to reduce bug potential - Incidence: high to always
- Implementation complexity: low
- Workaround: error prone and too verbose, invoke abstract equality and
typeof
orinstanceof
in every expression it occurs - Standard: ES3
- Verdict: recommended
- Incidence rate: intermediate
- Implementation complexity: low
- Reason: the simplest alternative for interactive document modification
- Workaround: serialize state, generate a complete new document using the string return value of a
javascript:
link to navigate away to, deserialize state - Standard: NS2
- Verdict: required, same for textarea
- Incidence rate: high
- Implementation complexity: low, read both the default value from the static HTML and text entered by the user
- Reason: allow for interacting with typed user input without server involvement
- Workaround: unsatisfactory due to lack of caching, allow to submit the form via GET and parse the values from the URI upon load, without forms, provide an on screen keyboard with individual links for each key
- Standard: NS2
- Verdict: recommended
- Restriction: you can apply the same operator consecutively in an expression without using parenthesis
- Use cases: string concatenation, numerical sums, factors, short circuiting bool logic
- Incidence rate: high
- Implementation complexity: trivial (only a few lines of code)
- Drawback: it creates an irregular corner case of supported syntax that needs to be remembered
- Workaround: parenthesis
- Standard: JS1
- Verdict: supported
- Reason: expected by users
- Drawbacks: restricting it could improve hardening, either remove it completely or only support integers 0 and 1
- Incidence rate: high, higher for an interpreter substituting integers for the Boolean type
- Implementation complexity: trivial
- Workaround: invoke the
Boolean()
function - Standard: JS1
- Verdict: not mandatory, avoid in user code if possible
- Reason: may lead to bugs, difficult to keep in mind all corner cases for beginners, may only be needed for compatibility with JavaScript 1.0
- Incidence: low
- Implementation complexity: low
- Workaround: usually unwanted, but may simulate by first converting a value to canonical form according to the standard and compare with a sequence of strict equality checks
- Standard: JS1
- Verdict: Desirable, but unsupported
- Restriction: only integers supported and the special value of
NaN
- Reason: too complex to implement and potentially increases memory use and more difficult to optimize.
NaN
is desirable to detect error conditions of standard functions. - Standard: JS1
- Verdict: partial
- Restriction: only allowed for concatenation of a String and Number, Object or undefined using
+
- Reason: expected by users, but would be beneficial to forbid
- Drawbacks: can often cause bugs if working on values of unforeseen types
- Incidence rate: high
- Implementation complexity: trivial, assuming
String()
is already available, high if had to make standard library conforming - Workaround: invoke the
String()
function - Standard: JS1
- Verdict: partially supported
- Restrictions: String indexing may iterate on UTF8 instead of UCS-2. May assume that the HTML and JS source are all encoded as UTF8.
- Use cases: must be able to process input in extant human languages in a way that should work in a way equivalent to extant web browsers.
- Standard: JS1
- Verdict: partial
- Restriction: only support unary and binary operators to avoid having to observe operator precedence rules. A few subexpressions may be supported without parenthesis that are very common: function invocation, array index, object member. The special case of consecutive terms of same operator is detailed separately.
- Incidence rate: intermediate
- Implementation complexity: intermediate
- Workaround: parenthesis, temporary variables
- Standard: JS1
- Verdict: not supported
- Incidence rate: high
- Implementation complexity: low
- Workaround: can be substituted with
0===1
and1===1
, but 0/1 can also be used instead of false/true similarly to C - Standard: JS1
- Verdict: partial
- Restriction: You can only subtract two Date objects from each other to get the elapsed time in milliseconds, add a Date and a Number offset to result in a Date and divide or compute modulo of a Date by a Number (usually 1000) as taken in number of milliseconds since Unix epoch. This should allow for Number to be represented on 32 bits. Consider methods for returning the locale time offset.
- Implementation complexity: high if unrestricted
- Incidence rate: low
- Workaround: library
- Standard: JS1
- Verdict: partial, investigate
- Restrictions: only String.prototype.match, no RegExp class, PCRE subset
- Incidence rate: intermediate to high
- Implementation complexity: intermediate if platform has compatible built-ins, very high otherwise
- Runtime overhead: variable memory and CPU utilization, may be exploited with ReDoS unless additional sanitization is implemented
- Workaround: while, if, String charCodeAt
- Standard: ES3
https://en.wikipedia.org/wiki/ReDoS
- Verdict: partial
- Implementation complexity: high if done per standard
- Reason: automatic semicolon insertion as called for by the standard is very complicated to both implement and remember.
- Restriction: terminate or begin every statement with a
;
. You can leave out;
either before the end of a block (end of program or before}
) or after the start of a block (start of program or after{
) - Standard: JS1
- Verdict: Partial
- Restriction: only a single string argument is allowed for console.log() without any formatting
- Incidence rate: low in web code, high in command line and server CGI code
- Reason: Turing-completeness
- Solution: console.log
- Workaround: some other API that can open and write to a file descriptor
- Standard: Node.js, IE8, Firefox 4, Chrome 4, Opera 11, Safari 3.1
- Verdict: supported
- Restrictions: only allowed (optional) for body of if-else and while
- Implementation complexity: easy if restricted
- Workaround: function, multiple if
- Standard: JS1
- Verdict: Recommended
- Reason: desirable qualities of encapsulation useful for modules and userscript (userjs) within a web browser.
- Restrictions: not all syntax may be supported and in not every position within an expression. This should work:
(function(){})();
- Workaround:
Function
- Standard: ES1 (
Function
), ES3 (function(){}
)
- Verdict: Desirable, but only partially supported
- Use cases: state encapsulation for object oriented programming, Currying for functional programming
- Restrictions: to avoid reference cycles, a runtime may make a shallow copy of the environment from above the function definition, not including itself.
- Workaround: Use a C-like function definition order within the file. Recursion needs to be worked around by passing in a self-reference for the function.
Function
andeval
could also be used as an alternative. - Standard: ES3
- Verdict: Desirable, partially supported
- Incidence rate: frequently
- Implementation complexity: easy
- Restriction: single variable and single initializer supported per
var
keyword as usually recommended by style guides to maintain one statement per line. - Standard: JS1
- Verdict: desirable, limited support
- Restriction: no classes, catch may be implemented as a restricted kind of environment
- Reason: Useful for detecting error conditions of standard functions.
- Standard: ES3, NS5
- Verdict: desirable, limited support
- Incidence rate: very common
- Implementation complexity: easy
- Restriction: chaining starting from a variable should be supported, but may not support interspersing function calls or parenthesized expressions
- Standard: JS1
- Verdict: partial
- Use cases: process arguments in the URI query or hash anchor, possibly read
GET
form submissions - Restriction: can only get the full URL as a string, no property setter
- Workaround: library
- Standard: NS2
- Verdict: recommended
- Use cases: change internal state in the URI query or hash anchor, possibly create
GET
form submissions - Workaround: library
- Standard: NS3
- Verdict: recommended
- Use cases: navigate to a different page without a setter for href
- Workaround: library
- Standard: NS2
- Verdict: partial
- Restriction: function argument, up to a single timeout active at a time
- Implementation complexity: higher intermediate, needs an event loop with termination and signal handling
- Use cases: retry with backoff, autosave, neighborly crawling, animation, debouncing, initialization after onload (instead of noscript)
- Workaround: eval instead of string argument, none for setTimeout itself (except for immediately invoking the function if the timeout is 0), implement a dispatcher that tracks upcoming events in ascending order to simulate multiple timers
- Standard: NS2, JS1
- Verdict: partial
- Implementation complexity: high, encoding types, file attachments, hooks for both HTML and JavaScript
- Restriction: limited input types, limited attributes (action, method, enctype)
- Standard: NS2
- Verdict: partial
- Implementation complexity: high, header handling, timeout, reference cycle
- Restriction: can only return a string responseText without progress, CORS may not be complete
- Use cases: interfacing with API, third party integration, incremental update of local state, bookmarklet that would parse the current document
- Workaround: JSONP, form submit, Fetch
- Standard: Internet Explorer 5, Gecko 1.0, Safari 1.2, Opera 8
- Verdict: partial
- Restriction: only allowed to get milliseconds from a Date for certain operators detailed in the Date section
- Reason: potential for bugs outweighs ergonomic benefits in most common code
- Drawbacks: can often cause bugs if working on values of unforeseen types
- Incidence rate: low
- Implementation complexity: low, assuming
parseInt()
is already available, high if had to make standard library conforming - Workaround:
typeof
,parseInt()
- Standard: JS1
- Verdict: partial
- Restriction: only for a few predetermined classes (Array*, Object*, Date, XMLHttpRequest), see constructor arguments detailed separately.
- Incidence rate: low for custom classes, intermediate for built-in
- Implementation complexity: high if assuming full OOP, prototype and this support
- Drawbacks: prototype based inheritance is disfavored
- Workaround: can cleanly simulate OOP by capturing state within a Function that returns an Object of methods
- Standard: JS1
- Verdict: unsupported
- Reason: implementation cost and introduced irregularity outweighs ergonomic benefits in most common code
- Drawbacks: can often cause bugs if working on values of unforeseen types
- Incidence rate: low
- Implementation complexity: high
- Workaround: convert to appropriate type manually
- Standard: JS1
- Verdict: unsupported
- Implementation complexity: intermediate
- Incidence rate: low
- Use cases: Array initializer (instead of ES3 Array literal), ES3 RegExp
- Reason: not crucial in practice
- Workaround: separately instantiate the class and then initialize it (Array), use function application based alternatives that work without the new keyword (Function, String), substitute RegExp with String match, search or replace
- Standard: JS1
- Verdict: unsupported
- Implementation complexity: low
- Workaround: simulate using setTimeout and Date
- Standard: NS4
- Verdict: not supported
- Incidence rate: low
- Implementation complexity: higher intermediate, depending on widget toolkit, may need to keep the whole HTML source or a representation in memory and reflow
- Workaround: generate a new document with the intended value set as default, possibly represent value within body outside form
- Standard: NS2
- Verdict: not supported
- Reason: considered bad practice, confusing for beginners
- Implementation complexity: low to intermediate depending on graph representation, may carry a runtime penalty when streaming
- Incidence rate: very low, usually not on purpose
- Use cases: none
- Workaround: declare a variable before referencing it
- Standard: JS1
- Verdict: not supported
- Reason: redundant, but would be beneficial at times
- Implementation complexity: easy
- Incidence rate: low
- Workaround: while, if, return
- Standard: ES3
- Verdict: not supported
- Reason: redundant, but would be beneficial at times
- Implementation complexity: easy
- Incidence rate: intermediate
- Workaround: while
- Standard: JS1
- Verdict: not supported
- Implementation complexity: intermediate
- Incidence rate: low
- Reason: goto also disfavored by style guides
- Workaround: return, if, altered loop condition, function expression
- Standard: JS1
- Verdict: not supported
- Implementation complexity: intermediate (function arguments object, call, apply)
- Incidence rate: rare
- Use cases: a few standard library functions in ES3 whose functionality could be restricted to only support the minimal amount of non-trivial arguments (1 for Array.prototype.concat, push, unshift, String.fromCharCode, String.prototype.concat, 2 for Array.prototype.splice, Math.min, max and the Function() constructor)
- Workaround: Array
- Standard: JS1
- Verdict: not supported
- Implementation complexity: complicated
- Incidence rate: would be often useful
- Reason: would increase memory pressure, would be less error prone for newcomers than the function scope
var
- Workaround: function, immediately invoked anonymous function expression
- Standard: ES6
- Verdict: not supported
- Implementation complexity: intermediate
- Incidence rate: rare
- Workaround: if-else
- Standard: ES3
- Verdict: not supported, desirable at times
- Implementation complexity: straightforward
- Incidence rate: intermediate
- Workaround: easy, create an intermediate object and add the value via an accessor
- Standard: ES3
- Verdict: not supported, desirable at times
- Implementation complexity: straightforward
- Incidence rate: intermediate
- Workaround: easy, create an intermediate array and add the value via an index
- Standard: ES3
- Verdict: Unsupported.
- Restriction: Avoid storing a reference within object
p
pointing to objectq
if there exists a directed path leading fromq
top
. Captured function environment scopes are also counted as a reference. - Reason: Such a cycle would mandate a more complicated and less deterministic garbage collection scheme for collecting cycles specifically.
- Workaround: store the key of a given object within a common map instead of a direct reference. Inspect carefully which environment a given function definition captures and alter the ordering or use additional encapsulation to hide stray paths.
- Standard: JS1
- Verdict: unsupported
- Reason: still not supported by most major browsers as of 2023
- Implementation complexity: very high
- Incidence rate: low (none for common imperative code)
- Workaround: while
- Standard: optional since ES6
- Verdict: avoid in user code
- Restriction: runtime implementation may use it internally but may not expose it to user code
- Reason: uniform implementation is difficult, slow and uses more memory. Also considered bad practice for most use cases.
- Workaround: emulate regular inheritance by function expressions or chain only pure functions where applicable
- Standard: JS1
- https://lists.w3.org/Archives/Public/www-tv/1999JanMar/0033.html
- https://quirksmode.org/js/dom0.html
- https://quirksmode.org/dom/core/
- http://www.brainjar.com/dhtml/intro/default5.asp
- https://www.yaldex.com/javascript_tutorial_2/LiB0178.html
- https://www.w3.org/TR/REC-DOM-Level-1/level-one-core.html
- https://public.websites.umich.edu/~jwithrow/materials/dom1.html