Skip to content

Selecting property names

Properties of objects may be defined and accessed in several ways in JavaScript. Static, literal properties, or ones that have a name known before runtime, are commonly accessed through an identifier or a computed string, like a.b or a["b"]. Additionally, a property may be defined on an object literal using a string literal, as in: { "b": ... }.

(id+) selects such static property names, regardless of the "form" in which they are defined or accessed. This super-selector is suitable for use when the form itself is irrelevant to your query, while the existence, or access, of the property is not.

For example, the query (mem (id+ b)) selects a.b, a["b"] and a[x] in the following snippet:

javascript
var x = "b"

a.b
a["b"]
a[x]

And when (id+) is used with (prop), the query (obj (prop (id+ x))) selects all four of the following object literals:

javascript
var a = "x"

({ x: 1 })
({ "x": 1 })
({ ["x"]: 1 })
({ [a]: 1 })

Technically, the query (id+ x) is shorthand for:

clojure
(:or (id x)
     (str x)
     (comp (str x))
     (comp (:ref (str x))))

The last selector in the expansion, (comp (:ref (str x))), warrants an explanation: the only time (id+) would select a property via a computed identifier - such as a[x] or { [x]: 1 } - is when a reference to the string literal value of the operand is found in scope. If that wasn't the case, then for the query to select a[b] when b is not known to have exactly the value "x", i.e. the operand you supplied to (id+), would be a false selection!

Computed property names have different semantics; they can be any valid expression, unlike their simpler counterparts, the identifier and the string literal. Chances are, when you're looking for the property actually identified by x, e.g. through a query like (mem (comp (id b))), you most definitely aren't interested in the access to a["b"] --- only a[b].

Copyright © 2022-present Semantic Works, Inc.