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:
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:
var a = "x"
({ x: 1 })
({ "x": 1 })
({ ["x"]: 1 })
({ [a]: 1 })
Technically, the query (id+ x)
is shorthand for:
(: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]
.