Object & Array

Python equivalents of JavaScript’s Object & Array types.

jstypes.JSObject

jstypes.JSObject(self, properties=(), /, **kwarg_properties)

A Python equivalent of JavaScript plain objects.

JSObject is a Python Mapping, whose keys can be strings or numbers. JavaScript Objects treat integer keys and integer strings as equivalent, and JSObject does too. In fact, JavaScript Arrays and Objects are almost entirely the same, and JSArray is also the same as JSObject, except for its constructor arguments. The JSArray description provides details of integer indexing behaviour which also applies to JSObject.

JSObject implements just the JavaScript Object behaviour that can be transferred with V8 serialization (which is essentially the behaviour of structuredClone()). This is similar to JSON objects — object prototypes, methods, get/set properties and symbol properties cannot be transferred. Unlike JSON, objects can contain cycles and all the other JavaScript types supported by the V8 Serialization format, such as JavaScript’s RegExp and Date (JSRegExp and datetime.datetime).

JSObject is also an ABC can other types can register as virtual subtypes of in order to serialize themselves as JavaScript Objects (by default, Python Mappings are serialized as JavaScript Maps).

Parameters

Name Type Description Default
properties SupportsKeysAndGetItem[str | int, T] | Iterable[tuple[str | int, T]] The items to populate the object with, either as a mapping to copy, or an iterable of (key, value) pairs. ()
kwarg_properties T Additional key-values to populate the object with. These override any items from properties with the same key. {}

Notes

The behaviour JSObject implements aims to match that described by the ECMA-262 spec, so that details are not lost in translation when serializing between Python and JavaScript.

Examples

>>> o = JSObject(name='Bob', likes_hats=False)
>>> o['name']
'Bob'
>>> o['518'] = 'Teapot'
>>> o['404'] = 'Not Found'

Properties are kept in order of creation, but array indexes (e.g. strings that are non-negative integers) always come first, in numeric order.

>>> o
JSObject({404: 'Not Found', 518: 'Teapot'}, name='Bob', likes_hats=False)
>>> dict(o)
{404: 'Not Found', 518: 'Teapot', 'name': 'Bob', 'likes_hats': False}

Attributes

Name Description
array Properties with integer names.
properties Properties with string names.

Methods

Name Description
setdefault
update

setdefault

jstypes.JSObject.setdefault(key, default=None, /)

update

jstypes.JSObject.update(*args, **kwargs)

jstypes.JSArray

jstypes.JSArray(self, properties=(), /, **kwarg_properties)

A Python equivalent of a JavaScript Array.

The constructor accepts lists/iterables of values, like list() does. Otherwise its functionally the same as v8serialize.jstypes.JSObject.

JavaScript Array values deserialized from V8 data are represented as JSArray rather than JSObject, which allows them to round-trip back as Array on the JavaScript side.

Note in particular that JSArray itself is not a Python Sequence, because JavaScript Arrays can also have string property values. The .array property contains a sequence of the integer-indexed values, which — in the typical case where a JSArray has no string properties — will hold all the object’s values. The .properties Mapping holds just the non-array string properties.

JavaScript arrays have the special property of supporting sparse indexes — they can store values with large gaps between integer indexes without using space for unused indexes in between. JSArray (and thus JSObject) also have this behaviour. The .array property is SparseMutableSequence, which extends the regular Sequence API with has extra methods and properties to support sparse arrays. (See the examples below.)

Parameters

Name Type Description Default
properties SupportsKeysAndGetItem[str | int, T] | Iterable[T | JSHoleType] Ordered values to populate the array with, or a mapping of key-values to initialise either or both int array indexes and string properties. ()
kwarg_properties T Additional key-values to populate either or both int array indexes and string properties. These override any items from properties with the same key. {}

Examples

>>> a = JSArray(['a', 'b'])
>>> a
JSArray(['a', 'b'])
>>> a[0]
'a'

As in JavaScript, JSArray works exactly like a JSObject — arrays can also have non-integer properties:

>>> a['foo'] = 'bar'
>>> a
JSArray(['a', 'b'], foo='bar')

JavaScript Object and Array treat string properties that are integers the same as using integers directly. JSMap does the same:

>>> a['2'] = 'c'
>>> a
JSArray(['a', 'b', 'c'], foo='bar')

The .array property is a MutableSequence that contains only the integer-indexed array properties, whereas JSArray objects themselves are MutableMappings of all values:

>>> from typing import MutableSequence, MutableMapping
>>> isinstance(a.array, MutableSequence)
True
>>> list(a.array)
['a', 'b', 'c']
>>> isinstance(a, MutableSequence)
False
>>> isinstance(a, MutableMapping)
True
>>> dict(a)
{0: 'a', 1: 'b', 2: 'c', 'foo': 'bar'}

JavaScript Arrays are sparse — they can have large gaps between array entries without using space for all the empty indexes in between. JSArray’s .array property is a special type of sequence that models this behaviour:

>>> from v8serialize import SparseMutableSequence
>>> isinstance(a.array, SparseMutableSequence)
True
>>> a[6] = 'g'
>>> a
JSArray(['a', 'b', 'c', JSHole, JSHole, JSHole, 'g'], foo='bar')
>>> len(a.array)
7
>>> a.array.elements_used
4
>>> list(a.array.element_indexes())
[0, 1, 2, 6]

elements() is a view of the array as a Mapping, containing keys for indexes that have values.

>>> a.array.elements().get(6)
'g'
>>> a.array.elements().get(4, 'default')
'default'
>>> dict(a.array.elements())
{0: 'a', 1: 'b', 2: 'c', 6: 'g'}

To be consistent with normal sequences, .array raises IndexError for out-of-bounds index operations:

>>> a.array[1234567] = '?'
Traceback (most recent call last):
...
IndexError: list index out of range

The main JSArray object allows setting any index though.

>>> a[1234567] = '?'
>>> a
JSArray({0: 'a', 1: 'b', 2: 'c', 6: 'g', 1234567: '?'}, foo='bar')

jstypes.JSHole

jstypes.JSHole

Explicit representation of the empty elements in JavaScript arrays.