This section summarizes Duktape behavior which deviates from the E5.1 or other relevant specifications.
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.
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.
The "use duk notail" directive is non-standard. It prevents a function from being tail called.
The const
keyword is supported with minimal non-standard
semantics (officially defined in ECMAScript 6). See
Const variables for more detail.
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
.
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.
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
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
.
See Object.setPrototypeOf and Object.prototype.__proto__.
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()
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
.
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.
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.
Duktape provides a Node.js-like Buffer
binding. There are
some differences between the Node.js behavior and Duktape behavior. These
differences include:
totalLength
exceeds combined size of input buffers.noAssert
is true. Failed
reads return NaN and failed writes return 0.writeUInt8()
silently coerces to
0x00 rather than throwing a TypeError."utf8"
encoding (and accepts no
spelling variants). Most API calls ignore an encoding argument, and
use UTF-8 implicitly for string-to-buffer coercion.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
.