Custom behavior

This section summarizes Duktape behavior which deviates from the E5.1 or other relevant specifications.

Duktape built-in and custom types

The Duktape built-in is (of course) non-standard and provides access to Duktape specific features. Also the buffer, pointer, and lightfunc types are custom.

Hidden Symbols

Objects may have properties with hidden Symbol keys. These are similar to ES2015 Symbols but won't be enumerated or returned from even Object.getOwnPropertySymbols(). Ordinary ECMAScript code cannot refer to such properties because the keys intentionally use an invalid (extended) UTF-8 representation.

"use duk notail" directive

The "use duk notail" directive is non-standard. It prevents a function from being tail called.

"const" treated mostly like "var"

The const keyword is supported with minimal non-standard semantics (officially defined in ECMAScript 6). See Const variables for more detail.

Additional Error and Function object properties

See Error objects and Function objects.

Non-strict function instances don't have a caller property in the E5/E5.1 specification. Some real world code expects to have this property, so it can be enabled with the config option DUK_USE_NONSTD_FUNC_CALLER_PROPERTY.

Function statements

E5.1 does not allow a function declaration to appear outside program or function top level:

function test() {
    // point A
    try {
        throw new Error('test');
    } catch (e) {
        // This is a SyntaxError in E5.1
        function func() {
            print(typeof e);
        }
        // point B
    }
    // point C
}

These declarations are also referred to as "function statements", and appear quite often in real world code (including the test262 test suite), so they are allowed by Duktape. Unfortunately there are several semantics used by different Javascript engines (ES2015 unfortunately doesn't specify semantics for function statements either). Duktape follows the V8 behavior for function statements:

As an illustration, the above example would behave as the following:

function test() {
    function func() {
        print(typeof e);
    }
 
    try {
        throw new Error('test');
    } catch (e) {
    }
}

func() in the above example would already be declared and callable in point A, and would not have access to the e binding in any of the points A, B, or C.

RegExp leniency

Most ECMAScript engines support more syntax than guaranteed by the ECMAScript E5.1 specification (Section 15.10.1 Patterns). As a result there's quite a lot of code that won't work with strict ECMAScript E5.1 regexp syntax. Much of the additional syntax expected of web browser engines is documented in ES2015 Annex B.1.4 Regular Expression Patterns. However, note that features in Annex B Additional ECMAScript Features for Web Browsers are not recommended for new code: "These features are not considered part of the core ECMAScript language. Programmers should not use or assume the existence of these features and behaviours when writing new ECMAScript code. ECMAScript implementations are discouraged from implementing these features unless the implementation is part of a web browser or is required to run the same legacy ECMAScript code that web browsers encounter."

Duktape also allows some ES2015 Annex B syntax to better support existing code. You can turn this non-standard behavior off using config options if you prefer. Some examples of additional syntax supported:

  /{(\d+)}/    // unescaped left curly, digits, unescaped right curly; ES2015 Annex B
  /\{(\d+)\}/  // same, ES5 compliant

  /]/          // unescaped right bracket; ES2015 Annex B
  /\]/         // same, ES5 compliant

  /\$/         // literal dollar using escape; ES2015 Annex B
  /\u0024/     // same, ES5 compliant

Setter/getter key argument

ECMAScript standard behavior is that setters and getters are not given the name of the property being accessed. This prevents reusing a single setter or a getter for multiple properties; separate functions are needed for each property which is sometimes inconvenient and wastes memory.

Duktape provides the property key name as a non-standard additional argument to setter and getter functions. See test-dev-nonstd-setget-key-argument.js and Property virtualization for more discussion. The strict standards compliant behavior can be enabled by disabling the config options DUK_USE_NONSTD_GETTER_KEY_ARGUMENT and DUK_USE_NONSTD_SETTER_KEY_ARGUMENT.

Object.setPrototypeOf and Object.prototype.__proto__ (ES2015)

See Object.setPrototypeOf and Object.prototype.__proto__.

Proxy object (ES2015)

See Proxy object (subset).

JSON.stringify() escapes U+2028 and U+2029

JSON.stringify() standard behavior is to output U+2028 and U+2029 without escaping. This leads to counterintuitive behavior when the output is used in a web page or parsed with eval(): the U+2028 and U+2029 characters are considered line terminators which leads to a syntax error (unterminated string). Duktape escapes U+2028 and U+2029 by default to avoid this issue; you can turn on the compliant behavior by disabling the config option DUK_USE_NONSTD_JSON_ESC_U2028_U2029.

String.fromCharCode() accepts 32-bit codepoints

String.fromCharCode() standard behavior is to use ToUInt16() coercion for codepoint values. Duktape uses ToUint32() by default to better support non-BMP strings. You can force the compliant behavior by disabling the config optipn DUK_USE_NONSTD_STRING_FROMCHARCODE_32BIT.

Array instance numeric index writes

By default Duktape provides a fast path for writing to Array instances. The fast path is active when numeric indices are used (e.g. arr[7] = 'foo') and a few internal conditions are met. When the fast path is taken, Duktape doesn't check Array.prototype for conflicting properties (these are very rare in practical code), which makes common array writes faster. The behavior is non-compliant, but there's no outward difference unless Array.prototype has properties with numeric keys. You can turn on the compliant behavior by disaling the config options DUK_USE_NONSTD_ARRAY_WRITE and DUK_USE_ARRAY_PROP_FASTPATH. See the following for more details on the fast path behavior: test-misc-array-fast-write.js.

TypedArray binding

Duktape provides the ES2015 TypedArray binding, with some details yet to be fixed, e.g. small differences in argument coercion e.g. for offset and length values.

The plain buffer custom type behaves mostly like an Uint8Array object for ECMAScript code, but has a separate type in the Duktape C API.

Node.js Buffer binding

Duktape provides a Node.js-like Buffer binding. There are some differences between the Node.js behavior and Duktape behavior. These differences include:

Shebang comment support

duk_compile() flag DUK_COMPILE_SHEBANG allows shebang comment parsing: #! on the first column of the first line causes the line to be treated as a comment. For example:

#!/usr/bin/duk
print('Hello world!');

The feature can be disabled by undefining DUK_USE_SHEBANG_COMMENTS.